Make sure ro mmap region is not overwritten

This commit is contained in:
topjohnwu 2023-03-21 15:49:43 -07:00 committed by John Wu
parent 2eef542054
commit 4417997749
3 changed files with 85 additions and 71 deletions

View File

@ -32,7 +32,7 @@ static off_t compress(format_t type, int fd, const void *in, size_t size) {
return now - prev;
}
static void dump(void *buf, size_t size, const char *filename) {
static void dump(const void *buf, size_t size, const char *filename) {
if (size == 0)
return;
int fd = creat(filename, 0644);
@ -150,7 +150,7 @@ void dyn_img_hdr::load_hdr_file() {
boot_img::boot_img(const char *image) : map(image) {
fprintf(stderr, "Parsing boot image: [%s]\n", image);
for (uint8_t *addr = map.buf; addr < map.buf + map.sz; ++addr) {
for (const uint8_t *addr = map.buf; addr < map.buf + map.sz; ++addr) {
format_t fmt = check_fmt(addr, map.sz);
switch (fmt) {
case CHROMEOS:
@ -184,15 +184,15 @@ boot_img::~boot_img() {
delete hdr;
}
static int find_dtb_offset(uint8_t *buf, unsigned sz) {
uint8_t * const end = buf + sz;
static int find_dtb_offset(const uint8_t *buf, unsigned sz) {
const uint8_t * const end = buf + sz;
for (uint8_t *curr = buf; curr < end; curr += sizeof(fdt_header)) {
for (auto curr = buf; curr < end; curr += sizeof(fdt_header)) {
curr = static_cast<uint8_t*>(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t)));
if (curr == nullptr)
return -1;
auto fdt_hdr = reinterpret_cast<fdt_header *>(curr);
auto fdt_hdr = reinterpret_cast<const fdt_header *>(curr);
// Check that fdt_header.totalsize does not overflow kernel image size
uint32_t totalsize = fdt32_to_cpu(fdt_hdr->totalsize);
@ -205,7 +205,7 @@ static int find_dtb_offset(uint8_t *buf, unsigned sz) {
continue;
// Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE
auto fdt_node_hdr = reinterpret_cast<fdt_node_header *>(curr + off_dt_struct);
auto fdt_node_hdr = reinterpret_cast<const fdt_node_header *>(curr + off_dt_struct);
if (fdt32_to_cpu(fdt_node_hdr->tag) != FDT_BEGIN_NODE)
continue;
@ -214,7 +214,7 @@ static int find_dtb_offset(uint8_t *buf, unsigned sz) {
return -1;
}
static format_t check_fmt_lg(uint8_t *buf, unsigned sz) {
static format_t check_fmt_lg(const uint8_t *buf, unsigned sz) {
format_t fmt = check_fmt(buf, sz);
if (fmt == LZ4_LEGACY) {
// We need to check if it is LZ4_LG
@ -233,10 +233,10 @@ static format_t check_fmt_lg(uint8_t *buf, unsigned sz) {
#define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s)
dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
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<boot_img_hdr_vnd_v3*>(addr);
auto h = reinterpret_cast<const boot_img_hdr_vnd_v3*>(addr);
hdr_addr = addr;
switch (h->header_version) {
case 4:
@ -246,7 +246,7 @@ dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
}
}
auto h = reinterpret_cast<boot_img_hdr_v0*>(addr);
auto h = reinterpret_cast<const boot_img_hdr_v0*>(addr);
if (h->page_size >= 0x02000000) {
fprintf(stderr, "PXA_BOOT_HDR\n");
@ -254,6 +254,40 @@ dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
return 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);
switch (h->header_version) {
case 1:
return new dyn_img_v1(ptr);
case 2:
return new dyn_img_v2(ptr);
case 3:
return new dyn_img_v3(ptr);
case 4:
return new dyn_img_v4(ptr);
default:
return new dyn_img_v0(ptr);
}
};
// For NOOKHD and ACCLAIM, the entire boot image is shifted by a fixed offset.
// For AMONET, only the header is internally shifted by a fixed offset.
if (BUFFER_CONTAIN(addr, AMONET_MICROLOADER_SZ, AMONET_MICROLOADER_MAGIC) &&
BUFFER_MATCH(addr + AMONET_MICROLOADER_SZ, BOOT_MAGIC)) {
flags[AMONET_FLAG] = true;
fprintf(stderr, "AMONET_MICROLOADER\n");
// 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);
hdr_addr = addr;
return make_hdr(buf.get());
}
if (CMD_MATCH(NOOKHD_RL_MAGIC) ||
CMD_MATCH(NOOKHD_GL_MAGIC) ||
CMD_MATCH(NOOKHD_GR_MAGIC) ||
@ -262,36 +296,15 @@ dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
flags[NOOKHD_FLAG] = true;
fprintf(stderr, "NOOKHD_LOADER\n");
addr += NOOKHD_PRE_HEADER_SZ;
} else if (memcmp(h->name, ACCLAIM_MAGIC, 10) == 0) {
} else if (BUFFER_MATCH(h->name, ACCLAIM_MAGIC)) {
flags[ACCLAIM_FLAG] = true;
fprintf(stderr, "ACCLAIM_LOADER\n");
addr += ACCLAIM_PRE_HEADER_SZ;
} else if (str_contains(string_view((const char *) addr, AMONET_MICROLOADER_SZ), AMONET_MICROLOADER_MAGIC) &&
string_view((const char *)addr + AMONET_MICROLOADER_SZ, BOOT_MAGIC_SIZE) == BOOT_MAGIC) {
flags[AMONET_FLAG] = true;
fprintf(stderr, "AMONET_MICROLOADER\n");
uint8_t microloader[AMONET_MICROLOADER_SZ];
memcpy(microloader, addr, AMONET_MICROLOADER_SZ);
memcpy(addr, addr + AMONET_MICROLOADER_SZ, AMONET_MICROLOADER_SZ);
memcpy(addr + AMONET_MICROLOADER_SZ, microloader, AMONET_MICROLOADER_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);
}
return make_hdr(addr);
}
#define get_block(name) \
@ -306,7 +319,7 @@ if (hdr->name##_size()) { \
off += blk_sz; \
}
void boot_img::parse_image(uint8_t *addr, format_t type) {
void boot_img::parse_image(const uint8_t *addr, format_t type) {
hdr = create_hdr(addr, type);
if (char *id = hdr->id()) {
@ -345,7 +358,7 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
if (k_fmt == MTK) {
fprintf(stderr, "MTK_KERNEL_HDR\n");
flags[MTK_KERNEL] = true;
k_hdr = reinterpret_cast<mtk_hdr *>(kernel);
k_hdr = reinterpret_cast<const mtk_hdr *>(kernel);
fprintf(stderr, "%-*s [%u]\n", PADDING, "SIZE", k_hdr->size);
fprintf(stderr, "%-*s [%s]\n", PADDING, "NAME", k_hdr->name);
kernel += sizeof(mtk_hdr);
@ -353,7 +366,7 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
}
if (k_fmt == ZIMAGE) {
z_hdr = reinterpret_cast<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)) {
fprintf(stderr, "ZIMAGE_KERNEL\n");
z_info.hdr_sz = (uint8_t *) gzip_offset - kernel;
@ -397,7 +410,7 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
if (r_fmt == MTK) {
fprintf(stderr, "MTK_RAMDISK_HDR\n");
flags[MTK_RAMDISK] = true;
r_hdr = reinterpret_cast<mtk_hdr *>(ramdisk);
r_hdr = reinterpret_cast<const mtk_hdr *>(ramdisk);
fprintf(stderr, "%-*s [%u]\n", PADDING, "SIZE", r_hdr->size);
fprintf(stderr, "%-*s [%s]\n", PADDING, "NAME", r_hdr->name);
ramdisk += sizeof(mtk_hdr);
@ -432,15 +445,15 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
}
// Find AVB footer
void *footer = tail + tail_size - sizeof(AvbFooter);
const void *footer = tail + tail_size - sizeof(AvbFooter);
if (BUFFER_MATCH(footer, AVB_FOOTER_MAGIC)) {
avb_footer = reinterpret_cast<AvbFooter*>(footer);
avb_footer = reinterpret_cast<const AvbFooter*>(footer);
// Double check if meta header exists
void *meta = hdr_addr + __builtin_bswap64(avb_footer->vbmeta_offset);
const void *meta = hdr_addr + __builtin_bswap64(avb_footer->vbmeta_offset);
if (BUFFER_MATCH(meta, AVB_MAGIC)) {
fprintf(stderr, "VBMETA\n");
flags[AVB_FLAG] = true;
vbmeta = reinterpret_cast<AvbVBMetaImageHeader*>(meta);
vbmeta = reinterpret_cast<const AvbVBMetaImageHeader*>(meta);
}
}
}
@ -771,7 +784,12 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
hdr->print();
// Copy main header
memcpy(out.buf + off.header, hdr->raw_hdr(), hdr->hdr_size());
if (boot.flags[AMONET_FLAG]) {
auto real_hdr_sz = std::min(hdr->hdr_space() - AMONET_MICROLOADER_SZ, hdr->hdr_size());
memcpy(out.buf + off.header + AMONET_MICROLOADER_SZ, hdr->raw_hdr(), real_hdr_sz);
} else {
memcpy(out.buf + off.header, hdr->raw_hdr(), hdr->hdr_size());
}
if (boot.flags[AVB_FLAG]) {
// Copy and patch AVB structures
@ -796,9 +814,4 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) {
auto b_hdr = reinterpret_cast<blob_hdr *>(out.buf);
b_hdr->size = off.total - sizeof(blob_hdr);
}
if (boot.flags[AMONET_FLAG]) {
memcpy(out.buf + off.header + AMONET_MICROLOADER_SZ, out.buf + off.header, AMONET_MICROLOADER_SZ);
memcpy(out.buf + off.header, boot.hdr_addr + AMONET_MICROLOADER_SZ, AMONET_MICROLOADER_SZ);
}
}

View File

@ -407,7 +407,7 @@ private:
#define __impl_cls(name, hdr) \
protected: name() = default; \
public: \
name(void *ptr) { \
name(const void *ptr) { \
raw = malloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \
} \
@ -577,13 +577,13 @@ struct boot_img {
format_t r_fmt = UNKNOWN;
format_t e_fmt = UNKNOWN;
/***************************************************
* Following pointers points within the mmap region
***************************************************/
/*************************************************************
* Following pointers points within the read-only mmap region
*************************************************************/
// MTK headers
mtk_hdr *k_hdr;
mtk_hdr *r_hdr;
const mtk_hdr *k_hdr;
const mtk_hdr *r_hdr;
// The pointers/values after parse_image
// +---------------+
@ -593,40 +593,40 @@ struct boot_img {
// +---------------+
// | z_info.tail | z_info.tail_sz
// +---------------+
zimage_hdr *z_hdr;
const zimage_hdr *z_hdr;
struct {
uint32_t hdr_sz;
uint32_t tail_sz = 0;
uint8_t *tail = nullptr;
const uint8_t *tail = nullptr;
} z_info;
// Pointer to dtb that is embedded in kernel
uint8_t *kernel_dtb;
const uint8_t *kernel_dtb;
// Pointer to end of image
uint8_t *tail;
const uint8_t *tail;
size_t tail_size = 0;
// AVB structs
AvbFooter *avb_footer;
AvbVBMetaImageHeader *vbmeta;
const AvbFooter *avb_footer;
const AvbVBMetaImageHeader *vbmeta;
// Pointers to blocks defined in header
uint8_t *hdr_addr;
uint8_t *kernel;
uint8_t *ramdisk;
uint8_t *second;
uint8_t *extra;
uint8_t *recovery_dtbo;
uint8_t *dtb;
const uint8_t *hdr_addr;
const uint8_t *kernel;
const uint8_t *ramdisk;
const uint8_t *second;
const uint8_t *extra;
const uint8_t *recovery_dtbo;
const uint8_t *dtb;
// Pointer to blocks defined in header, but we do not care
uint8_t *ignore;
const uint8_t *ignore;
size_t ignore_size = 0;
boot_img(const char *);
~boot_img();
void parse_image(uint8_t *addr, format_t type);
dyn_img_hdr *create_hdr(uint8_t *addr, format_t type);
void parse_image(const uint8_t *addr, format_t type);
dyn_img_hdr *create_hdr(const uint8_t *addr, format_t type);
};

View File

@ -31,6 +31,7 @@ typedef enum {
#define COMPRESSED_ANY(fmt) ((fmt) >= GZIP && (fmt) <= LZOP)
#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0)
#define BUFFER_CONTAIN(buf, sz, s) (memmem(buf, sz, s, sizeof(s) - 1) != nullptr)
#define BOOT_MAGIC "ANDROID!"
#define VENDOR_BOOT_MAGIC "VNDRBOOT"
@ -57,8 +58,8 @@ typedef enum {
#define NOOKHD_PRE_HEADER_SZ 1048576
#define ACCLAIM_MAGIC "BauwksBoot"
#define ACCLAIM_PRE_HEADER_SZ 262144
#define AMONET_MICROLOADER_SZ 1024
#define AMONET_MICROLOADER_MAGIC "microloader"
#define AMONET_MICROLOADER_SZ 1024
#define AVB_FOOTER_MAGIC "AVBf"
#define AVB_MAGIC "AVB0"
#define ZIMAGE_MAGIC "\x18\x28\x6f\x01"