From 35ebd45442ee9104d429c0c7e29f796c943ae90a Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 5 Jun 2016 00:41:09 +0200 Subject: [PATCH 01/10] libbootimg: Fix support of Stock Sony ELF boot images * Unlike all boot images built for CyanogenMod or AOSP based ROMs over the last years, the elf bootimages from Stock also include additional metadata in the header section that is required for the device to power up with its kernel * Add a 3900 8bits array at the end of the header, followed by the 16 chars of the added bootimage name, in order to match the Sony ELF 4096 first block and therefore save the additional data from Stock images * Regular Sony ELF images have about 1200-1600 chars there so filling the 4096 block is more than enough for this, and moving the bootimage name at the end makes things safer Change-Id: Ic2b619b6f5e862920dcfefa5b86b016987305d4a Signed-off-by: AdrianDC --- include/boot_img_hdr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index e92a423..1f7f59e 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -130,6 +130,7 @@ struct boot_img_hdr_elf uint32_t cmd_msize; /* cmdline size duplicate */ uint32_t cmd_flags; /* cmdline flags (0xAC to 0xAF) */ uint32_t cmd_align; /* cmdline alignment */ + uint8_t header_vals[3900]; /* header additional values */ uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ }; From 37572bcbf2b814c3a98c8af9990119a6ba762c37 Mon Sep 17 00:00:00 2001 From: Alexander Diewald Date: Thu, 6 Oct 2016 22:04:05 +0200 Subject: [PATCH 02/10] libbootimg: Add support for newer Sony ELF boot images The boot image found in sony firmwares (stock) is different to the already implemented version. This change adds support for these images (found in the Z2) by introducing more flexibility in the ELF handling and the output format (ELF --> ANDROID!) In particular: - Use a more dynamic structure to describe elf files: Add handling information (e.g., the elf version) and separate structures for the ELF header, the program headers, and the section headers - Adjust the read/load operations to account for the new structure - Add handling code for the differentiation between the two known ELF versions - Adjust the writing code such that it can output the content of an ELF image as a standard ANDROID! image: The newer ELF versions are not booted if a single (unused) bit is modifed Possibly the (unlocked) bootloader performs a signature check only for ELF files - Add some debug code that allows to print either to stdout or the kernel log (useful for on-device debugging) - Extend the Sony Stock support in a dynamic way - Add dependencies for klog_write - Also fix all minor warnings The code has been tested with the boot image of an Xperia Z2, and on the devices from the original ELF implementation (SP) Change-Id: I0e9a41ae6ce26bf4608ef86cec1e2735f746abb6 Signed-off-by: Alexander Diewald Signed-off-by: Adrian DC --- Android.mk | 13 +- include/boot_img_hdr.h | 124 ++++---- include/libbootimg.h | 120 +++++++- src/libbootimg.c | 653 +++++++++++++++++++++++++++++++++++------ 4 files changed, 766 insertions(+), 144 deletions(-) diff --git a/Android.mk b/Android.mk index d7b4251..5a14e38 100644 --- a/Android.mk +++ b/Android.mk @@ -13,10 +13,12 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_EXECUTABLES_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libc +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_STATIC_LIBRARIES := libc libcutils include $(BUILD_EXECUTABLE) +# bbootimge_host include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(bbootimg_src_file) @@ -36,14 +38,19 @@ LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin LOCAL_MODULE_STEM := bbootimg LOCAL_SRC_FILES:= src/bbootimg.c src/libbootimg.c -LOCAL_SHARED_LIBRARIES := libc -include $(BUILD_EXECUTABLE) +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_SHARED_LIBRARIES := libc libcutils +include $(BUILD_EXECUTABLE) # libbootimg include $(CLEAR_VARS) + LOCAL_SRC_FILES := src/libbootimg.c LOCAL_MODULE := libbootimg LOCAL_MODULE_TAGS := eng + +LOCAL_CFLAGS := -DDEBUG_KMSG + include $(BUILD_STATIC_LIBRARY) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index 1f7f59e..6ce3a33 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -20,7 +20,7 @@ #include /* -** +-----------------+ +** +-----------------+ ** | boot header | 1 page ** +-----------------+ ** | kernel | n pages @@ -51,11 +51,24 @@ #define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 -#define BOOT_MAGIC_ELF "ELF" -#define BOOT_MAGIC_ELF_SIZE 3 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 +#define BOOT_MAGIC_ELF "ELF" +#define BOOT_MAGIC_ELF_SIZE 3 +#define VER_ELF_1 (1 << 0) +#define VER_ELF_2 (1 << 1) + +#define OUT_ELF (1 << 0) /* Same output format: ELF container */ +#define OUT_AND (1 << 1) /* Different output format: standard Android container */ + +#define ELF_PROG_KER 0 +#define ELF_PROG_RAM 1 +#define ELF_PROG_RPM 2 +#define ELF_PROG_CMD 3 + +#define ELF_SECT_CMD 0 + struct boot_img_hdr { uint8_t magic[BOOT_MAGIC_SIZE]; @@ -81,59 +94,64 @@ struct boot_img_hdr uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ }; -struct boot_img_hdr_elf +struct boot_img_elf_hdr { uint8_t magic[8]; /* .ELF (0x00 to 0x07) */ - uint8_t unused[8]; /* unused chars */ - uint16_t type; /* boot type */ - uint16_t machine; /* boot machine */ - uint32_t version; /* boot version */ - uint32_t entry_addr; /* boot entry */ - uint32_t phoff; /* boot phoff */ - uint32_t shoff; /* boot shoff */ - uint32_t flags; /* boot flags */ - uint16_t ehsize; /* boot ehsize */ - uint16_t phentsize; /* boot phentsize */ - uint16_t phnum; /* boot phnum */ - uint16_t shentsize; /* boot shentsize */ - uint16_t shnum; /* boot shnum */ - uint16_t shstrndx; /* boot shstrndx */ - uint32_t kernel_type; /* kernel type (0x34 to 0x37) */ - uint32_t kernel_offset; /* kernel offset (0x38 to 0x3B) */ - uint32_t kernel_vaddr; /* kernel address (0x3C to 0x3F) */ - uint32_t kernel_paddr; /* kernel address duplicate */ - uint32_t kernel_size; /* kernel size (0x44 to 0x47) */ - uint32_t kernel_msize; /* kernel size duplicate */ - uint32_t kernel_flags; /* kernel flags (0x4C to 0x4F) */ - uint32_t kernel_align; /* kernel alignment */ - uint32_t ramdisk_type; /* kernel type (0x54) */ - uint32_t ramdisk_offset; /* ramdisk offset (0x58 to 0x5B) */ - uint32_t ramdisk_vaddr; /* ramdisk address (0x5C to 0x5F) */ - uint32_t ramdisk_paddr; /* ramdisk address duplicate */ - uint32_t ramdisk_size; /* ramdisk size (0x64 to 0x67) */ - uint32_t ramdisk_msize; /* ramdisk size duplicate */ - uint32_t ramdisk_flags; /* ramdisk flags (0x6C to 0x6F) */ - uint32_t ramdisk_align; /* cmdline alignment */ - uint32_t rpm_type; /* rpm type (0x74 to 0x77) */ - uint32_t rpm_offset; /* rpm offset (0x78 to 0x7B) */ - uint32_t rpm_vaddr; /* rpm address (0x7C to 0x7F) */ - uint32_t rpm_paddr; /* rpm address duplicate */ - uint32_t rpm_size; /* rpm size (0x84 to 0x87) */ - uint32_t rpm_msize; /* rpm size duplicate */ - uint32_t rpm_flags; /* rpm flags (0x8C to 0x8F) */ - uint32_t rpm_align; /* rpm alignment */ - uint32_t cmd_type; /* cmdline type (0x94 to 0x97) */ - uint32_t cmd_offset; /* cmdline offset (0x98 to 0x9B) */ - uint32_t cmd_vaddr; /* cmdline address (0x9C to 0x9F) */ - uint32_t cmd_paddr; /* cmdline address duplicate */ - uint32_t cmd_size; /* cmdline size (0xA4 to 0xA7) */ - uint32_t cmd_msize; /* cmdline size duplicate */ - uint32_t cmd_flags; /* cmdline flags (0xAC to 0xAF) */ - uint32_t cmd_align; /* cmdline alignment */ - uint8_t header_vals[3900]; /* header additional values */ - uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) */ + uint16_t type; /* boot type (0x10 to 0x11) */ + uint16_t machine; /* boot machine (0x12 to 0x13) */ + uint32_t version; /* boot version (0x14 to 0x17) */ + uint32_t entry_addr; /* boot entry (0x18 to 0x1B) */ + uint32_t phoff; /* boot phoff (0x1C to 0x1F) */ + uint32_t shoff; /* boot shoff (0x20 to 0x23) */ + uint32_t flags; /* boot flags (0x24 to 0x27) */ + uint16_t ehsize; /* boot ehsize (0x28 to 0x29) */ + uint16_t phentsize; /* boot phentsize (0x2A to 0x2B) */ + uint16_t phnum; /* boot phnum (0x2C to 0x2D) */ + uint16_t shentsize; /* boot shentsize (0x2E to 0x2F)*/ + uint16_t shnum; /* boot shnum (0x30 to 0x31) */ + uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) */ +}; + +struct boot_img_elf_info +{ + struct boot_img_elf_hdr hdr; /* The ELF file header. */ + struct boot_img_elf_prog_hdr* prog; /* The program header entries. */ + struct boot_img_elf_sect_hdr* sect; /* The section header entries. */ + struct boot_img_elf_misc_hdr* misc; /* Miscellaneous information found in some ELF versions. */ + uint8_t elf_version; + uint8_t elf_out_format; + uint32_t cmdline_size; +}; + +struct boot_img_elf_prog_hdr +{ + uint32_t type; /* type (position + 0x0 to 0x3) */ + uint32_t offset; /* offset (position + 0x4 to 0x7) */ + uint32_t vaddr; /* address (position + 0x8 to 0xB) */ + uint32_t paddr; /* address duplicate (position + 0xC to 0xF) */ + uint32_t size; /* size (position + 0x10 to 0x13) */ + uint32_t msize; /* size duplicate (position + 0x14 to 0x17) */ + uint32_t flags; /* flags (position + 0x18 to 0x1B) */ + uint32_t align; /* alignment (position + 0x1C to 0x1F)*/ }; -typedef struct boot_img_hdr boot_img_hdr; +struct boot_img_elf_sect_hdr +{ + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint8_t misc[16]; +}; + +struct boot_img_elf_misc_hdr +{ + uint8_t* data; /* header additional data */ + uint32_t data_size; /* header additional size */ + uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ +}; #endif diff --git a/include/libbootimg.h b/include/libbootimg.h index 1aed9d1..dd4efe0 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -11,11 +11,20 @@ extern "C" { #include #include +#include #include "boot_img_hdr.h" #define LIBBOOTIMG_VERSION 0x000203 // 0xMMNNPP #define LIBBOOTIMG_VERSION_STR "0.2.3" +#ifdef DEBUG_KMSG +#define LOG_DBG(fmt, ...) klog_write(3, "<3>%s: " fmt, "libbootimg", ##__VA_ARGS__) +#elif DEBUG_STDOUT +#define LOG_DBG printf("libbootimg: "); printf +#else +#define LOG_DBG(fmt, ...) "" +#endif + /** * Enum containing possible blob types in a boot image. */ @@ -84,10 +93,12 @@ struct bootimg_blob struct bootimg { struct boot_img_hdr hdr; /*!< Boot image header */ - struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image. */ - int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file. */ - struct boot_img_hdr_elf* hdr_elf; /*!< Boot image header in ELF format */ + struct bootimg_blob blob; /* Complete blob */ + uint32_t blob_size; /* Size of the complete blob */ + struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image */ + int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file */ uint8_t is_elf; /*!< Select the ELF boot image format */ + struct boot_img_elf_info* hdr_info; /*!< Boot image meta-information for ELF formats */ }; /** @@ -117,6 +128,62 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma */ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); +/** + * Determines the ELF boot image version (custom definition) and the + * required output format (ELF or ANDROID!) based on the number of + * program headers given by the ELF header. + * @param hdr_info pointer to the structure holding the read header information + */ +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info); + +/** + * Reads the program headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the section headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the miscellaneous information from the given ELF file and adds the content + * to the given structure. This information is present in some ELF versions and + * required for them to operate properly (version 1). + * @param hdr_info structure holding the meta-information of the given ELF file + * @param size of the bootimage pagesize needed for alignment + * @param f pointer to the file descriptor of the ELF file + * @return one on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f); + +/** + * Extracts the kernel boot command line from an ELF file and adds it to + * the generic structure describing the blob (-> hdr). + * @param hdr pointer to boot_img_hdr structure + * @param elf_info structure holding the meta-information of the given ELF file. + * @param f pointer to the file descriptor of the ELF file. + */ +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f); + +/** + * Returns a pointer referencing the ELF program header which describes the content + * of a given type like the kernel or ramdisk part of a boot image. + * @param hdr_info structure holding the meta-information of the given ELF file. + * @param type integer value that describes the desired pointer as given in the enum + * {@link libbootimg_blob_type}. + * @return pointer to the program header describing the desired part of the boot image. + */ +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type); + /** * Loads boot_img_hdr or boot_img_hdr_elf from file on disk * @param hdr pointer to boot_img_hdr structure @@ -127,7 +194,7 @@ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); * successful, negative value from libbootimg_error if failed. */ int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path); + struct boot_img_elf_info *hdr_elf, uint8_t *is_elf, const char *path); /** * Updates the header addresses to the blobs. @@ -142,8 +209,6 @@ int libbootimg_update_headers(struct bootimg *b); */ void libbootimg_destroy(struct bootimg *b); - - /** * Writes blob to a file. * @param blob pointer to source struct bootimg_blob @@ -244,6 +309,14 @@ int libbootimg_write_img(struct bootimg *b, const char *dest); */ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f); +/** + * Writes boot image to a file: Updated implementation that effectively *injects* data into an existing boot image + * @param b pointer to struct bootimg + * @param f pointer to FILE to write data into + * @return number of bytes written to the file if successful, negative value from libbootimg_error if failed. + */ +int libbootimg_write_img_fileptr_new(struct bootimg *b, FILE *f); + /** * Writes boot image to a file and then calls libbootimg_destroy. * The bootimg struct is destroyed even if this function fails. @@ -274,6 +347,41 @@ const char *libbootimg_version_str(void); */ const char *libbootimg_error_str(int error); +/** + * Prints the content of the boot image information to the stdout or + * the kernel log (dmesg). + * @param hdr pointer to the boot image information. + */ +void print_hdr_to_log(struct boot_img_hdr* hdr); + +/** + * Prints the content of an elf header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_info pointer to the elf header information. + */ +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info); + +/** + * Prints the content of an elf program header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_prog_hdr pointer to the program header information. + */ +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr); + +/** + * Prints the content of an elf section header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr); + +/** + * Prints the content of an elf misc header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr); + #ifdef __cplusplus } #endif diff --git a/src/libbootimg.c b/src/libbootimg.c index 0e44f3d..6ea5b28 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -72,8 +72,13 @@ static void fill_id_hashes(struct bootimg *b) int i = 0; // hash blobs - for(; i < LIBBOOTIMG_BLOB_CNT && i < 5; ++i) - b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + for (; i < LIBBOOTIMG_BLOB_CNT ; ++i) + { + if (b->blobs[i].size != NULL) + { + b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + } + } // hash kernel, ramdisk and second _addr and _size together b->hdr.id[i++] = calc_fnv_hash(&b->hdr.kernel_size, sizeof(uint32_t)*6); @@ -92,8 +97,8 @@ void libbootimg_init_new(struct bootimg *img) memset(img, 0, sizeof(struct bootimg)); memcpy(img->hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); img->hdr.page_size = DEFAULT_PAGE_SIZE; - img->hdr_elf = malloc(sizeof(struct boot_img_hdr_elf)); - memset(img->hdr_elf, 0, sizeof(struct boot_img_hdr_elf)); + img->hdr_info = malloc(sizeof(struct boot_img_elf_info)); + memset(img->hdr_info, 0, sizeof(struct boot_img_elf_info)); img->is_elf = 0; img->blobs[LIBBOOTIMG_BLOB_KERNEL].size = &img->hdr.kernel_size; @@ -102,6 +107,30 @@ void libbootimg_init_new(struct bootimg *img) img->blobs[LIBBOOTIMG_BLOB_DTB].size = &img->hdr.dt_size; } +int libbootimg_read_blob(int64_t addr, struct bootimg_blob* blob, FILE* f) +{ + int res = 0; + if (fseek(f, addr, SEEK_SET) < 0) + { + if (errno == EINVAL) + { + res = LIBBOOTIMG_ERROR_IMG_EOF; + } + else + { + res = translate_errnum(errno); + } + return res; + } + blob->data = malloc(*blob->size); + if (fread(blob->data, *blob->size, 1, f) != 1) + { + res = translate_fread_error(f); + return res; + } + return res; +} + int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_mask) { int i; @@ -112,7 +141,7 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma libbootimg_init_new(img); - res = libbootimg_load_headers(&img->hdr, img->hdr_elf, &img->is_elf, path); + res = libbootimg_load_headers(&img->hdr, img->hdr_info, &img->is_elf, path); if(res < 0) { libbootimg_destroy(img); @@ -127,38 +156,27 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma addr = img->start_offset + img->hdr.page_size; - for(i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) + for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { blob = &img->blobs[i]; - if((load_blob_mask & (1 << i)) && *blob->size != 0) + if (img->is_elf) { - if(fseek(f, addr, SEEK_SET) < 0) + struct boot_img_elf_prog_hdr *cur_prog_hdr = get_elf_proc_hdr_of(img->hdr_info, i); + if (cur_prog_hdr != NULL) { - if(errno == EINVAL) - res = LIBBOOTIMG_ERROR_IMG_EOF; - else - res = translate_errnum(errno); - goto fail; - } - - blob->data = malloc(*blob->size); - - if(fread(blob->data, *blob->size, 1, f) != 1) - { - res = translate_fread_error(f); - goto fail; + res = libbootimg_read_blob(cur_prog_hdr->offset, blob, f); } } + else if ((load_blob_mask & (1 << i)) && *blob->size != 0) + { + res = libbootimg_read_blob(addr, blob, f); + } if (!img->is_elf) { addr += align_size(*blob->size, img->hdr.page_size); } - else - { - addr += *blob->size; - } } fclose(f); @@ -174,7 +192,7 @@ void libbootimg_destroy(struct bootimg *b) { struct bootimg_blob *blob = b->blobs; struct bootimg_blob * const blobs_end = blob + LIBBOOTIMG_BLOB_CNT; - free(b->hdr_elf); + free(b->hdr_info); for(; blob != blobs_end; ++blob) { free(blob->data); @@ -184,12 +202,12 @@ void libbootimg_destroy(struct bootimg *b) int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path) { - struct boot_img_hdr_elf hdr_elf; + struct boot_img_elf_info hdr_elf; return libbootimg_load_headers(hdr, &hdr_elf, NULL, path); } int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path) + struct boot_img_elf_info *hdr_info, uint8_t *is_elf, const char *path) { int res = 0; FILE *f; @@ -219,33 +237,98 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, res = known_magic_pos[i]; break; } - else if (hdr_elf != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, + else if (hdr_info != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, BOOT_MAGIC_ELF_SIZE) == 0) { fseek(f, 0, SEEK_SET); - if (fread(hdr_elf, sizeof(struct boot_img_hdr_elf), 1, f) == 1) + if (fread(&hdr_info->hdr, sizeof(struct boot_img_elf_hdr), 1, f) == 1) { - hdr->kernel_size = hdr_elf->kernel_size; - hdr->kernel_addr = hdr_elf->kernel_offset; - hdr->ramdisk_size = hdr_elf->ramdisk_size; - hdr->ramdisk_addr = hdr_elf->ramdisk_offset; - hdr->second_size = hdr_elf->rpm_size; - hdr->second_addr = hdr_elf->rpm_offset; - hdr->page_size = hdr_elf->kernel_offset; - hdr->tags_addr = 0; - hdr->dt_size = 0; hdr->id[0] = '\0'; - memcpy(hdr->name, hdr_elf->name, BOOT_NAME_SIZE); - cmd_len = hdr_elf->cmd_size; - memset(hdr->cmdline, '\0', BOOT_ARGS_SIZE); - fseek(f, hdr_elf->cmd_offset, SEEK_SET); - fread(hdr->cmdline, cmd_len < BOOT_ARGS_SIZE ? - cmd_len : BOOT_ARGS_SIZE, 1, f); + res = known_magic_pos[i]; if (is_elf != NULL) { *is_elf = 1; + print_elf_hdr_to_log(hdr_info); + } + + libbootimg_get_elf_version(hdr_info); + + res = libbootimg_load_elf_prog_header(hdr_info, f); + if (res != 1) + { + break; } + + // Update the standard boot image meta-information with + // the information found in the elf file + struct boot_img_elf_prog_hdr *kernel_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_KERNEL); + hdr->kernel_size = kernel_hdr->size; + hdr->kernel_addr = kernel_hdr->offset; + + struct boot_img_elf_prog_hdr *ramdisk_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_RAMDISK); + hdr->ramdisk_size = ramdisk_hdr->size; + hdr->ramdisk_addr = ramdisk_hdr->offset; + + struct boot_img_elf_prog_hdr *second_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_SECOND); + if (second_hdr != NULL) + { + hdr->second_size = second_hdr->size; + hdr->second_addr = second_hdr->offset; + } + else + { + hdr->second_size = 0; + hdr->second_addr = 0; + } + + struct boot_img_elf_prog_hdr *dtb_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_DTB); + if (dtb_hdr != NULL) + { + hdr->dt_size = dtb_hdr->size; + hdr->tags_addr = dtb_hdr->offset; + } + else + { + hdr->dt_size = 0; + hdr->tags_addr = 0; + } + + // ELF files version 1 are page aligned, version 2 are not + if (hdr_info->elf_version == VER_ELF_1) + { + hdr->page_size = hdr->kernel_addr; + } + else + { + hdr->page_size = DEFAULT_PAGE_SIZE; + } + + if (hdr_info->elf_version == VER_ELF_1) + { + res = libbootimg_load_elf_misc_header(hdr_info, hdr->page_size, f); + if (res != 1) + { + break; + } + memcpy(hdr->name, hdr_info->misc->name, BOOT_NAME_SIZE); + } + else if (hdr_info->elf_version == VER_ELF_2) + { + res = libbootimg_load_elf_sect_header(hdr_info, f); + if (res != 1) + { + break; + } + } + + libbootimg_read_cmdline(hdr, hdr_info, f); + + print_hdr_to_log(hdr); break; } } @@ -261,36 +344,271 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, return res; } +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info) +{ + switch (hdr_info->hdr.phnum) + { + case 3: + // Version 2 (found in Z2, 8960) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_2; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + break; + case 4: + default: + // Version 1 (found in SP, 8960) has 4 program headers + hdr_info->elf_version = VER_ELF_1; + hdr_info->elf_out_format = OUT_ELF; + break; + } +} + +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int prog_entry_size = sizeof(struct boot_img_elf_prog_hdr); + struct boot_img_elf_prog_hdr *prog_entry; + prog_entry = malloc(prog_entry_size * hdr_info->hdr.phnum); + hdr_info->prog = prog_entry; + + int prog_entry_idx = 0; + for (; prog_entry_idx < hdr_info->hdr.phnum; ++prog_entry_idx) + { + LOG_DBG("Reading program header %u/%u.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + res = fread(&prog_entry[prog_entry_idx], prog_entry_size, 1, f); + if (res == 1) + { + LOG_DBG("Program header %u/%u successfully read.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); + } + else + { + break; + } + } + return res; +} + +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int sect_entry_size = sizeof(struct boot_img_elf_sect_hdr); + struct boot_img_elf_sect_hdr *sect_entry; + + fseek(f, hdr_info->hdr.shoff, SEEK_SET); + sect_entry = malloc(hdr_info->hdr.shentsize * hdr_info->hdr.shnum); + hdr_info->sect = sect_entry; + + int sect_entry_idx = 0; + for (; sect_entry_idx < hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Reading section header %u/%u.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); + res = fread(§_entry[sect_entry_idx], sect_entry_size, 1, f); + + if (res == 1) + { + LOG_DBG("Section header %u/%u successfully read.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); + print_elf_sect_hdr_to_log(&hdr_info->sect[sect_entry_idx]); + } + else + { + break; + } + } + + return res; +} + +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f) +{ + if (hdr_info->elf_version != VER_ELF_1) + { + return -1; + } + + int res = 0; + int misc_entry_size = sizeof(struct boot_img_elf_misc_hdr); + struct boot_img_elf_misc_hdr *misc; + + int misc_offset = hdr_info->hdr.phoff + hdr_info->hdr.phnum * hdr_info->hdr.phentsize; + + fseek(f, misc_offset, SEEK_SET); + misc = malloc(misc_entry_size); + hdr_info->misc = misc; + + misc->data_size = (page_size - misc_offset - sizeof(misc->name)) * + sizeof(uint8_t); + misc->data = malloc(misc->data_size); + + res = fread(misc->data, misc->data_size, 1, f); + if (res == 1) + { + res = fread(misc->name, sizeof(misc->name), 1, f); + } + + LOG_DBG("Misc data size: %u / %u\n", misc->data_size, page_size); + LOG_DBG("Misc boot name: %s\n", misc->name); + + return res; +} + +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f) +{ + unsigned char buf[BOOT_ARGS_SIZE]; + int cmdline_start_pos = 0; + int cmd_len_max = 0; + + if (elf_info->elf_version == VER_ELF_1) + { + cmdline_start_pos = elf_info->prog[ELF_PROG_CMD].offset; + elf_info->cmdline_size = elf_info->prog[ELF_PROG_CMD].size; + cmd_len_max = elf_info->cmdline_size; + } + else if (elf_info->elf_version == VER_ELF_2) + { + cmdline_start_pos = elf_info->sect[ELF_SECT_CMD].offset; + elf_info->cmdline_size = elf_info->sect[ELF_SECT_CMD].size; + cmd_len_max = elf_info->cmdline_size; + } + cmd_len_max = cmd_len_max < BOOT_ARGS_SIZE ? cmd_len_max : BOOT_ARGS_SIZE; + + memset(&hdr->cmdline, '\0', BOOT_ARGS_SIZE); + memset(&buf, '\0', BOOT_ARGS_SIZE); + fseek(f, cmdline_start_pos, SEEK_SET); + fread(buf, cmd_len_max, 1, f); + + int buf_offset = 0; + if (elf_info->elf_version == VER_ELF_2) + { + buf_offset = 8; + } + + int buf_idx = 0; + for (; buf_idx < cmd_len_max; ++buf_idx) + { + hdr->cmdline[buf_idx] = buf[buf_idx + buf_offset]; + if (buf[buf_idx + buf_offset] == '\0') + { + break; + } + } + LOG_DBG("Cmd line: %s\n", hdr->cmdline); +} + +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type) +{ + switch (type) + { + case LIBBOOTIMG_BLOB_KERNEL: + return &elf_info->prog[ELF_PROG_KER]; + case LIBBOOTIMG_BLOB_RAMDISK: + return &elf_info->prog[ELF_PROG_RAM]; + case LIBBOOTIMG_BLOB_SECOND: + if (elf_info->elf_version == VER_ELF_1) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + case LIBBOOTIMG_BLOB_DTB: + if (elf_info->elf_version == VER_ELF_2) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + default: + break; + } + return NULL; +} + int libbootimg_update_headers(struct bootimg *b) { - uint32_t addr; + uint32_t addr = 0; if (b == NULL) return translate_errnum(ENOENT); - if (b->is_elf) + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - b->hdr_elf->kernel_size = b->hdr.kernel_size; - b->hdr_elf->kernel_msize = b->hdr.kernel_size; - b->hdr_elf->ramdisk_size = b->hdr.ramdisk_size; - b->hdr_elf->ramdisk_msize = b->hdr.ramdisk_size; - b->hdr_elf->rpm_size = b->hdr.second_size; - b->hdr_elf->rpm_msize = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_KER].size = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_KER].msize = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_RAM].size = b->hdr.ramdisk_size; + b->hdr_info->prog[ELF_PROG_RAM].msize = b->hdr.ramdisk_size; + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.second_size; + + if (b->hdr_info->elf_version == VER_ELF_1) + { + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr_info->cmdline_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr_info->cmdline_size; + } + else + { + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr.dt_size; + } + + LOG_DBG("Updating program headers...\n"); - addr = b->hdr_elf->kernel_offset; + addr = b->hdr_info->prog[ELF_PROG_KER].offset; - addr += b->hdr_elf->kernel_size; - b->hdr_elf->ramdisk_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_KER].size; + b->hdr_info->prog[ELF_PROG_RAM].offset = addr; - addr += b->hdr_elf->ramdisk_size; - b->hdr_elf->rpm_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_RAM].size; + b->hdr_info->prog[ELF_PROG_RPM].offset = addr; - addr += b->hdr_elf->rpm_size; - b->hdr_elf->cmd_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_RPM].size; + b->hdr_info->prog[ELF_PROG_CMD].offset = addr; - memcpy(b->hdr_elf->name, b->hdr.name, BOOT_NAME_SIZE); + addr += b->hdr_info->prog[ELF_PROG_CMD].size; + + // Also, we need to update the address/offset pointers & sizes + // in the section header table + int sect_entry_idx = 0; + for (; sect_entry_idx < b->hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Updating section header entry %d/%d...\n", + sect_entry_idx + 1, b->hdr_info->hdr.shnum); + b->hdr_info->sect[sect_entry_idx].offset = addr; + addr += b->hdr_info->sect[sect_entry_idx].size; + } + + if (b->hdr_info->elf_version == VER_ELF_1) + { + LOG_DBG("Updating misc header: name %s...\n", b->hdr.name); + memcpy(b->hdr_info->misc->name, b->hdr.name, BOOT_NAME_SIZE); + } + + // The section header is placed after the last section + if (b->hdr_info->hdr.shnum > 0) + { + b->hdr_info->hdr.shoff = addr; + } + + } + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_AND) + { + // ELF format found in stock Sony ROMs for, e.g, the Xperia Z2. + // If more formats exist, we should differ the assignments at + // the bottom of this function by the "elf version" + + b->hdr.magic[0] = 'A'; + b->hdr.magic[1] = 'N'; + b->hdr.magic[2] = 'D'; + b->hdr.magic[3] = 'R'; + b->hdr.magic[4] = 'O'; + b->hdr.magic[5] = 'I'; + b->hdr.magic[6] = 'D'; + b->hdr.magic[7] = '!'; + + b->hdr.kernel_addr = b->hdr_info->prog[ELF_PROG_KER].paddr; + b->hdr.ramdisk_addr = b->hdr_info->prog[ELF_PROG_RAM].paddr; + b->hdr.tags_addr = b->hdr_info->prog[ELF_PROG_RPM].paddr; } + print_hdr_to_log(&b->hdr); return 0; } @@ -402,12 +720,6 @@ int libbootimg_write_img(struct bootimg *b, const char *dest) FILE *f; int res; - if(b->hdr.kernel_size == 0 || b->hdr.ramdisk_size == 0) - return LIBBOOTIMG_ERROR_MISSING_BLOB; - - if(b->hdr.page_size < sizeof(b->hdr)) - return LIBBOOTIMG_ERROR_INVALID_PAGESIZE; - f = fopen(dest, "w"); if(!f) return translate_errnum(errno); @@ -423,10 +735,12 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) int i; int res = 0; char *blank = NULL; - size_t padding; + size_t padding = 0; struct bootimg_blob *blob; - int pos_start, pos_end; + int pos_start; + int pos_end = 0; + LOG_DBG("Writing.\n"); pos_start = ftell(f); if(pos_start < 0) return translate_errnum(errno); @@ -449,47 +763,139 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) blank = malloc(b->hdr.page_size); memset(blank, 0, b->hdr.page_size); - // write header - if (!b->is_elf) + // Update & write header + libbootimg_update_headers(b); + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { if (fwrite(&b->hdr, sizeof(b->hdr), 1, f) != 1) goto fail_fwrite; padding = align_size(sizeof(b->hdr), b->hdr.page_size) - sizeof(b->hdr); } - else + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - libbootimg_update_headers(b); - - if (fwrite(b->hdr_elf, sizeof(*b->hdr_elf), 1, f) != 1) + if (fwrite(&b->hdr_info->hdr, sizeof(b->hdr_info->hdr), 1, f) != 1) + { goto fail_fwrite; + } + + // Write the Program headers. + int num_prog_hdr = b->hdr_info->hdr.phnum; + int hdr_entry_idx = 0; + for (; hdr_entry_idx < num_prog_hdr; ++hdr_entry_idx) + { + print_elf_prog_hdr_to_log(&b->hdr_info->prog[hdr_entry_idx]); + if (fwrite(&b->hdr_info->prog[hdr_entry_idx], + b->hdr_info->hdr.phentsize, 1, f) == 1) + { + LOG_DBG("Program header %u/%u writing successful.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + } + else + { + LOG_DBG("Program failed %u/%u writing failed.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + goto fail_fwrite; + } + } - padding = align_size(sizeof(*b->hdr_elf), b->hdr.page_size) - sizeof(*b->hdr_elf); + if (b->hdr_info->elf_version == VER_ELF_1) + { + print_elf_misc_hdr_to_log(b->hdr_info->misc); + if (fwrite(b->hdr_info->misc->data, b->hdr_info->misc->data_size, + 1, f) != 1) + { + LOG_DBG("Misc data writing successful.\n"); + goto fail_fwrite; + } + else if (fwrite(b->hdr_info->misc->name, + sizeof(b->hdr_info->misc->name), 1, f) != 1) + { + LOG_DBG("Misc boot name writing failed.\n"); + goto fail_fwrite; + } + else + { + LOG_DBG("Misc header writing successful.\n"); + } + } + else if (b->hdr_info->elf_version == VER_ELF_2) + { + // Fill remaining block with 0s up to first prog entry + // (misc data NOT written back!) + uint32_t header_size = sizeof(b->hdr_info->hdr) + + b->hdr_info->hdr.phnum * b->hdr_info->hdr.phentsize + + b->hdr_info->hdr.shnum * b->hdr_info->hdr.shentsize; + uint32_t blank_size = b->hdr.page_size - header_size; + if (fwrite(blank, blank_size, 1, f) != blank_size) + { + goto fail_fwrite; + } + } } - if (fwrite(blank, 1, padding, f) != padding) - goto fail_fwrite; + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) + { + if (fwrite(blank, 1, padding, f) != padding) + goto fail_fwrite; + } for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { + LOG_DBG("Writing blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); + LOG_DBG("Writing to position 0x%lx.\n", ftell(f)); blob = &b->blobs[i]; if (*blob->size == 0) continue; if (fwrite(blob->data, *blob->size, 1, f) != 1) + { + LOG_DBG("Writing blob %d failed.\n", i + 1); goto fail_fwrite; + } - if (!b->is_elf) + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { padding = align_size(*blob->size, b->hdr.page_size) - *blob->size; if (fwrite(blank, 1, padding, f) != padding) + { + LOG_DBG("Writing padding of blob %d failed.\n", i + 1); goto fail_fwrite; + } } } - if (b->is_elf && fwrite(b->hdr.cmdline, b->hdr_elf->cmd_size, 1, f) != 1) - goto fail_fwrite; + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) + { + if (b->hdr_info->elf_version == VER_ELF_1) + { + pos_end += b->hdr_info->cmdline_size; + LOG_DBG("cmdline: %s\n", b->hdr.cmdline); + LOG_DBG("cmdline: %x\n", b->hdr_info->cmdline_size); + // Write the cmdline (last part ref by the prog header) + if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline.\n"); + goto fail_fwrite; + } + } + + // Write the section header if needed by the ELF + if (b->hdr_info->hdr.shnum > 0) + { + LOG_DBG("Writing section header.\n"); + fseek(f, b->hdr_info->hdr.shoff, SEEK_SET); + if (fwrite(b->hdr_info->sect, b->hdr_info->hdr.shentsize, 1, f) == 1) + { + print_elf_sect_hdr_to_log(&b->hdr_info->sect[ELF_SECT_CMD]); + } + else + { + goto fail_fwrite; + } + } + } pos_end = ftell(f); @@ -525,7 +931,7 @@ const char *libbootimg_version_str(void) const char *libbootimg_error_str(int error) { - switch(error) + switch (error) { case LIBBOOTIMG_SUCCESS: return "No errors"; case LIBBOOTIMG_ERROR_IO: return "Input/output error"; @@ -542,3 +948,86 @@ const char *libbootimg_error_str(int error) default: return "Unknown error"; } } + +void print_hdr_to_log(struct boot_img_hdr* hdr) +{ + LOG_DBG("* kernel size = %u bytes (%.2f MB)\n", hdr->kernel_size, + (double )hdr->kernel_size / 0x100000); + LOG_DBG(" ramdisk size = %u bytes (%.2f MB)\n", hdr->ramdisk_size, + (double )hdr->ramdisk_size / 0x100000); + if (hdr->second_size) + { + LOG_DBG(" second stage size = %u bytes (%.2f MB)\n", hdr->second_size, + (double )hdr->second_size / 0x100000); + } + if (hdr->dt_size) + { + LOG_DBG(" device tree size = %u bytes (%.2f MB)\n", hdr->dt_size, + (double )hdr->dt_size / 0x100000); + } + LOG_DBG("* load addresses:\n"); + LOG_DBG(" kernel: 0x%08x\n", hdr->kernel_addr); + LOG_DBG(" ramdisk: 0x%08x\n", hdr->ramdisk_addr); + if (hdr->second_size) + { + LOG_DBG(" second stage: 0x%08x\n", hdr->second_addr); + } + LOG_DBG(" tags: 0x%08x\n", hdr->tags_addr); +} + +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) +{ + (void)elf_info; + LOG_DBG("========= ELF header content =========\n"); + LOG_DBG("Type (0x10 to 0x11) = %x\n", elf_info->hdr.type); + LOG_DBG("Machine (0x12 to 0x13) = %x\n", elf_info->hdr.machine); + LOG_DBG("Version (0x14 to 0x17) = %x\n", elf_info->hdr.version); + LOG_DBG("Entry Address (0x18 to 0x1B) = %x\n", elf_info->hdr.entry_addr); + LOG_DBG("Phys Offset (0x1C to 0x1F) = %x\n", elf_info->hdr.phoff); + LOG_DBG("Section Offset (0x20 to 0x23) = %x\n", elf_info->hdr.shoff); + LOG_DBG("Flags (0x24 to 0x27) = %x\n", elf_info->hdr.flags); + LOG_DBG("Ehsize (0x28 to 0x29) = %x\n", elf_info->hdr.ehsize); + LOG_DBG("Ph entry size (0x2A to 0x2B) = %x\n", elf_info->hdr.phentsize); + LOG_DBG("Ph number (0x2C to 0x2D) = %x\n", elf_info->hdr.phnum); + LOG_DBG("Sect entry size (0x2E to 0x2F) = %x\n", elf_info->hdr.shentsize); + LOG_DBG("Sect number (0x30 to 0x31) = %x\n", elf_info->hdr.shnum); + LOG_DBG("Sect strndx (0x32 to 0x33) = %x\n", elf_info->hdr.shstrndx); + LOG_DBG("======================================\n"); +} + +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr) +{ + (void)elf_prog_hdr; + LOG_DBG("===== ELF program header content =====\n"); + LOG_DBG("Type = %x\n", elf_prog_hdr->type); + LOG_DBG("Offset = %x\n", elf_prog_hdr->offset); + LOG_DBG("VAddr = %x\n", elf_prog_hdr->vaddr); + LOG_DBG("PAddr = %x\n", elf_prog_hdr->paddr); + LOG_DBG("Size = %x\n", elf_prog_hdr->size); + LOG_DBG("MSize = %x\n", elf_prog_hdr->msize); + LOG_DBG("Flags = %x\n", elf_prog_hdr->flags); + LOG_DBG("Align = %x\n", elf_prog_hdr->align); + LOG_DBG("======================================\n"); +} + +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr) +{ + (void)elf_sect_hdr; + LOG_DBG("===== ELF section header content =====\n"); + LOG_DBG("Name = %x\n", elf_sect_hdr->name); + LOG_DBG("Type = %x\n", elf_sect_hdr->type); + LOG_DBG("Flags = %x\n", elf_sect_hdr->flags); + LOG_DBG("Address = %x\n", elf_sect_hdr->addr); + LOG_DBG("Offset = %x\n", elf_sect_hdr->offset); + LOG_DBG("Size = %x\n", elf_sect_hdr->size); + LOG_DBG("======================================\n"); +} + +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr) +{ + (void)elf_misc_hdr; + LOG_DBG("====== ELF misc header content =======\n"); + LOG_DBG("Data size = %u\n", elf_misc_hdr->data_size); + LOG_DBG("Boot name = %s\n", elf_misc_hdr->name); + LOG_DBG("======================================\n"); +} From 3c9d4dc300ac60cba86eb333fcddd87da7cf45fc Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Fri, 16 Dec 2016 23:36:10 +0100 Subject: [PATCH 03/10] libbootimg: Add an helper for 32/64 bits host detection * Used for debugging in the first place * Call libbootimg_get_elf_version earlier for outputs Change-Id: Id16fa289957b168c3fb6b578a8a83a0a6ddd88c5 Signed-off-by: Adrian DC --- include/libbootimg.h | 8 ++++++++ src/bbootimg.c | 3 +++ src/libbootimg.c | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/libbootimg.h b/include/libbootimg.h index dd4efe0..fa803e4 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -25,6 +25,9 @@ extern "C" { #define LOG_DBG(fmt, ...) "" #endif +#define ARCH_32_BITS 0 +#define ARCH_64_BITS 1 + /** * Enum containing possible blob types in a boot image. */ @@ -326,6 +329,11 @@ int libbootimg_write_img_fileptr_new(struct bootimg *b, FILE *f); */ int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest); +/** + * Returns architecture type, 32bits or 64bits + * @return architecture identification ARCH_32_BITS or ARCH_64_BITS + */ +uint8_t libbootimg_architecture(void); /** * Returns version number, format is 0xMMNNPP, so for version 0.1.12 it would return 0x000112 diff --git a/src/bbootimg.c b/src/bbootimg.c index aada563..188e6ea 100644 --- a/src/bbootimg.c +++ b/src/bbootimg.c @@ -286,6 +286,9 @@ static int print_info(const char *path) img.hdr.cmdline[BOOT_ARGS_SIZE-1] = 0; printf ("\nAndroid Boot Image Info:\n\n"); + printf ("* architecture = %s\n\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); + printf ("* file name = %s\n\n", path); printf ("* image size = %ld bytes (%.2f MB)\n", size, (double)size/0x100000); diff --git a/src/libbootimg.c b/src/libbootimg.c index 6ea5b28..797fec6 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -245,6 +246,8 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, { hdr->id[0] = '\0'; + libbootimg_get_elf_version(hdr_info); + res = known_magic_pos[i]; if (is_elf != NULL) { @@ -252,8 +255,6 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, print_elf_hdr_to_log(hdr_info); } - libbootimg_get_elf_version(hdr_info); - res = libbootimg_load_elf_prog_header(hdr_info, f); if (res != 1) { @@ -919,6 +920,33 @@ int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest) return res; } +uint8_t libbootimg_architecture(void) +{ + FILE* cpuinfo; + char buffer[100]; + + memset(buffer, 0, sizeof(buffer)); + cpuinfo = fopen("/proc/cpuinfo", "rb"); + + if (cpuinfo == NULL) + { + return ARCH_32_BITS; + } + + if (fread(buffer, 1, sizeof(buffer), cpuinfo) == 0) + { + fclose(cpuinfo); + return ARCH_32_BITS; + } + fclose(cpuinfo); + + if (strstr(buffer, "aarch64")) { + return ARCH_64_BITS; + } + + return ARCH_32_BITS; +} + uint32_t libbootimg_version(void) { return LIBBOOTIMG_VERSION; @@ -951,6 +979,9 @@ const char *libbootimg_error_str(int error) void print_hdr_to_log(struct boot_img_hdr* hdr) { + LOG_DBG("* architecture = %s\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); + LOG_DBG("* kernel size = %u bytes (%.2f MB)\n", hdr->kernel_size, (double )hdr->kernel_size / 0x100000); LOG_DBG(" ramdisk size = %u bytes (%.2f MB)\n", hdr->ramdisk_size, @@ -979,6 +1010,8 @@ void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) { (void)elf_info; LOG_DBG("========= ELF header content =========\n"); + LOG_DBG("Architecture = %s\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); LOG_DBG("Type (0x10 to 0x11) = %x\n", elf_info->hdr.type); LOG_DBG("Machine (0x12 to 0x13) = %x\n", elf_info->hdr.machine); LOG_DBG("Version (0x14 to 0x17) = %x\n", elf_info->hdr.version); From 05f14d6dd7cf0e82e84f9183ed1135026d026cc8 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Fri, 16 Dec 2016 23:51:40 +0100 Subject: [PATCH 04/10] libbootimg: Detail usual values of the ELF header for 8960/8974 * Kept as reference to easily compare alternative headers Change-Id: I25b62f898acb192c0b9ac7df5489839e0525b1d4 Signed-off-by: Adrian DC --- include/boot_img_hdr.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index 6ce3a33..bb01093 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -96,21 +96,22 @@ struct boot_img_hdr struct boot_img_elf_hdr { - uint8_t magic[8]; /* .ELF (0x00 to 0x07) */ - uint8_t unused[8]; /* unused chars (0x08 to 0x0F) */ - uint16_t type; /* boot type (0x10 to 0x11) */ - uint16_t machine; /* boot machine (0x12 to 0x13) */ - uint32_t version; /* boot version (0x14 to 0x17) */ - uint32_t entry_addr; /* boot entry (0x18 to 0x1B) */ - uint32_t phoff; /* boot phoff (0x1C to 0x1F) */ - uint32_t shoff; /* boot shoff (0x20 to 0x23) */ - uint32_t flags; /* boot flags (0x24 to 0x27) */ - uint16_t ehsize; /* boot ehsize (0x28 to 0x29) */ - uint16_t phentsize; /* boot phentsize (0x2A to 0x2B) */ - uint16_t phnum; /* boot phnum (0x2C to 0x2D) */ - uint16_t shentsize; /* boot shentsize (0x2E to 0x2F)*/ - uint16_t shnum; /* boot shnum (0x30 to 0x31) */ - uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) */ + /* Global structure of the Sony ELF header - Respective usual values: | 8960 | 8974 | */ + uint8_t magic[8]; /* .ELF (0x00 to 0x07) | .ELF... | .ELF... | */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) | 0x00 | 0x00 | */ + uint16_t type; /* boot type (0x10 to 0x11) | 0x02 | 0x02 | */ + uint16_t machine; /* boot machine (0x12 to 0x13) | 0x28 | 0x28 | */ + uint32_t version; /* boot version (0x14 to 0x17) | 0x01 | 0x01 | */ + uint32_t entry_addr; /* boot entry (0x18 to 0x1B) | 0x80208000 | 0x00008000 | */ + uint32_t phoff; /* boot phoff (0x1C to 0x1F) | 0x34 | 0x34 | */ + uint32_t shoff; /* boot shoff (0x20 to 0x23) | 0x00000000 | 0x00B3.... | */ + uint32_t flags; /* boot flags (0x24 to 0x27) | 0x00 | 0x00 | */ + uint16_t ehsize; /* boot ehsize (0x28 to 0x29) | 0x34 | 0x34 | */ + uint16_t phentsize; /* boot phentsize (0x2A to 0x2B) | 0x20 | 0x20 | */ + uint16_t phnum; /* boot phnum (0x2C to 0x2D) | 0x05/0x04 | 0x03 | */ + uint16_t shentsize; /* boot shentsize (0x2E to 0x2F) | 0x00 | 0x28 | */ + uint16_t shnum; /* boot shnum (0x30 to 0x31) | 0x00 | 0x01 | */ + uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) | 0x00 | 0x00 | */ }; struct boot_img_elf_info From 003f727c555afe47ebbeb7c18157ac15cf9e34ac Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 18 Dec 2016 01:23:09 +0100 Subject: [PATCH 05/10] libbootimg: Cleanup and improve the ELF debugging * Additional errors / success outputs * Display sizes in decimals instead of hexadecimal * Rewrite the ELF headers details outputs * Cleanup code styles Change-Id: I3b4e2277474497d8d8d97056562457df88a20779 Signed-off-by: Adrian DC --- src/libbootimg.c | 61 ++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/libbootimg.c b/src/libbootimg.c index 797fec6..98de232 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -376,15 +376,19 @@ int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) int prog_entry_idx = 0; for (; prog_entry_idx < hdr_info->hdr.phnum; ++prog_entry_idx) { - LOG_DBG("Reading program header %u/%u.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + LOG_DBG("Reading program header %u/%u.\n", + prog_entry_idx + 1, hdr_info->hdr.phnum); res = fread(&prog_entry[prog_entry_idx], prog_entry_size, 1, f); if (res == 1) { - LOG_DBG("Program header %u/%u successfully read.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + LOG_DBG("Program header %u/%u successfully read.\n", + prog_entry_idx + 1, hdr_info->hdr.phnum); print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); } else { + LOG_DBG("Program header %u/%u read failed.\n", + prog_entry_idx + 1, hdr_info->hdr.phnum); break; } } @@ -409,11 +413,14 @@ int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f) if (res == 1) { - LOG_DBG("Section header %u/%u successfully read.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); + LOG_DBG("Section header %u/%u successfully read.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); print_elf_sect_hdr_to_log(&hdr_info->sect[sect_entry_idx]); } else { + LOG_DBG("Section header %u/%u read failed.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); break; } } @@ -843,12 +850,16 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { - LOG_DBG("Writing blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); - LOG_DBG("Writing to position 0x%lx.\n", ftell(f)); blob = &b->blobs[i]; if (*blob->size == 0) + { + LOG_DBG("Ignored empty blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); continue; + } + + LOG_DBG("Writing blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); + LOG_DBG("Writing to position 0x%lx.\n", ftell(f)); if (fwrite(blob->data, *blob->size, 1, f) != 1) { @@ -871,10 +882,10 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) { if (b->hdr_info->elf_version == VER_ELF_1) { + // Write the cmdline (last part ref by the prog header) pos_end += b->hdr_info->cmdline_size; LOG_DBG("cmdline: %s\n", b->hdr.cmdline); - LOG_DBG("cmdline: %x\n", b->hdr_info->cmdline_size); - // Write the cmdline (last part ref by the prog header) + LOG_DBG("cmdline size: %u\n", b->hdr_info->cmdline_size); if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) { LOG_DBG("Failed to write the cmdline.\n"); @@ -910,6 +921,7 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) res = LIBBOOTIMG_ERROR_IO; exit: free(blank); + LOG_DBG("Done writing.\n"); return res; } @@ -1009,22 +1021,25 @@ void print_hdr_to_log(struct boot_img_hdr* hdr) void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) { (void)elf_info; + LOG_DBG("\n"); LOG_DBG("========= ELF header content =========\n"); LOG_DBG("Architecture = %s\n", libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); - LOG_DBG("Type (0x10 to 0x11) = %x\n", elf_info->hdr.type); - LOG_DBG("Machine (0x12 to 0x13) = %x\n", elf_info->hdr.machine); - LOG_DBG("Version (0x14 to 0x17) = %x\n", elf_info->hdr.version); - LOG_DBG("Entry Address (0x18 to 0x1B) = %x\n", elf_info->hdr.entry_addr); - LOG_DBG("Phys Offset (0x1C to 0x1F) = %x\n", elf_info->hdr.phoff); - LOG_DBG("Section Offset (0x20 to 0x23) = %x\n", elf_info->hdr.shoff); - LOG_DBG("Flags (0x24 to 0x27) = %x\n", elf_info->hdr.flags); - LOG_DBG("Ehsize (0x28 to 0x29) = %x\n", elf_info->hdr.ehsize); - LOG_DBG("Ph entry size (0x2A to 0x2B) = %x\n", elf_info->hdr.phentsize); - LOG_DBG("Ph number (0x2C to 0x2D) = %x\n", elf_info->hdr.phnum); - LOG_DBG("Sect entry size (0x2E to 0x2F) = %x\n", elf_info->hdr.shentsize); - LOG_DBG("Sect number (0x30 to 0x31) = %x\n", elf_info->hdr.shnum); - LOG_DBG("Sect strndx (0x32 to 0x33) = %x\n", elf_info->hdr.shstrndx); + LOG_DBG("ELF Version = %x\n", elf_info->elf_version); + LOG_DBG("Output format = %s\n", elf_info->elf_out_format == OUT_ELF ? "ELF" : "ANDROID"); + LOG_DBG("Type = %u\n", elf_info->hdr.type); + LOG_DBG("Machine = %u\n", elf_info->hdr.machine); + LOG_DBG("Version = %u\n", elf_info->hdr.version); + LOG_DBG("Entry Address = %x\n", elf_info->hdr.entry_addr); + LOG_DBG("Program Offset = %x\n", elf_info->hdr.phoff); + LOG_DBG("Section Offset = %x\n", elf_info->hdr.shoff); + LOG_DBG("Flags = %x\n", elf_info->hdr.flags); + LOG_DBG("Ehsize = %u\n", elf_info->hdr.ehsize); + LOG_DBG("Program headers size = %u\n", elf_info->hdr.phentsize); + LOG_DBG("Program headers number = %u\n", elf_info->hdr.phnum); + LOG_DBG("Section headers size = %u\n", elf_info->hdr.shentsize); + LOG_DBG("Section headers number = %u\n", elf_info->hdr.shnum); + LOG_DBG("Section strndx = %x\n", elf_info->hdr.shstrndx); LOG_DBG("======================================\n"); } @@ -1036,8 +1051,8 @@ void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr) LOG_DBG("Offset = %x\n", elf_prog_hdr->offset); LOG_DBG("VAddr = %x\n", elf_prog_hdr->vaddr); LOG_DBG("PAddr = %x\n", elf_prog_hdr->paddr); - LOG_DBG("Size = %x\n", elf_prog_hdr->size); - LOG_DBG("MSize = %x\n", elf_prog_hdr->msize); + LOG_DBG("Size = %u\n", elf_prog_hdr->size); + LOG_DBG("MSize = %u\n", elf_prog_hdr->msize); LOG_DBG("Flags = %x\n", elf_prog_hdr->flags); LOG_DBG("Align = %x\n", elf_prog_hdr->align); LOG_DBG("======================================\n"); @@ -1052,7 +1067,7 @@ void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr) LOG_DBG("Flags = %x\n", elf_sect_hdr->flags); LOG_DBG("Address = %x\n", elf_sect_hdr->addr); LOG_DBG("Offset = %x\n", elf_sect_hdr->offset); - LOG_DBG("Size = %x\n", elf_sect_hdr->size); + LOG_DBG("Size = %u\n", elf_sect_hdr->size); LOG_DBG("======================================\n"); } From 7beeaeeda54225d0c9509c5090b96f39ada887ca Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 18 Dec 2016 01:33:09 +0100 Subject: [PATCH 06/10] libbootimg: Fix the ELF output structures for v2 (Sony 8974) * Usage of the second (rpm) should only be on 8960 * Usage of the DTB data added for v2 (8974) * The ELF format should not have blank padding added Change-Id: I66926b91b173563e767a76cb9bf332e4e6e0a9fa Signed-off-by: Adrian DC --- src/libbootimg.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/libbootimg.c b/src/libbootimg.c index 98de232..505457f 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -543,16 +543,18 @@ int libbootimg_update_headers(struct bootimg *b) b->hdr_info->prog[ELF_PROG_KER].msize = b->hdr.kernel_size; b->hdr_info->prog[ELF_PROG_RAM].size = b->hdr.ramdisk_size; b->hdr_info->prog[ELF_PROG_RAM].msize = b->hdr.ramdisk_size; - b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.second_size; - b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.second_size; if (b->hdr_info->elf_version == VER_ELF_1) { + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.second_size; b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr_info->cmdline_size; b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr_info->cmdline_size; } else { + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.dt_size; b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr.dt_size; b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr.dt_size; } @@ -568,9 +570,12 @@ int libbootimg_update_headers(struct bootimg *b) b->hdr_info->prog[ELF_PROG_RPM].offset = addr; addr += b->hdr_info->prog[ELF_PROG_RPM].size; - b->hdr_info->prog[ELF_PROG_CMD].offset = addr; - addr += b->hdr_info->prog[ELF_PROG_CMD].size; + if (b->hdr_info->elf_version == VER_ELF_1) + { + b->hdr_info->prog[ELF_PROG_CMD].offset = addr; + addr += b->hdr_info->prog[ELF_PROG_CMD].size; + } // Also, we need to update the address/offset pointers & sizes // in the section header table @@ -827,19 +832,6 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) LOG_DBG("Misc header writing successful.\n"); } } - else if (b->hdr_info->elf_version == VER_ELF_2) - { - // Fill remaining block with 0s up to first prog entry - // (misc data NOT written back!) - uint32_t header_size = sizeof(b->hdr_info->hdr) + - b->hdr_info->hdr.phnum * b->hdr_info->hdr.phentsize + - b->hdr_info->hdr.shnum * b->hdr_info->hdr.shentsize; - uint32_t blank_size = b->hdr.page_size - header_size; - if (fwrite(blank, blank_size, 1, f) != blank_size) - { - goto fail_fwrite; - } - } } if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) From 5e439cfe3efbad745fbf08cd476691a82a7d549e Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 18 Dec 2016 01:48:55 +0100 Subject: [PATCH 07/10] libbootimg: Properly handle the ELF v2 cmdline with section header * Store the initial 8 bytes of metadata that used to be ignored with an offset in order to rebuild the ELF original structure * Store the additional signature stored after the cmdline inside the section data on Sony ELF v2 bootimages Change-Id: I4324c88431c4d265d7e5c61f1491b6b1bfffb242 Signed-off-by: Adrian DC --- include/boot_img_hdr.h | 4 ++ src/libbootimg.c | 88 +++++++++++++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index bb01093..c9ad437 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -123,6 +123,10 @@ struct boot_img_elf_info uint8_t elf_version; uint8_t elf_out_format; uint32_t cmdline_size; + uint8_t cmdline_metadata[8]; + uint32_t cmdline_metadata_cnt; + uint8_t* cmdline_signature; + uint32_t cmdline_signature_cnt; }; struct boot_img_elf_prog_hdr diff --git a/src/libbootimg.c b/src/libbootimg.c index 505457f..1c89e17 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -100,6 +100,7 @@ void libbootimg_init_new(struct bootimg *img) img->hdr.page_size = DEFAULT_PAGE_SIZE; img->hdr_info = malloc(sizeof(struct boot_img_elf_info)); memset(img->hdr_info, 0, sizeof(struct boot_img_elf_info)); + img->hdr_info->cmdline_signature = 0; img->is_elf = 0; img->blobs[LIBBOOTIMG_BLOB_KERNEL].size = &img->hdr.kernel_size; @@ -193,6 +194,10 @@ void libbootimg_destroy(struct bootimg *b) { struct bootimg_blob *blob = b->blobs; struct bootimg_blob * const blobs_end = blob + LIBBOOTIMG_BLOB_CNT; + if (b->hdr_info->cmdline_signature != 0) + { + free(b->hdr_info->cmdline_signature); + } free(b->hdr_info); for(; blob != blobs_end; ++blob) { @@ -465,42 +470,62 @@ void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info { unsigned char buf[BOOT_ARGS_SIZE]; int cmdline_start_pos = 0; - int cmd_len_max = 0; + uint32_t cmdline_full_size = 0; if (elf_info->elf_version == VER_ELF_1) { cmdline_start_pos = elf_info->prog[ELF_PROG_CMD].offset; elf_info->cmdline_size = elf_info->prog[ELF_PROG_CMD].size; - cmd_len_max = elf_info->cmdline_size; } else if (elf_info->elf_version == VER_ELF_2) { cmdline_start_pos = elf_info->sect[ELF_SECT_CMD].offset; elf_info->cmdline_size = elf_info->sect[ELF_SECT_CMD].size; - cmd_len_max = elf_info->cmdline_size; } - cmd_len_max = cmd_len_max < BOOT_ARGS_SIZE ? cmd_len_max : BOOT_ARGS_SIZE; + + cmdline_full_size = elf_info->cmdline_size; + elf_info->cmdline_signature = 0; + elf_info->cmdline_signature_cnt = 0; + elf_info->cmdline_size = cmdline_full_size < BOOT_ARGS_SIZE ? + cmdline_full_size : BOOT_ARGS_SIZE; memset(&hdr->cmdline, '\0', BOOT_ARGS_SIZE); - memset(&buf, '\0', BOOT_ARGS_SIZE); fseek(f, cmdline_start_pos, SEEK_SET); - fread(buf, cmd_len_max, 1, f); - int buf_offset = 0; + int buf_idx; if (elf_info->elf_version == VER_ELF_2) { - buf_offset = 8; + elf_info->cmdline_metadata_cnt = 8; + if (fread(elf_info->cmdline_metadata, 8, 1, f) != 1) + { + LOG_DBG("Cmd line metadata read failed.\n"); + } + } + else + { + elf_info->cmdline_metadata_cnt = 0; + memset(elf_info->cmdline_metadata, + 0, sizeof(elf_info->cmdline_metadata)); } - int buf_idx = 0; - for (; buf_idx < cmd_len_max; ++buf_idx) + fread(hdr->cmdline, elf_info->cmdline_size, 1, f); + + if (cmdline_full_size > elf_info->cmdline_size) { - hdr->cmdline[buf_idx] = buf[buf_idx + buf_offset]; - if (buf[buf_idx + buf_offset] == '\0') + elf_info->cmdline_signature_cnt = + cmdline_full_size - elf_info->cmdline_size; + elf_info->cmdline_signature = malloc( + elf_info->cmdline_signature_cnt * sizeof(uint8_t)); + + LOG_DBG("Cmd line signature size: %u\n", + elf_info->cmdline_signature_cnt); + if (fread(elf_info->cmdline_signature, elf_info->cmdline_signature_cnt, + 1, f) != 1) { - break; + LOG_DBG("Cmd line signature read failed.\n"); } } + LOG_DBG("Cmd line: %s\n", hdr->cmdline); } @@ -888,6 +913,43 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) // Write the section header if needed by the ELF if (b->hdr_info->hdr.shnum > 0) { + // Prepare the cmdline data + LOG_DBG("Writing cmdline data.\n"); + LOG_DBG("cmdline: %s\n", b->hdr.cmdline); + LOG_DBG("cmdline size: %u\n", b->hdr_info->cmdline_size); + fseek(f, b->hdr_info->sect[ELF_SECT_CMD].offset, SEEK_SET); + + // Write the cmdline metadata + if (b->hdr_info->cmdline_metadata_cnt > 0 && + fwrite(&b->hdr_info->cmdline_metadata, + b->hdr_info->cmdline_metadata_cnt, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline metadata.\n"); + goto fail_fwrite; + } + + // Write the cmdline based on section header + if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline.\n"); + goto fail_fwrite; + } + + // Write the cmdline signature based on section header + if (b->hdr_info->cmdline_signature_cnt > 0) + { + LOG_DBG("Writing cmdline signature.\n"); + fseek(f, b->hdr_info->sect[ELF_SECT_CMD].offset + + b->hdr_info->cmdline_metadata_cnt + BOOT_ARGS_SIZE, SEEK_SET); + if (fwrite(b->hdr_info->cmdline_signature, + b->hdr_info->cmdline_signature_cnt, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline signature.\n"); + goto fail_fwrite; + } + } + + // Write the section header LOG_DBG("Writing section header.\n"); fseek(f, b->hdr_info->hdr.shoff, SEEK_SET); if (fwrite(b->hdr_info->sect, b->hdr_info->hdr.shentsize, 1, f) == 1) From ac5a755174367d6d2c02f7cb4a1300c3779caf80 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 18 Dec 2016 01:55:25 +0100 Subject: [PATCH 08/10] libbootimg: Add support for 64bits Sony ELF format * Compatibility for the ELF partition used on the msm8996 devices like the Xperia X Performance * Structures aligned with 64bits addresses, offsets and sizes to match Stock bootimage * Usage of "__attribute__((packed))" to avoid structures padding breakage * Add the VER_ELF_4 identifier * Properly convert 32bits -> 64bits and reverse * Use the 64bits structures as main data * Add the libbootimg_load_elf_header function to separate the ELF header handling Change-Id: I40559ecc32833aed7b3ca7f3ebf8d53b9bc9b471 Signed-off-by: Adrian DC --- include/boot_img_hdr.h | 63 ++++++- include/libbootimg.h | 9 + src/libbootimg.c | 364 +++++++++++++++++++++++++++++++++++------ 3 files changed, 382 insertions(+), 54 deletions(-) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index c9ad437..09d1a22 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -58,6 +58,7 @@ #define BOOT_MAGIC_ELF_SIZE 3 #define VER_ELF_1 (1 << 0) #define VER_ELF_2 (1 << 1) +#define VER_ELF_4 (1 << 3) #define OUT_ELF (1 << 0) /* Same output format: ELF container */ #define OUT_AND (1 << 1) /* Different output format: standard Android container */ @@ -94,7 +95,7 @@ struct boot_img_hdr uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ }; -struct boot_img_elf_hdr +struct boot_img_elf_hdr_32 { /* Global structure of the Sony ELF header - Respective usual values: | 8960 | 8974 | */ uint8_t magic[8]; /* .ELF (0x00 to 0x07) | .ELF... | .ELF... | */ @@ -114,12 +115,36 @@ struct boot_img_elf_hdr uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) | 0x00 | 0x00 | */ }; +struct __attribute__((packed)) boot_img_elf_hdr +{ + /* Global structure of the Sony ELF header - Respective usual values: | 8996 | */ + uint8_t magic[8]; /* .ELF (0x00 to 0x07) | .ELF... | */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) | 0x00 | */ + uint16_t type; /* boot type (0x10 to 0x11) | 0x02 | */ + uint16_t machine; /* boot machine (0x12 to 0x13) | 0x28 | */ + uint32_t version; /* boot version (0x14 to 0x17) | 0x01 | */ + uint64_t entry_addr; /* boot entry (0x18 to 0x1F) | 0x80080000 | */ + uint64_t phoff; /* boot phoff (0x20 to 0x27) | 0x40 | */ + uint64_t shoff; /* boot shoff (0x28 to 0x2F) | 0x0214.... | */ + uint32_t flags; /* boot flags (0x30 to 0x33) | 0x00 | */ + uint16_t ehsize; /* boot ehsize (0x34 to 0x35) | 0x40 | */ + uint16_t phentsize; /* boot phentsize (0x36 to 0x37) | 0x38 | */ + uint16_t phnum; /* boot phnum (0x38 to 0x39) | 0x03 | */ + uint16_t shentsize; /* boot shentsize (0x3A to 0x3B) | 0x40 | */ + uint16_t shnum; /* boot shnum (0x3C to 0x3D) | 0x01 | */ + uint16_t shstrndx; /* boot shstrndx (0x3E to 0x3F) | 0x00 | */ +}; + struct boot_img_elf_info { - struct boot_img_elf_hdr hdr; /* The ELF file header. */ - struct boot_img_elf_prog_hdr* prog; /* The program header entries. */ - struct boot_img_elf_sect_hdr* sect; /* The section header entries. */ - struct boot_img_elf_misc_hdr* misc; /* Miscellaneous information found in some ELF versions. */ + struct boot_img_elf_hdr hdr; /* The ELF file header (64 bits). */ + struct boot_img_elf_hdr_32 hdr_32; /* The ELF file header (32 bits). */ + struct boot_img_elf_prog_hdr* prog; /* The program header entries (64 bits). */ + struct boot_img_elf_prog_hdr_32* prog_32; /* The program header entries (32 bits). */ + struct boot_img_elf_sect_hdr* sect; /* The section header entries (64 bits). */ + struct boot_img_elf_sect_hdr_32* sect_32; /* The section header entries (32 bits). */ + struct boot_img_elf_misc_hdr* misc; /* Miscellaneous information found in some ELF versions. */ + uint8_t elf_architecture; uint8_t elf_version; uint8_t elf_out_format; uint32_t cmdline_size; @@ -129,7 +154,7 @@ struct boot_img_elf_info uint32_t cmdline_signature_cnt; }; -struct boot_img_elf_prog_hdr +struct boot_img_elf_prog_hdr_32 { uint32_t type; /* type (position + 0x0 to 0x3) */ uint32_t offset; /* offset (position + 0x4 to 0x7) */ @@ -141,7 +166,19 @@ struct boot_img_elf_prog_hdr uint32_t align; /* alignment (position + 0x1C to 0x1F)*/ }; -struct boot_img_elf_sect_hdr +struct __attribute__((packed)) boot_img_elf_prog_hdr +{ + uint64_t type; /* type (position + 0x0 to 0x3) */ + uint64_t offset; /* offset (position + 0x4 to 0x7) */ + uint64_t vaddr; /* address (position + 0x8 to 0xF) */ + uint64_t paddr; /* address duplicate (position + 0x10 to 0x17) */ + uint64_t size; /* size (position + 0x18 to 0x1F) */ + uint64_t msize; /* size duplicate (position + 0x20 to 0x23) */ + uint32_t flags; /* flags (position + 0x24 to 0x27) */ + uint32_t align; /* alignment (position + 0x28 to 0x2B)*/ +}; + +struct boot_img_elf_sect_hdr_32 { uint32_t name; uint32_t type; @@ -152,6 +189,18 @@ struct boot_img_elf_sect_hdr uint8_t misc[16]; }; +struct __attribute__((packed)) boot_img_elf_sect_hdr +{ + uint32_t name; + uint64_t type; + uint32_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint8_t misc[16]; + uint8_t padding[8]; +}; + struct boot_img_elf_misc_hdr { uint8_t* data; /* header additional data */ diff --git a/include/libbootimg.h b/include/libbootimg.h index fa803e4..4b6d51e 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -139,6 +139,15 @@ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); */ void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info); +/** + * Reads the image header from the given ELF file and adds the content + * to the given structure, adapting 32 bits to 64 bits if needed. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_header(struct boot_img_elf_info *hdr_info, FILE *f); + /** * Reads the program headers from the given ELF file and adds the content * of each header to the given structure. diff --git a/src/libbootimg.c b/src/libbootimg.c index 1c89e17..6ba5120 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -246,8 +247,8 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, else if (hdr_info != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, BOOT_MAGIC_ELF_SIZE) == 0) { - fseek(f, 0, SEEK_SET); - if (fread(&hdr_info->hdr, sizeof(struct boot_img_elf_hdr), 1, f) == 1) + res = libbootimg_load_elf_header(hdr_info, f); + if (res == 1) { hdr->id[0] = '\0'; @@ -323,7 +324,8 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, } memcpy(hdr->name, hdr_info->misc->name, BOOT_NAME_SIZE); } - else if (hdr_info->elf_version == VER_ELF_2) + else if (hdr_info->elf_version == VER_ELF_2 || + hdr_info->elf_version == VER_ELF_4) { res = libbootimg_load_elf_sect_header(hdr_info, f); if (res != 1) @@ -352,22 +354,76 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info) { - switch (hdr_info->hdr.phnum) + if (hdr_info->elf_architecture == ARCH_64_BITS) { - case 3: - // Version 2 (found in Z2, 8960) has 3 program headers + 1 section header - hdr_info->elf_version = VER_ELF_2; - // Also the bootloader does not load modified elf images - // Output to standard Android container format - hdr_info->elf_out_format = OUT_AND; - break; - case 4: - default: - // Version 1 (found in SP, 8960) has 4 program headers - hdr_info->elf_version = VER_ELF_1; - hdr_info->elf_out_format = OUT_ELF; - break; + // Version 4 (found in XP, 8996) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_4; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + } + else + { + switch (hdr_info->hdr.phnum) + { + case 3: + // Version 2 (found in Z2, 8960) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_2; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + break; + case 4: + case 5: + default: + // Version 1 (found in SP, 8960) has 4 program headers + hdr_info->elf_version = VER_ELF_1; + hdr_info->elf_out_format = OUT_ELF; + break; + } + } +} + +int libbootimg_load_elf_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + + fseek(f, 0, SEEK_SET); + hdr_info->elf_architecture = libbootimg_architecture(); + + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + LOG_DBG("Reading elf header (64bits).\n"); + res = fread(&hdr_info->hdr, sizeof(struct boot_img_elf_hdr), 1, f); + } + else + { + LOG_DBG("Reading elf header (32bits).\n"); + res = fread(&hdr_info->hdr_32, sizeof(struct boot_img_elf_hdr_32), + 1, f); + if (res == 1) + { + memcpy(hdr_info->hdr.magic, hdr_info->hdr_32.magic, + 8 * sizeof(uint8_t)); + memcpy(hdr_info->hdr.unused, hdr_info->hdr_32.unused, + 8 * sizeof(uint8_t)); + hdr_info->hdr.type = hdr_info->hdr_32.type; + hdr_info->hdr.machine = hdr_info->hdr_32.machine; + hdr_info->hdr.version = hdr_info->hdr_32.version; + hdr_info->hdr.entry_addr = (uint64_t) hdr_info->hdr_32.entry_addr; + hdr_info->hdr.phoff = (uint64_t) hdr_info->hdr_32.phoff; + hdr_info->hdr.shoff = (uint64_t) hdr_info->hdr_32.shoff; + hdr_info->hdr.flags = hdr_info->hdr_32.flags; + hdr_info->hdr.ehsize = hdr_info->hdr_32.ehsize; + hdr_info->hdr.phentsize = hdr_info->hdr_32.phentsize; + hdr_info->hdr.phnum = hdr_info->hdr_32.phnum; + hdr_info->hdr.shentsize = hdr_info->hdr_32.shentsize; + hdr_info->hdr.shnum = hdr_info->hdr_32.shnum; + hdr_info->hdr.shstrndx = hdr_info->hdr_32.shstrndx; + } } + + return res; } int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) @@ -381,19 +437,74 @@ int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) int prog_entry_idx = 0; for (; prog_entry_idx < hdr_info->hdr.phnum; ++prog_entry_idx) { - LOG_DBG("Reading program header %u/%u.\n", - prog_entry_idx + 1, hdr_info->hdr.phnum); - res = fread(&prog_entry[prog_entry_idx], prog_entry_size, 1, f); - if (res == 1) + if (hdr_info->elf_architecture == ARCH_64_BITS) { - LOG_DBG("Program header %u/%u successfully read.\n", + LOG_DBG("Reading program header %u/%u (64bits).\n", prog_entry_idx + 1, hdr_info->hdr.phnum); - print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); + + if (prog_entry_size != hdr_info->hdr.phentsize) + { + LOG_DBG("Program header %u/%u [%u != %u] mismatch.\n", + prog_entry_idx + 1, hdr_info->hdr.phnum, + prog_entry_size, hdr_info->hdr.phentsize); + free(prog_entry); + return 0; + } + + res = fread(&prog_entry[prog_entry_idx], + hdr_info->hdr.phentsize, 1, f); } else { - LOG_DBG("Program header %u/%u read failed.\n", + LOG_DBG("Reading program header %u/%u (32bits).\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + + int prog_entry_size_32 = sizeof(struct boot_img_elf_prog_hdr_32); + struct boot_img_elf_prog_hdr_32 *prog_entry_32; + prog_entry_32 = malloc(prog_entry_size * hdr_info->hdr_32.phnum); + hdr_info->prog_32 = prog_entry_32; + + if (prog_entry_size_32 != hdr_info->hdr_32.phentsize) + { + LOG_DBG("Program header %u/%u [%u != %u] mismatch.\n", + prog_entry_idx + 1, hdr_info->hdr_32.phnum, + prog_entry_size_32, hdr_info->hdr_32.phentsize); + free(prog_entry_32); + free(prog_entry); + return 0; + } + + res = fread(&prog_entry_32[prog_entry_idx], + hdr_info->hdr_32.phentsize, 1, f); + if (res == 1) + { + prog_entry[prog_entry_idx].type = + (uint64_t) prog_entry_32[prog_entry_idx].type; + prog_entry[prog_entry_idx].offset = + (uint64_t) prog_entry_32[prog_entry_idx].offset; + prog_entry[prog_entry_idx].vaddr = + (uint64_t) prog_entry_32[prog_entry_idx].vaddr; + prog_entry[prog_entry_idx].paddr = + (uint64_t) prog_entry_32[prog_entry_idx].paddr; + prog_entry[prog_entry_idx].size = + (uint64_t) prog_entry_32[prog_entry_idx].size; + prog_entry[prog_entry_idx].msize = + (uint64_t) prog_entry_32[prog_entry_idx].msize; + prog_entry[prog_entry_idx].flags = + prog_entry_32[prog_entry_idx].flags; + prog_entry[prog_entry_idx].align = + prog_entry_32[prog_entry_idx].align; + } + } + + if (res == 1) + { + LOG_DBG("Program header %u/%u successfully read.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); + } + else + { + LOG_DBG("Program header %u/%u read failed.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); break; } } @@ -407,14 +518,70 @@ int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f) struct boot_img_elf_sect_hdr *sect_entry; fseek(f, hdr_info->hdr.shoff, SEEK_SET); - sect_entry = malloc(hdr_info->hdr.shentsize * hdr_info->hdr.shnum); + sect_entry = malloc(sect_entry_size * hdr_info->hdr.shnum); hdr_info->sect = sect_entry; int sect_entry_idx = 0; for (; sect_entry_idx < hdr_info->hdr.shnum; ++sect_entry_idx) { - LOG_DBG("Reading section header %u/%u.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); - res = fread(§_entry[sect_entry_idx], sect_entry_size, 1, f); + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + LOG_DBG("Reading section header %u/%u (64bits).\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + + if (sect_entry_size != hdr_info->hdr.shentsize) + { + LOG_DBG("Section header %u/%u [%u != %u] mismatch.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum, + sect_entry_size, hdr_info->hdr.shentsize); + free(sect_entry); + return 0; + } + + res = fread(§_entry[sect_entry_idx], + hdr_info->hdr.shentsize, 1, f); + } + else + { + LOG_DBG("Reading section header %u/%u (32bits).\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + + int sect_entry_size_32 = sizeof(struct boot_img_elf_sect_hdr_32); + struct boot_img_elf_sect_hdr_32 *sect_entry_32; + sect_entry_32 = malloc(hdr_info->hdr.shentsize * hdr_info->hdr.shnum); + hdr_info->sect_32 = sect_entry_32; + + if (sect_entry_size_32 != hdr_info->hdr_32.shentsize) + { + LOG_DBG("Section header %u/%u [%u != %u] mismatch.\n", + sect_entry_idx + 1, hdr_info->hdr_32.shnum, + sect_entry_size_32, hdr_info->hdr_32.shentsize); + free(sect_entry_32); + free(sect_entry); + return 0; + } + + res = fread(§_entry_32[sect_entry_idx], + hdr_info->hdr_32.shentsize, 1, f); + if (res == 1) + { + sect_entry[sect_entry_idx].name = + sect_entry_32[sect_entry_idx].name; + sect_entry[sect_entry_idx].type = + (uint64_t) sect_entry_32[sect_entry_idx].type; + sect_entry[sect_entry_idx].flags = + sect_entry_32[sect_entry_idx].flags; + sect_entry[sect_entry_idx].addr = + (uint64_t) sect_entry_32[sect_entry_idx].addr; + sect_entry[sect_entry_idx].offset = + (uint64_t) sect_entry_32[sect_entry_idx].offset; + sect_entry[sect_entry_idx].size = + sect_entry_32[sect_entry_idx].size; + memcpy(sect_entry[sect_entry_idx].misc, + sect_entry_32[sect_entry_idx].misc, + 16 * sizeof(uint8_t)); + } + } if (res == 1) { @@ -477,7 +644,8 @@ void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info cmdline_start_pos = elf_info->prog[ELF_PROG_CMD].offset; elf_info->cmdline_size = elf_info->prog[ELF_PROG_CMD].size; } - else if (elf_info->elf_version == VER_ELF_2) + else if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) { cmdline_start_pos = elf_info->sect[ELF_SECT_CMD].offset; elf_info->cmdline_size = elf_info->sect[ELF_SECT_CMD].size; @@ -493,7 +661,8 @@ void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info fseek(f, cmdline_start_pos, SEEK_SET); int buf_idx; - if (elf_info->elf_version == VER_ELF_2) + if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) { elf_info->cmdline_metadata_cnt = 8; if (fread(elf_info->cmdline_metadata, 8, 1, f) != 1) @@ -544,7 +713,8 @@ struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_ } break; case LIBBOOTIMG_BLOB_DTB: - if (elf_info->elf_version == VER_ELF_2) + if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) { return &elf_info->prog[ELF_PROG_RPM]; } @@ -625,6 +795,78 @@ int libbootimg_update_headers(struct bootimg *b) b->hdr_info->hdr.shoff = addr; } + // Update 32 bits structures + if (b->hdr_info->elf_architecture != ARCH_64_BITS) + { + // Update boot_img_elf_hdr_32 + memcpy(b->hdr_info->hdr_32.magic, b->hdr_info->hdr.magic, + 8 * sizeof(uint8_t)); + memcpy(b->hdr_info->hdr_32.unused, b->hdr_info->hdr.unused, + 8 * sizeof(uint8_t)); + b->hdr_info->hdr_32.type = b->hdr_info->hdr.type; + b->hdr_info->hdr_32.machine = b->hdr_info->hdr.machine; + b->hdr_info->hdr_32.version = b->hdr_info->hdr.version; + b->hdr_info->hdr_32.entry_addr = + (uint32_t) b->hdr_info->hdr.entry_addr; + b->hdr_info->hdr_32.phoff = + (uint32_t) b->hdr_info->hdr.phoff; + b->hdr_info->hdr_32.shoff = + (uint32_t) b->hdr_info->hdr.shoff; + b->hdr_info->hdr_32.flags = b->hdr_info->hdr.flags; + b->hdr_info->hdr_32.ehsize = b->hdr_info->hdr.ehsize; + b->hdr_info->hdr_32.phentsize = b->hdr_info->hdr.phentsize; + b->hdr_info->hdr_32.phnum = b->hdr_info->hdr.phnum; + b->hdr_info->hdr_32.shentsize = b->hdr_info->hdr.shentsize; + b->hdr_info->hdr_32.shnum = b->hdr_info->hdr.shnum; + b->hdr_info->hdr_32.shstrndx = b->hdr_info->hdr.shstrndx; + + // Update boot_img_elf_prog_hdr_32 + int prog_entry_idx = 0; + for (; prog_entry_idx < b->hdr_info->hdr.phnum; ++prog_entry_idx) + { + LOG_DBG("Syncing program header 32bits entry %d/%d.\n", + prog_entry_idx + 1, b->hdr_info->hdr_32.phnum); + b->hdr_info->prog_32[prog_entry_idx].type = + (uint32_t) b->hdr_info->prog[prog_entry_idx].type; + b->hdr_info->prog_32[prog_entry_idx].offset = + (uint32_t) b->hdr_info->prog[prog_entry_idx].offset; + b->hdr_info->prog_32[prog_entry_idx].vaddr = + (uint32_t) b->hdr_info->prog[prog_entry_idx].vaddr; + b->hdr_info->prog_32[prog_entry_idx].paddr = + (uint32_t) b->hdr_info->prog[prog_entry_idx].paddr; + b->hdr_info->prog_32[prog_entry_idx].size = + (uint32_t) b->hdr_info->prog[prog_entry_idx].size; + b->hdr_info->prog_32[prog_entry_idx].msize = + (uint32_t) b->hdr_info->prog[prog_entry_idx].msize; + b->hdr_info->prog_32[prog_entry_idx].flags = + b->hdr_info->prog[prog_entry_idx].flags; + b->hdr_info->prog_32[prog_entry_idx].align = + b->hdr_info->prog[prog_entry_idx].align; + } + + // Update boot_img_elf_sect_hdr_32 + sect_entry_idx = 0; + for (; sect_entry_idx < b->hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Syncing section header 32bits entry %d/%d.\n", + sect_entry_idx + 1, b->hdr_info->hdr_32.shnum); + b->hdr_info->sect_32[sect_entry_idx].name = + b->hdr_info->sect[sect_entry_idx].name; + b->hdr_info->sect_32[sect_entry_idx].type = + (uint32_t) b->hdr_info->sect[sect_entry_idx].type; + b->hdr_info->sect_32[sect_entry_idx].flags = + b->hdr_info->sect[sect_entry_idx].flags; + b->hdr_info->sect_32[sect_entry_idx].addr = + (uint32_t) b->hdr_info->sect[sect_entry_idx].addr; + b->hdr_info->sect_32[sect_entry_idx].offset = + (uint32_t) b->hdr_info->sect[sect_entry_idx].offset; + b->hdr_info->sect_32[sect_entry_idx].size = + (uint32_t) b->hdr_info->sect[sect_entry_idx].size; + memcpy(b->hdr_info->sect_32[sect_entry_idx].misc, + b->hdr_info->sect[sect_entry_idx].misc, + 16 * sizeof(uint8_t)); + } + } } else if (b->is_elf && b->hdr_info->elf_out_format == OUT_AND) { @@ -812,7 +1054,16 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) } else if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - if (fwrite(&b->hdr_info->hdr, sizeof(b->hdr_info->hdr), 1, f) != 1) + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(&b->hdr_info->hdr, sizeof(b->hdr_info->hdr), 1, f); + } + else + { + res = fwrite(&b->hdr_info->hdr_32, sizeof(b->hdr_info->hdr_32), + 1, f); + } + if (res != 1) { goto fail_fwrite; } @@ -823,8 +1074,17 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) for (; hdr_entry_idx < num_prog_hdr; ++hdr_entry_idx) { print_elf_prog_hdr_to_log(&b->hdr_info->prog[hdr_entry_idx]); - if (fwrite(&b->hdr_info->prog[hdr_entry_idx], - b->hdr_info->hdr.phentsize, 1, f) == 1) + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(&b->hdr_info->prog[hdr_entry_idx], + b->hdr_info->hdr.phentsize, 1, f); + } + else + { + res = fwrite(&b->hdr_info->prog_32[hdr_entry_idx], + b->hdr_info->hdr_32.phentsize, 1, f); + } + if (res == 1) { LOG_DBG("Program header %u/%u writing successful.\n", hdr_entry_idx + 1, b->hdr_info->hdr.phnum); @@ -952,7 +1212,17 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) // Write the section header LOG_DBG("Writing section header.\n"); fseek(f, b->hdr_info->hdr.shoff, SEEK_SET); - if (fwrite(b->hdr_info->sect, b->hdr_info->hdr.shentsize, 1, f) == 1) + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(b->hdr_info->sect, + b->hdr_info->hdr.shentsize, 1, f); + } + else + { + res = fwrite(b->hdr_info->sect_32, + b->hdr_info->hdr_32.shentsize, 1, f); + } + if (res == 1) { print_elf_sect_hdr_to_log(&b->hdr_info->sect[ELF_SECT_CMD]); } @@ -1084,9 +1354,9 @@ void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) LOG_DBG("Type = %u\n", elf_info->hdr.type); LOG_DBG("Machine = %u\n", elf_info->hdr.machine); LOG_DBG("Version = %u\n", elf_info->hdr.version); - LOG_DBG("Entry Address = %x\n", elf_info->hdr.entry_addr); - LOG_DBG("Program Offset = %x\n", elf_info->hdr.phoff); - LOG_DBG("Section Offset = %x\n", elf_info->hdr.shoff); + LOG_DBG("Entry Address = %"PRIx64"\n", elf_info->hdr.entry_addr); + LOG_DBG("Program Offset = %"PRIx64"\n", elf_info->hdr.phoff); + LOG_DBG("Section Offset = %"PRIx64"\n", elf_info->hdr.shoff); LOG_DBG("Flags = %x\n", elf_info->hdr.flags); LOG_DBG("Ehsize = %u\n", elf_info->hdr.ehsize); LOG_DBG("Program headers size = %u\n", elf_info->hdr.phentsize); @@ -1101,12 +1371,12 @@ void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr) { (void)elf_prog_hdr; LOG_DBG("===== ELF program header content =====\n"); - LOG_DBG("Type = %x\n", elf_prog_hdr->type); - LOG_DBG("Offset = %x\n", elf_prog_hdr->offset); - LOG_DBG("VAddr = %x\n", elf_prog_hdr->vaddr); - LOG_DBG("PAddr = %x\n", elf_prog_hdr->paddr); - LOG_DBG("Size = %u\n", elf_prog_hdr->size); - LOG_DBG("MSize = %u\n", elf_prog_hdr->msize); + LOG_DBG("Type = %"PRIx64"\n", elf_prog_hdr->type); + LOG_DBG("Offset = %"PRIx64"\n", elf_prog_hdr->offset); + LOG_DBG("VAddr = %"PRIx64"\n", elf_prog_hdr->vaddr); + LOG_DBG("PAddr = %"PRIx64"\n", elf_prog_hdr->paddr); + LOG_DBG("Size = %"PRIu64"\n", elf_prog_hdr->size); + LOG_DBG("MSize = %"PRIu64"\n", elf_prog_hdr->msize); LOG_DBG("Flags = %x\n", elf_prog_hdr->flags); LOG_DBG("Align = %x\n", elf_prog_hdr->align); LOG_DBG("======================================\n"); @@ -1117,11 +1387,11 @@ void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr) (void)elf_sect_hdr; LOG_DBG("===== ELF section header content =====\n"); LOG_DBG("Name = %x\n", elf_sect_hdr->name); - LOG_DBG("Type = %x\n", elf_sect_hdr->type); + LOG_DBG("Type = %"PRIx64"\n", elf_sect_hdr->type); LOG_DBG("Flags = %x\n", elf_sect_hdr->flags); - LOG_DBG("Address = %x\n", elf_sect_hdr->addr); - LOG_DBG("Offset = %x\n", elf_sect_hdr->offset); - LOG_DBG("Size = %u\n", elf_sect_hdr->size); + LOG_DBG("Address = %"PRIx64"\n", elf_sect_hdr->addr); + LOG_DBG("Offset = %"PRIx64"\n", elf_sect_hdr->offset); + LOG_DBG("Size = %"PRIu64"\n", elf_sect_hdr->size); LOG_DBG("======================================\n"); } From 056a34a04bc824de484fc7ad82901c67b825c826 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Sun, 11 Jun 2017 20:00:54 +0200 Subject: [PATCH 09/10] bbootimg: Present an hexadecimal dump of the bootimage name * Allows seeing hidden chars as hexadecimal values Change-Id: Ie35813f75d59596d484f9aab0bc659dcf3ea8ffe --- src/bbootimg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bbootimg.c b/src/bbootimg.c index 188e6ea..4bc6fdf 100644 --- a/src/bbootimg.c +++ b/src/bbootimg.c @@ -294,7 +294,12 @@ static int print_info(const char *path) printf ("* image size = %ld bytes (%.2f MB)\n", size, (double)size/0x100000); printf (" page size = %u bytes\n\n", img.hdr.page_size); - printf ("* Boot Name = \"%s\"\n\n", name); + printf ("* Boot Name = \"%s\" [ ", name); + for (i = 0; i < BOOT_NAME_SIZE && name[i] != '\0'; ++i) + { + printf ("0x%02X ", name[i]); + } + printf ("]\n\n", name); printf ("* kernel size = %u bytes (%.2f MB)\n", img.hdr.kernel_size, (double)img.hdr.kernel_size/0x100000); printf (" ramdisk size = %u bytes (%.2f MB)\n", img.hdr.ramdisk_size, (double)img.hdr.ramdisk_size/0x100000); From 3523b0679e23187abfa1ae88195b90b7ea0733f8 Mon Sep 17 00:00:00 2001 From: Adrian DC Date: Mon, 25 Dec 2017 22:46:38 +0100 Subject: [PATCH 10/10] libbootimg_architecture: Use uname instead of /proc/cpuinfo * A new situation on the Sony X Performance has shown that the "Processor" field from cpuinfo can be missing, therefore breaking the 32 / 64bits detection * Instead, use the native uname handling to get the name of the host machine, allowing to detect aarch64/armv8 properly Change-Id: Ib7f1aa6303390b4cc64e402e7ee242a272ddf722 Signed-off-by: Adrian DC --- src/libbootimg.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/libbootimg.c b/src/libbootimg.c index 6ba5120..988ad0e 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -1258,25 +1258,11 @@ int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest) uint8_t libbootimg_architecture(void) { - FILE* cpuinfo; - char buffer[100]; + struct utsname sysinfo; + uname(&sysinfo); - memset(buffer, 0, sizeof(buffer)); - cpuinfo = fopen("/proc/cpuinfo", "rb"); - - if (cpuinfo == NULL) - { - return ARCH_32_BITS; - } - - if (fread(buffer, 1, sizeof(buffer), cpuinfo) == 0) - { - fclose(cpuinfo); - return ARCH_32_BITS; - } - fclose(cpuinfo); - - if (strstr(buffer, "aarch64")) { + if (strstr(sysinfo.machine, "aarch64") || + strstr(sysinfo.machine, "armv8")) { return ARCH_64_BITS; }