Segment memory mapped boot image region

This commit is contained in:
topjohnwu 2023-07-13 21:01:49 -07:00
parent 4caed73fe0
commit c97ab690b6
3 changed files with 83 additions and 64 deletions

View File

@ -211,7 +211,7 @@ class byte_channel;
struct heap_data : public byte_data { struct heap_data : public byte_data {
ALLOW_MOVE_ONLY(heap_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); } ~heap_data() { free(_buf); }
// byte_channel needs to reallocate the internal buffer // byte_channel needs to reallocate the internal buffer

View File

@ -169,8 +169,9 @@ boot_img::boot_img(const char *image) : map(image) {
break; break;
case AOSP: case AOSP:
case AOSP_VENDOR: case AOSP_VENDOR:
parse_image(addr, fmt); if (parse_image(addr, fmt))
return; return;
// fallthrough
default: default:
break; 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) #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<const uint8_t *, dyn_img_hdr *>
boot_img::create_hdr(const uint8_t *addr, format_t type) {
if (type == AOSP_VENDOR) { if (type == AOSP_VENDOR) {
fprintf(stderr, "VENDOR_BOOT_HDR\n"); fprintf(stderr, "VENDOR_BOOT_HDR\n");
auto h = reinterpret_cast<const boot_img_hdr_vnd_v3*>(addr); auto h = reinterpret_cast<const boot_img_hdr_vnd_v3*>(addr);
hdr_addr = addr;
switch (h->header_version) { switch (h->header_version) {
case 4: case 4:
return new dyn_img_vnd_v4(addr); return make_pair(addr, new dyn_img_vnd_v4(addr));
default: 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) { if (h->page_size >= 0x02000000) {
fprintf(stderr, "PXA_BOOT_HDR\n"); fprintf(stderr, "PXA_BOOT_HDR\n");
hdr_addr = addr; return make_pair(addr, new dyn_img_pxa(addr));
return new dyn_img_pxa(addr);
} }
auto make_hdr = [](const uint8_t *ptr) -> dyn_img_hdr * { auto make_hdr = [](const uint8_t *ptr) -> dyn_img_hdr * {
auto h = reinterpret_cast<const boot_img_hdr_v0*>(ptr); auto h = reinterpret_cast<const boot_img_hdr_v0*>(ptr);
if (memcmp(h->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0)
return nullptr;
switch (h->header_version) { switch (h->header_version) {
case 1: case 1:
return new dyn_img_v1(ptr); 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 // The real header is shifted, copy to temporary buffer
h = reinterpret_cast<const boot_img_hdr_v0*>(addr + AMONET_MICROLOADER_SZ); h = reinterpret_cast<const boot_img_hdr_v0*>(addr + AMONET_MICROLOADER_SZ);
auto real_hdr_sz = h->page_size - AMONET_MICROLOADER_SZ; if (memcmp(h->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0)
auto buf = make_unique<uint8_t[]>(h->page_size); return make_pair(addr, nullptr);
memcpy(buf.get(), h, real_hdr_sz);
hdr_addr = addr; auto real_hdr_sz = h->page_size - AMONET_MICROLOADER_SZ;
return make_hdr(buf.get()); 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) || 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 // addr could be adjusted
hdr_addr = addr; return make_pair(addr, make_hdr(addr));
return 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) \ #define get_block(name) \
name = hdr_addr + off; \ name = base_addr + off; \
off += hdr->name##_size(); \ off += hdr->name##_size(); \
off = align_to(off, hdr->page_size()); off = align_to(off, hdr->page_size()); \
assert_off();
#define get_ignore(name) \ #define get_ignore(name) \
if (hdr->name##_size()) { \ if (hdr->name##_size()) { \
auto blk_sz = align_to(hdr->name##_size(), hdr->page_size()); \ auto blk_sz = align_to(hdr->name##_size(), hdr->page_size()); \
ignore_size += blk_sz; \
off += blk_sz; \ off += blk_sz; \
} \
assert_off();
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;
} }
void boot_img::parse_image(const uint8_t *addr, format_t type) { if (const char *id = hdr->id()) {
auto hdr = create_hdr(addr, type);
if (char *id = hdr->id()) {
for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) { for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) {
if (id[i]) { if (id[i]) {
flags[SHA256_FLAG] = true; 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(recovery_dtbo);
get_block(dtb); get_block(dtb);
ignore = hdr_addr + off; auto ignore_addr = base_addr + off;
get_ignore(signature) get_ignore(signature)
get_ignore(vendor_ramdisk_table) get_ignore(vendor_ramdisk_table)
get_ignore(bootconfig) 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 (auto size = hdr->kernel_size()) {
if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) { if (int dtb_off = find_dtb_offset(kernel, size); dtb_off > 0) {
kernel_dtb = kernel + dtb_off; kernel_dtb = byte_view(kernel + dtb_off, size - dtb_off);
hdr->kernel_dt_size = size - dtb_off;
hdr->kernel_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()); 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) { if (k_fmt == ZIMAGE) {
z_hdr = reinterpret_cast<const zimage_hdr *>(kernel); z_hdr = reinterpret_cast<const zimage_hdr *>(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"); 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 // Find end of piggy
uint32_t zImage_size = z_hdr->end - z_hdr->start; 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"); fprintf(stderr, "! Could not find end of zImage piggy, keeping raw kernel\n");
} else { } else {
flags[ZIMAGE_KERNEL] = true; flags[ZIMAGE_KERNEL] = true;
z_info.tail = kernel + piggy_end; z_info.tail = byte_view(kernel + piggy_end, hdr->kernel_size() - piggy_end);
z_info.tail_sz = hdr->kernel_size() - piggy_end;
kernel += z_info.hdr_sz; kernel += z_info.hdr_sz;
hdr->kernel_size() = piggy_end - z_info.hdr_sz; hdr->kernel_size() = piggy_end - z_info.hdr_sz;
k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); 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]); fprintf(stderr, "%-*s [%s]\n", PADDING, "EXTRA_FMT", fmt2name[e_fmt]);
} }
if (addr + off < map.buf() + map.sz()) { if (tail.sz()) {
tail = addr + off;
tail_size = map.buf() + map.sz() - tail;
// Check special flags // 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"); fprintf(stderr, "SAMSUNG_SEANDROID\n");
flags[SEANDROID_FLAG] = true; 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"); fprintf(stderr, "LG_BUMP_IMAGE\n");
flags[LG_BUMP_FLAG] = true; flags[LG_BUMP_FLAG] = true;
} }
// Find AVB footer // 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)) { if (BUFFER_MATCH(footer, AVB_FOOTER_MAGIC)) {
avb_footer = reinterpret_cast<const AvbFooter*>(footer); avb_footer = reinterpret_cast<const AvbFooter*>(footer);
// Double check if meta header exists // 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)) { if (BUFFER_MATCH(meta, AVB_MAGIC)) {
fprintf(stderr, "VBMETA\n"); fprintf(stderr, "VBMETA\n");
flags[AVB_FLAG] = true; flags[AVB_FLAG] = true;
@ -450,6 +466,7 @@ void boot_img::parse_image(const uint8_t *addr, format_t type) {
} }
this->hdr = hdr; this->hdr = hdr;
return true;
} }
int split_image_dtb(const char *filename) { 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 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 // Dump ramdisk
if (!skip_decomp && COMPRESSED(boot.r_fmt)) { 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->ramdisk_size() = 0;
hdr->second_size() = 0; hdr->second_size() = 0;
hdr->dtb_size() = 0; hdr->dtb_size() = 0;
hdr->kernel_dt_size = 0;
if (access(HEADER_FILE, R_OK) == 0) if (access(HEADER_FILE, R_OK) == 0)
hdr->load_hdr_file(); hdr->load_hdr_file();
@ -577,7 +593,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
// Copy raw header // Copy raw header
off.header = lseek(fd, 0, SEEK_CUR); off.header = lseek(fd, 0, SEEK_CUR);
xwrite(fd, boot.hdr_addr, hdr->hdr_space()); xwrite(fd, boot.payload.buf(), hdr->hdr_space());
// kernel // kernel
off.kernel = lseek(fd, 0, SEEK_CUR); 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]) { if (boot.flags[ZIMAGE_KERNEL]) {
// Copy zImage tail and adjust size accordingly // Copy zImage tail and adjust size accordingly
hdr->kernel_size() += boot.z_info.hdr_sz; 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 // kernel dtb
@ -688,9 +704,9 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
} }
// Directly copy ignored blobs // Directly copy ignored blobs
if (boot.ignore_size) { if (boot.ignore.sz()) {
// ignore_size should already be aligned // ignore.sz() should already be aligned
xwrite(fd, boot.ignore, boot.ignore_size); xwrite(fd, boot.ignore.buf(), boot.ignore.sz());
} }
// Proprietary stuffs // Proprietary stuffs

View File

@ -365,7 +365,6 @@ struct dyn_img_hdr {
decl_str(cmdline) decl_str(cmdline)
decl_str(id) decl_str(id)
decl_str(extra_cmdline) decl_str(extra_cmdline)
uint32_t kernel_dt_size = 0;
// v1/v2 specific // v1/v2 specific
decl_var(recovery_dtbo_size, 32) decl_var(recovery_dtbo_size, 32)
@ -425,7 +424,6 @@ size_t hdr_size() const override { \
} \ } \
dyn_img_hdr *clone() const override { \ dyn_img_hdr *clone() const override { \
auto p = new name(raw); \ auto p = new name(raw); \
p->kernel_dt_size = kernel_dt_size; \
return p; \ return p; \
}; };
@ -604,6 +602,18 @@ struct boot_img {
* Following pointers points within the read-only mmap region * 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 // MTK headers
const mtk_hdr *k_hdr; const mtk_hdr *k_hdr;
const mtk_hdr *r_hdr; const mtk_hdr *r_hdr;
@ -614,28 +624,19 @@ struct boot_img {
// +---------------+ // +---------------+
// | kernel | hdr->kernel_size() // | kernel | hdr->kernel_size()
// +---------------+ // +---------------+
// | z_info.tail | z_info.tail_sz // | z_info.tail | z_info.tail.sz()
// +---------------+ // +---------------+
const zimage_hdr *z_hdr; const zimage_hdr *z_hdr;
struct { struct {
uint32_t hdr_sz; uint32_t hdr_sz;
uint32_t tail_sz = 0; byte_view tail;
const uint8_t *tail = nullptr;
} z_info; } 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 // AVB structs
const AvbFooter *avb_footer; const AvbFooter *avb_footer;
const AvbVBMetaImageHeader *vbmeta; const AvbVBMetaImageHeader *vbmeta;
// Pointers to blocks defined in header // Pointers to blocks defined in header
const uint8_t *hdr_addr;
const uint8_t *kernel; const uint8_t *kernel;
const uint8_t *ramdisk; const uint8_t *ramdisk;
const uint8_t *second; const uint8_t *second;
@ -643,13 +644,15 @@ struct boot_img {
const uint8_t *recovery_dtbo; const uint8_t *recovery_dtbo;
const uint8_t *dtb; const uint8_t *dtb;
// Pointer to blocks defined in header, but we do not care // dtb embedded in kernel
const uint8_t *ignore; byte_view kernel_dtb;
size_t ignore_size = 0;
// Blocks defined in header but we do not care
byte_view ignore;
boot_img(const char *); boot_img(const char *);
~boot_img(); ~boot_img();
void parse_image(const uint8_t *addr, format_t type); bool parse_image(const uint8_t *addr, format_t type);
dyn_img_hdr *create_hdr(const uint8_t *addr, format_t type); const std::pair<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, format_t type);
}; };