From c97ab690b6b17c67dea62b66a316383c2ab2c22b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 13 Jul 2023 21:01:49 -0700 Subject: [PATCH] Segment memory mapped boot image region --- native/src/base/misc.hpp | 2 +- native/src/boot/bootimg.cpp | 106 +++++++++++++++++++++--------------- native/src/boot/bootimg.hpp | 39 +++++++------ 3 files changed, 83 insertions(+), 64 deletions(-) diff --git a/native/src/base/misc.hpp b/native/src/base/misc.hpp index 8374cedad..eb0739c9f 100644 --- a/native/src/base/misc.hpp +++ b/native/src/base/misc.hpp @@ -211,7 +211,7 @@ class byte_channel; struct heap_data : public byte_data { ALLOW_MOVE_ONLY(heap_data) - explicit heap_data(size_t sz) : byte_data(malloc(sz), sz) {} + explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {} ~heap_data() { free(_buf); } // byte_channel needs to reallocate the internal buffer diff --git a/native/src/boot/bootimg.cpp b/native/src/boot/bootimg.cpp index d87b08581..47df7bfa4 100644 --- a/native/src/boot/bootimg.cpp +++ b/native/src/boot/bootimg.cpp @@ -169,8 +169,9 @@ boot_img::boot_img(const char *image) : map(image) { break; case AOSP: case AOSP_VENDOR: - parse_image(addr, fmt); - return; + if (parse_image(addr, fmt)) + return; + // fallthrough default: break; } @@ -231,16 +232,16 @@ static format_t check_fmt_lg(const uint8_t *buf, unsigned sz) { #define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s) -dyn_img_hdr *boot_img::create_hdr(const uint8_t *addr, format_t type) { +const pair + boot_img::create_hdr(const uint8_t *addr, format_t type) { if (type == AOSP_VENDOR) { fprintf(stderr, "VENDOR_BOOT_HDR\n"); auto h = reinterpret_cast(addr); - hdr_addr = addr; switch (h->header_version) { case 4: - return new dyn_img_vnd_v4(addr); + return make_pair(addr, new dyn_img_vnd_v4(addr)); default: - return new dyn_img_vnd_v3(addr); + return make_pair(addr, new dyn_img_vnd_v3(addr)); } } @@ -248,12 +249,14 @@ dyn_img_hdr *boot_img::create_hdr(const uint8_t *addr, format_t type) { if (h->page_size >= 0x02000000) { fprintf(stderr, "PXA_BOOT_HDR\n"); - hdr_addr = addr; - return new dyn_img_pxa(addr); + return make_pair(addr, new dyn_img_pxa(addr)); } auto make_hdr = [](const uint8_t *ptr) -> dyn_img_hdr * { auto h = reinterpret_cast(ptr); + if (memcmp(h->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) + return nullptr; + switch (h->header_version) { case 1: return new dyn_img_v1(ptr); @@ -278,12 +281,14 @@ dyn_img_hdr *boot_img::create_hdr(const uint8_t *addr, format_t type) { // The real header is shifted, copy to temporary buffer h = reinterpret_cast(addr + AMONET_MICROLOADER_SZ); - auto real_hdr_sz = h->page_size - AMONET_MICROLOADER_SZ; - auto buf = make_unique(h->page_size); - memcpy(buf.get(), h, real_hdr_sz); + if (memcmp(h->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) + return make_pair(addr, nullptr); - hdr_addr = addr; - return make_hdr(buf.get()); + auto real_hdr_sz = h->page_size - AMONET_MICROLOADER_SZ; + heap_data copy(h->page_size); + memcpy(copy.buf(), h, real_hdr_sz); + + return make_pair(addr, make_hdr(copy.buf())); } if (CMD_MATCH(NOOKHD_RL_MAGIC) || @@ -301,26 +306,37 @@ dyn_img_hdr *boot_img::create_hdr(const uint8_t *addr, format_t type) { } // addr could be adjusted - hdr_addr = addr; - return make_hdr(addr); + return make_pair(addr, make_hdr(addr)); +} + +#define assert_off() \ +if ((base_addr + off) > (map.buf() + map.sz())) { \ + fprintf(stderr, "Corrupted boot image!\n"); \ + return false; \ } #define get_block(name) \ -name = hdr_addr + off; \ +name = base_addr + off; \ off += hdr->name##_size(); \ -off = align_to(off, hdr->page_size()); +off = align_to(off, hdr->page_size()); \ +assert_off(); #define get_ignore(name) \ if (hdr->name##_size()) { \ auto blk_sz = align_to(hdr->name##_size(), hdr->page_size()); \ - ignore_size += blk_sz; \ off += blk_sz; \ -} +} \ +assert_off(); -void boot_img::parse_image(const uint8_t *addr, format_t type) { - auto hdr = create_hdr(addr, type); - if (char *id = hdr->id()) { +bool boot_img::parse_image(const uint8_t *p, format_t type) { + auto [base_addr, hdr] = create_hdr(p, type); + if (hdr == nullptr) { + fprintf(stderr, "Invalid boot image header!\n"); + return false; + } + + if (const char *id = hdr->id()) { for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) { if (id[i]) { flags[SHA256_FLAG] = true; @@ -339,17 +355,21 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) { get_block(recovery_dtbo); get_block(dtb); - ignore = hdr_addr + off; + auto ignore_addr = base_addr + off; get_ignore(signature) get_ignore(vendor_ramdisk_table) get_ignore(bootconfig) + payload = byte_view(base_addr, off); + auto tail_addr = base_addr + off; + ignore = byte_view(ignore_addr, tail_addr - ignore_addr); + tail = byte_view(tail_addr, map.buf() + map.sz() - tail_addr); + if (auto size = hdr->kernel_size()) { if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) { - kernel_dtb = kernel + dtb_off; - hdr->kernel_dt_size = size - dtb_off; + kernel_dtb = byte_view(kernel + dtb_off, size - dtb_off); hdr->kernel_size() = dtb_off; - fprintf(stderr, "%-*s [%u]\n", PADDING, "KERNEL_DTB_SZ", hdr->kernel_dt_size); + fprintf(stderr, "%-*s [%zu]\n", PADDING, "KERNEL_DTB_SZ", kernel_dtb.sz()); } k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); @@ -365,9 +385,9 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) { } if (k_fmt == ZIMAGE) { z_hdr = reinterpret_cast(kernel); - if (void *gzip_offset = memmem(kernel, hdr->kernel_size(), GZIP1_MAGIC "\x08\x00", 4)) { + if (const void *gzip = memmem(kernel, hdr->kernel_size(), GZIP1_MAGIC "\x08\x00", 4)) { fprintf(stderr, "ZIMAGE_KERNEL\n"); - z_info.hdr_sz = (uint8_t *) gzip_offset - kernel; + z_info.hdr_sz = (const uint8_t *) gzip - kernel; // Find end of piggy uint32_t zImage_size = z_hdr->end - z_hdr->start; @@ -385,8 +405,7 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) { fprintf(stderr, "! Could not find end of zImage piggy, keeping raw kernel\n"); } else { flags[ZIMAGE_KERNEL] = true; - z_info.tail = kernel + piggy_end; - z_info.tail_sz = hdr->kernel_size() - piggy_end; + z_info.tail = byte_view(kernel + piggy_end, hdr->kernel_size() - piggy_end); kernel += z_info.hdr_sz; hdr->kernel_size() = piggy_end - z_info.hdr_sz; k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); @@ -422,25 +441,22 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) { fprintf(stderr, "%-*s [%s]\n", PADDING, "EXTRA_FMT", fmt2name[e_fmt]); } - if (addr + off < map.buf() + map.sz()) { - tail = addr + off; - tail_size = map.buf() + map.sz() - tail; - + if (tail.sz()) { // Check special flags - if (tail_size >= 16 && BUFFER_MATCH(tail, SEANDROID_MAGIC)) { + if (tail.sz() >= 16 && BUFFER_MATCH(tail.buf(), SEANDROID_MAGIC)) { fprintf(stderr, "SAMSUNG_SEANDROID\n"); flags[SEANDROID_FLAG] = true; - } else if (tail_size >= 16 && BUFFER_MATCH(tail, LG_BUMP_MAGIC)) { + } else if (tail.sz() >= 16 && BUFFER_MATCH(tail.buf(), LG_BUMP_MAGIC)) { fprintf(stderr, "LG_BUMP_IMAGE\n"); flags[LG_BUMP_FLAG] = true; } // Find AVB footer - const void *footer = tail + tail_size - sizeof(AvbFooter); + const void *footer = tail.buf() + tail.sz() - sizeof(AvbFooter); if (BUFFER_MATCH(footer, AVB_FOOTER_MAGIC)) { avb_footer = reinterpret_cast(footer); // Double check if meta header exists - const void *meta = hdr_addr + __builtin_bswap64(avb_footer->vbmeta_offset); + const void *meta = base_addr + __builtin_bswap64(avb_footer->vbmeta_offset); if (BUFFER_MATCH(meta, AVB_MAGIC)) { fprintf(stderr, "VBMETA\n"); flags[AVB_FLAG] = true; @@ -450,6 +466,7 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) { } this->hdr = hdr; + return true; } int split_image_dtb(const char *filename) { @@ -490,7 +507,7 @@ int unpack(const char *image, bool skip_decomp, bool hdr) { } // Dump kernel_dtb - dump(boot.kernel_dtb, boot.hdr->kernel_dt_size, KER_DTB_FILE); + dump(boot.kernel_dtb.buf(), boot.kernel_dtb.sz(), KER_DTB_FILE); // Dump ramdisk if (!skip_decomp && COMPRESSED(boot.r_fmt)) { @@ -552,7 +569,6 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { hdr->ramdisk_size() = 0; hdr->second_size() = 0; hdr->dtb_size() = 0; - hdr->kernel_dt_size = 0; if (access(HEADER_FILE, R_OK) == 0) hdr->load_hdr_file(); @@ -577,7 +593,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { // Copy raw header off.header = lseek(fd, 0, SEEK_CUR); - xwrite(fd, boot.hdr_addr, hdr->hdr_space()); + xwrite(fd, boot.payload.buf(), hdr->hdr_space()); // kernel off.kernel = lseek(fd, 0, SEEK_CUR); @@ -622,7 +638,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { if (boot.flags[ZIMAGE_KERNEL]) { // Copy zImage tail and adjust size accordingly hdr->kernel_size() += boot.z_info.hdr_sz; - hdr->kernel_size() += xwrite(fd, boot.z_info.tail, boot.z_info.tail_sz); + hdr->kernel_size() += xwrite(fd, boot.z_info.tail.buf(), boot.z_info.tail.sz()); } // kernel dtb @@ -688,9 +704,9 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { } // Directly copy ignored blobs - if (boot.ignore_size) { - // ignore_size should already be aligned - xwrite(fd, boot.ignore, boot.ignore_size); + if (boot.ignore.sz()) { + // ignore.sz() should already be aligned + xwrite(fd, boot.ignore.buf(), boot.ignore.sz()); } // Proprietary stuffs diff --git a/native/src/boot/bootimg.hpp b/native/src/boot/bootimg.hpp index bdd423411..a8f982efa 100644 --- a/native/src/boot/bootimg.hpp +++ b/native/src/boot/bootimg.hpp @@ -365,7 +365,6 @@ struct dyn_img_hdr { decl_str(cmdline) decl_str(id) decl_str(extra_cmdline) - uint32_t kernel_dt_size = 0; // v1/v2 specific decl_var(recovery_dtbo_size, 32) @@ -425,7 +424,6 @@ size_t hdr_size() const override { \ } \ dyn_img_hdr *clone() const override { \ auto p = new name(raw); \ - p->kernel_dt_size = kernel_dt_size; \ return p; \ }; @@ -604,6 +602,18 @@ struct boot_img { * Following pointers points within the read-only mmap region *************************************************************/ + // Layout of the memory mapped region + // +---------+ + // | head | Vendor specific. Should be empty for standard AOSP boot images. + // +---------+ + // | payload | The actual boot image, including the AOSP boot image header. + // +---------+ + // | tail | Data after payload. Usually contains signature/AVB information. + // +---------+ + + byte_view payload; + byte_view tail; + // MTK headers const mtk_hdr *k_hdr; const mtk_hdr *r_hdr; @@ -614,28 +624,19 @@ struct boot_img { // +---------------+ // | kernel | hdr->kernel_size() // +---------------+ - // | z_info.tail | z_info.tail_sz + // | z_info.tail | z_info.tail.sz() // +---------------+ const zimage_hdr *z_hdr; struct { uint32_t hdr_sz; - uint32_t tail_sz = 0; - const uint8_t *tail = nullptr; + byte_view tail; } z_info; - // Pointer to dtb that is embedded in kernel - const uint8_t *kernel_dtb; - - // Pointer to end of image - const uint8_t *tail; - size_t tail_size = 0; - // AVB structs const AvbFooter *avb_footer; const AvbVBMetaImageHeader *vbmeta; // Pointers to blocks defined in header - const uint8_t *hdr_addr; const uint8_t *kernel; const uint8_t *ramdisk; const uint8_t *second; @@ -643,13 +644,15 @@ struct boot_img { const uint8_t *recovery_dtbo; const uint8_t *dtb; - // Pointer to blocks defined in header, but we do not care - const uint8_t *ignore; - size_t ignore_size = 0; + // dtb embedded in kernel + byte_view kernel_dtb; + + // Blocks defined in header but we do not care + byte_view ignore; boot_img(const char *); ~boot_img(); - void parse_image(const uint8_t *addr, format_t type); - dyn_img_hdr *create_hdr(const uint8_t *addr, format_t type); + bool parse_image(const uint8_t *addr, format_t type); + const std::pair create_hdr(const uint8_t *addr, format_t type); };