Fix unpacking vendor boot images

This commit is contained in:
topjohnwu 2021-11-20 22:44:38 -08:00
parent 68ac409bfd
commit aebf2672cd
2 changed files with 84 additions and 78 deletions

View File

@ -235,64 +235,69 @@ static format_t check_fmt_lg(uint8_t *buf, unsigned sz) {
return fmt; return fmt;
} }
#define get_block(name) {\
name = addr + off; \
off += hdr->name##_size(); \
off = do_align(off, hdr->page_size()); \
}
#define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s) #define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s)
void boot_img::parse_image(uint8_t *addr, format_t type) { dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
auto h = reinterpret_cast<boot_img_hdr_v0*>(addr);
if (type == AOSP_VENDOR) { if (type == AOSP_VENDOR) {
fprintf(stderr, "VENDOR_BOOT_HDR\n"); fprintf(stderr, "VENDOR_BOOT_HDR\n");
auto h = reinterpret_cast<boot_img_hdr_vnd_v3*>(addr);
hdr_addr = addr;
switch (h->header_version) { switch (h->header_version) {
case 4: case 4:
hdr = new dyn_img_vnd_v4(addr); return new dyn_img_vnd_v4(addr);
break;
case 3:
default: default:
hdr = new dyn_img_vnd_v3(addr); return new dyn_img_vnd_v3(addr);
break;
}
} else if (h->page_size >= 0x02000000) {
fprintf(stderr, "PXA_BOOT_HDR\n");
hdr = new dyn_img_pxa(addr);
} else {
if (CMD_MATCH(NOOKHD_RL_MAGIC) ||
CMD_MATCH(NOOKHD_GL_MAGIC) ||
CMD_MATCH(NOOKHD_GR_MAGIC) ||
CMD_MATCH(NOOKHD_EB_MAGIC) ||
CMD_MATCH(NOOKHD_ER_MAGIC)) {
flags[NOOKHD_FLAG] = true;
fprintf(stderr, "NOOKHD_LOADER\n");
addr += NOOKHD_PRE_HEADER_SZ;
} else if (memcmp(h->name, ACCLAIM_MAGIC, 10) == 0) {
flags[ACCLAIM_FLAG] = true;
fprintf(stderr, "ACCLAIM_LOADER\n");
addr += ACCLAIM_PRE_HEADER_SZ;
}
switch (h->header_version) {
case 1:
hdr = new dyn_img_v1(addr);
break;
case 2:
hdr = new dyn_img_v2(addr);
break;
case 3:
hdr = new dyn_img_v3(addr);
break;
case 4:
hdr = new dyn_img_v4(addr);
break;
default:
hdr = new dyn_img_v0(addr);
break;
} }
} }
auto h = reinterpret_cast<boot_img_hdr_v0*>(addr);
if (h->page_size >= 0x02000000) {
fprintf(stderr, "PXA_BOOT_HDR\n");
hdr_addr = addr;
return new dyn_img_pxa(addr);
}
if (CMD_MATCH(NOOKHD_RL_MAGIC) ||
CMD_MATCH(NOOKHD_GL_MAGIC) ||
CMD_MATCH(NOOKHD_GR_MAGIC) ||
CMD_MATCH(NOOKHD_EB_MAGIC) ||
CMD_MATCH(NOOKHD_ER_MAGIC)) {
flags[NOOKHD_FLAG] = true;
fprintf(stderr, "NOOKHD_LOADER\n");
addr += NOOKHD_PRE_HEADER_SZ;
} else if (memcmp(h->name, ACCLAIM_MAGIC, 10) == 0) {
flags[ACCLAIM_FLAG] = true;
fprintf(stderr, "ACCLAIM_LOADER\n");
addr += ACCLAIM_PRE_HEADER_SZ;
}
// addr could be adjusted
h = reinterpret_cast<boot_img_hdr_v0*>(addr);
hdr_addr = addr;
switch (h->header_version) {
case 1:
return new dyn_img_v1(addr);
case 2:
return new dyn_img_v2(addr);
case 3:
return new dyn_img_v3(addr);
case 4:
return new dyn_img_v4(addr);
default:
return new dyn_img_v0(addr);
}
}
#define get_block(name) \
name = hdr_addr + off; \
off += hdr->name##_size(); \
off = do_align(off, hdr->page_size());
void boot_img::parse_image(uint8_t *addr, format_t type) {
hdr = create_hdr(addr, type);
if (char *id = hdr->id()) { 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]) {
@ -305,7 +310,6 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
hdr->print(); hdr->print();
size_t off = hdr->hdr_space(); size_t off = hdr->hdr_space();
hdr_addr = addr;
get_block(kernel); get_block(kernel);
get_block(ramdisk); get_block(ramdisk);
get_block(second); get_block(second);

View File

@ -151,7 +151,15 @@ struct boot_img_hdr_v0_common {
struct boot_img_hdr_v0 : public boot_img_hdr_v0_common { struct boot_img_hdr_v0 : public boot_img_hdr_v0_common {
uint32_t tags_addr; /* physical addr for kernel tags */ uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
// In AOSP headers, this field is used for page size.
// For Samsung PXA headers, the use of this field is unknown;
// however, its value is something unrealistic to be treated as page size.
// We use this fact to determine whether this is an AOSP or PXA header.
union {
uint32_t unknown;
uint32_t page_size; /* flash page size we assume */
};
// In header v1, this field is used for header version // In header v1, this field is used for header version
// However, on some devices like Samsung, this field is used to store DTB // However, on some devices like Samsung, this field is used to store DTB
@ -374,13 +382,10 @@ struct dyn_img_hdr {
protected: protected:
union { union {
// Main header could be either AOSP or PXA
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */ boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
boot_img_hdr_v4 *v4_hdr; /* AOSP v4 header */ boot_img_hdr_v4 *v4_hdr; /* AOSP v4 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
boot_img_hdr_vnd_v3 *v3_vnd; /* AOSP vendor v3 header */
boot_img_hdr_vnd_v4 *v4_vnd; /* AOSP vendor v4 header */ boot_img_hdr_vnd_v4 *v4_vnd; /* AOSP vendor v4 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
void *raw; /* Raw pointer */ void *raw; /* Raw pointer */
}; };
dyn_img_hdr(bool b) : is_vendor(b) {} dyn_img_hdr(bool b) : is_vendor(b) {}
@ -394,31 +399,33 @@ private:
#undef decl_var #undef decl_var
#undef decl_val #undef decl_val
#define __impl_cls(name, hdr) \ #define __impl_cls(name, hdr) \
protected: name() = default; \ protected: name() = default; \
public: \ public: \
name(void *ptr) { \ name(void *ptr) { \
raw = xmalloc(sizeof(hdr)); \ raw = xmalloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \ memcpy(raw, ptr, sizeof(hdr)); \
} \ } \
size_t hdr_size() override { return sizeof(hdr); } \ size_t hdr_size() override { \
dyn_img_hdr *clone() override { \ return sizeof(hdr); \
auto p = new name(this->raw); \ } \
dyn_img_hdr *clone() override { \
auto p = new name(raw); \
p->kernel_dt_size = kernel_dt_size; \ p->kernel_dt_size = kernel_dt_size; \
return p; \ return p; \
}; };
#define __impl_val(name, hdr_name) \ #define __impl_val(name, hdr_name) \
decltype(std::declval<dyn_img_hdr>().name()) name() override { return hdr_name->name; } decltype(std::declval<dyn_img_hdr>().name()) name() override { return hdr_name->name; }
#define impl_cls(ver) __impl_cls(dyn_img_##ver, boot_img_hdr_##ver)
#define impl_val(name) __impl_val(name, v2_hdr)
struct dyn_img_hdr_boot : public dyn_img_hdr { struct dyn_img_hdr_boot : public dyn_img_hdr {
protected: protected:
dyn_img_hdr_boot() : dyn_img_hdr(false) {} dyn_img_hdr_boot() : dyn_img_hdr(false) {}
}; };
#define impl_cls(ver) __impl_cls(dyn_img_##ver, boot_img_hdr_##ver)
#define impl_val(name) __impl_val(name, v2_hdr)
struct dyn_img_common : public dyn_img_hdr_boot { struct dyn_img_common : public dyn_img_hdr_boot {
impl_val(kernel_size) impl_val(kernel_size)
impl_val(ramdisk_size) impl_val(ramdisk_size)
@ -469,7 +476,7 @@ struct dyn_img_pxa : public dyn_img_common {
}; };
#undef impl_val #undef impl_val
#define impl_val(name) __impl_val(name, v3_hdr) #define impl_val(name) __impl_val(name, v4_hdr)
struct dyn_img_v3 : public dyn_img_hdr_boot { struct dyn_img_v3 : public dyn_img_hdr_boot {
impl_cls(v3) impl_cls(v3)
@ -483,15 +490,12 @@ struct dyn_img_v3 : public dyn_img_hdr_boot {
// Make API compatible // Make API compatible
uint32_t &page_size() override { page_sz = 4096; return page_sz; } uint32_t &page_size() override { page_sz = 4096; return page_sz; }
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; } char *extra_cmdline() override { return &v4_hdr->cmdline[BOOT_ARGS_SIZE]; }
private: private:
uint32_t page_sz = 4096; uint32_t page_sz = 4096;
}; };
#undef impl_val
#define impl_val(name) __impl_val(name, v4_hdr)
struct dyn_img_v4 : public dyn_img_v3 { struct dyn_img_v4 : public dyn_img_v3 {
impl_cls(v4) impl_cls(v4)
}; };
@ -502,7 +506,7 @@ protected:
}; };
#undef impl_val #undef impl_val
#define impl_val(name) __impl_val(name, v3_vnd) #define impl_val(name) __impl_val(name, v4_vnd)
struct dyn_img_vnd_v3 : public dyn_img_hdr_vendor { struct dyn_img_vnd_v3 : public dyn_img_hdr_vendor {
impl_cls(vnd_v3) impl_cls(vnd_v3)
@ -518,12 +522,9 @@ struct dyn_img_vnd_v3 : public dyn_img_hdr_vendor {
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); } size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
// Make API compatible // Make API compatible
char *extra_cmdline() override { return &v3_vnd->cmdline[BOOT_ARGS_SIZE]; } char *extra_cmdline() override { return &v4_vnd->cmdline[BOOT_ARGS_SIZE]; }
}; };
#undef impl_val
#define impl_val(name) __impl_val(name, v4_vnd)
struct dyn_img_vnd_v4 : public dyn_img_vnd_v3 { struct dyn_img_vnd_v4 : public dyn_img_vnd_v3 {
impl_cls(vnd_v4) impl_cls(vnd_v4)
}; };
@ -616,4 +617,5 @@ struct boot_img {
~boot_img(); ~boot_img();
void parse_image(uint8_t *addr, format_t type); void parse_image(uint8_t *addr, format_t type);
dyn_img_hdr *create_hdr(uint8_t *addr, format_t type);
}; };