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 {
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

View File

@ -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<const uint8_t *, dyn_img_hdr *>
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<const boot_img_hdr_vnd_v3*>(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<const boot_img_hdr_v0*>(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<const boot_img_hdr_v0*>(addr + AMONET_MICROLOADER_SZ);
auto real_hdr_sz = h->page_size - AMONET_MICROLOADER_SZ;
auto buf = make_unique<uint8_t[]>(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<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");
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<const AvbFooter*>(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

View File

@ -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<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, format_t type);
};