From 74aae523ba762d10f8ae87a8e05d60cb4dba8e26 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Fri, 19 Oct 2018 23:10:47 -0400 Subject: [PATCH] Properly support boot image header v1 Close #695 --- native/jni/Android.mk | 2 +- native/jni/magiskboot/bootimg.c | 453 ---------------------------- native/jni/magiskboot/bootimg.cpp | 459 +++++++++++++++++++++++++++++ native/jni/magiskboot/bootimg.h | 126 +++++--- native/jni/magiskboot/format.c | 1 - native/jni/magiskboot/magiskboot.h | 4 +- 6 files changed, 555 insertions(+), 490 deletions(-) delete mode 100644 native/jni/magiskboot/bootimg.c create mode 100644 native/jni/magiskboot/bootimg.cpp diff --git a/native/jni/Android.mk b/native/jni/Android.mk index e4ab1223c..c8d237253 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -102,7 +102,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ magiskboot/cpio.c \ magiskboot/main.c \ - magiskboot/bootimg.c \ + magiskboot/bootimg.cpp \ magiskboot/hexpatch.c \ magiskboot/compress.c \ magiskboot/format.c \ diff --git a/native/jni/magiskboot/bootimg.c b/native/jni/magiskboot/bootimg.c deleted file mode 100644 index 711c9e10e..000000000 --- a/native/jni/magiskboot/bootimg.c +++ /dev/null @@ -1,453 +0,0 @@ -#include -#include -#include -#include -#include - -#include "bootimg.h" -#include "magiskboot.h" -#include "utils.h" -#include "logging.h" -#include "mincrypt/sha.h" -#include "mincrypt/sha256.h" - -// Macros to determine header on-the-go -#define lheader(b, e, o) \ - ((b)->flags & PXA_FLAG) ? \ - (((struct pxa_boot_img_hdr*) (b)->hdr)->e o) : \ - (((struct boot_img_hdr*) (b)->hdr)->e o) - -#define header(b, e) (lheader(b, e,)) - -static void dump(void *buf, size_t size, const char *filename) { - if (size == 0) - return; - int fd = creat(filename, 0644); - xwrite(fd, buf, size); - close(fd); -} - -static size_t restore(const char *filename, int fd) { - int ifd = xopen(filename, O_RDONLY); - size_t size = lseek(ifd, 0, SEEK_END); - lseek(ifd, 0, SEEK_SET); - xsendfile(fd, ifd, NULL, size); - close(ifd); - return size; -} - -static void restore_buf(int fd, const void *buf, size_t size) { - xwrite(fd, buf, size); -} - -static void print_hdr(const boot_img *boot) { - fprintf(stderr, "KERNEL [%u]\n", header(boot, kernel_size)); - fprintf(stderr, "RAMDISK [%u]\n", header(boot, ramdisk_size)); - fprintf(stderr, "SECOND [%u]\n", header(boot, second_size)); - fprintf(stderr, "EXTRA [%u]\n", header(boot, extra_size)); - fprintf(stderr, "PAGESIZE [%u]\n", header(boot, page_size)); - - if (!(boot->flags & PXA_FLAG)) { - uint32_t os_version = ((boot_img_hdr*) boot->hdr)->os_version; - if (os_version) { - int a,b,c,y,m = 0; - int version, patch_level; - version = os_version >> 11; - patch_level = os_version & 0x7ff; - - a = (version >> 14) & 0x7f; - b = (version >> 7) & 0x7f; - c = version & 0x7f; - fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c); - - y = (patch_level >> 4) + 2000; - m = patch_level & 0xf; - fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m); - } - } - - fprintf(stderr, "NAME [%s]\n", header(boot, name)); - fprintf(stderr, "CMDLINE [%s]\n", header(boot, cmdline)); - fprintf(stderr, "CHECKSUM ["); - for (int i = 0; i < ((boot->flags & SHA256_FLAG) ? SHA256_DIGEST_SIZE : SHA_DIGEST_SIZE); ++i) - fprintf(stderr, "%02x", header(boot, id)[i]); - fprintf(stderr, "]\n"); -} - -static void clean_boot(boot_img *boot) { - munmap(boot->map_addr, boot->map_size); - free(boot->hdr); - free(boot->k_hdr); - free(boot->r_hdr); - free(boot->b_hdr); - memset(boot, 0, sizeof(*boot)); -} - -#define CHROMEOS_RET 2 -#define ELF32_RET 3 -#define ELF64_RET 4 -#define pos_align() pos = align(pos, header(boot, page_size)) -int parse_img(const char *image, boot_img *boot) { - memset(boot, 0, sizeof(*boot)); - mmap_ro(image, &boot->map_addr, &boot->map_size); - - // Parse image - fprintf(stderr, "Parsing boot image: [%s]\n", image); - for (void *head = boot->map_addr; head < boot->map_addr + boot->map_size; ++head) { - size_t pos = 0; - - switch (check_fmt(head, boot->map_size)) { - case CHROMEOS: - // The caller should know it's chromeos, as it needs additional signing - boot->flags |= CHROMEOS_FLAG; - continue; - case DHTB: - boot->flags |= DHTB_FLAG; - boot->flags |= SEANDROID_FLAG; - fprintf(stderr, "DHTB_HDR\n"); - continue; - case ELF32: - exit(ELF32_RET); - case ELF64: - exit(ELF64_RET); - case BLOB: - boot->flags |= BLOB_FLAG; - fprintf(stderr, "TEGRA_BLOB\n"); - boot->b_hdr = malloc(sizeof(blob_hdr)); - memcpy(boot->b_hdr, head, sizeof(blob_hdr)); - continue; - case AOSP: - // Read the header - if (((boot_img_hdr*) head)->page_size >= 0x02000000) { - boot->flags |= PXA_FLAG; - fprintf(stderr, "PXA_BOOT_HDR\n"); - boot->hdr = malloc(sizeof(pxa_boot_img_hdr)); - memcpy(boot->hdr, head, sizeof(pxa_boot_img_hdr)); - } else if (memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_MAGIC, 12) == 0 - || memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_NEW_MAGIC, 26) == 0) { - boot->flags |= NOOKHD_FLAG; - fprintf(stderr, "NOOKHD_GREEN_LOADER\n"); - head += NOOKHD_PRE_HEADER_SZ - 1; - continue; - } else if (memcmp(((boot_img_hdr*) head)->name, ACCLAIM_MAGIC, 10) == 0) { - boot->flags |= ACCLAIM_FLAG; - fprintf(stderr, "ACCLAIM_BAUWKSBOOT\n"); - head += ACCLAIM_PRE_HEADER_SZ - 1; - continue; - } else { - boot->hdr = malloc(sizeof(boot_img_hdr)); - memcpy(boot->hdr, head, sizeof(boot_img_hdr)); - } - pos += header(boot, page_size); - - for (int i = SHA_DIGEST_SIZE; i < SHA256_DIGEST_SIZE; ++i) { - if (header(boot, id)[i]) { - boot->flags |= SHA256_FLAG; - break; - } - } - - print_hdr(boot); - - boot->kernel = head + pos; - pos += header(boot, kernel_size); - pos_align(); - - boot->ramdisk = head + pos; - pos += header(boot, ramdisk_size); - pos_align(); - - boot->second = head + pos; - pos += header(boot, second_size); - pos_align(); - - boot->extra = head + pos; - pos += header(boot, extra_size); - pos_align(); - - if (pos < boot->map_size) { - boot->tail = head + pos; - boot->tail_size = boot->map_size - (boot->tail - boot->map_addr); - } - - // Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE - if (boot->tail_size >= 16 && memcmp(boot->tail, SEANDROID_MAGIC, 16) == 0) { - boot->flags |= SEANDROID_FLAG; - } else if (boot->tail_size >= 16 && memcmp(boot->tail, LG_BUMP_MAGIC, 16) == 0) { - boot->flags |= LG_BUMP_FLAG; - } - - // Search for dtb in kernel - for (uint32_t i = 0; i < header(boot, kernel_size); ++i) { - if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) { - // Check that fdt_header.totalsize does not overflow kernel image size - uint32_t dt_size = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + 4)); - if (dt_size > header(boot, kernel_size) - i) { - fprintf(stderr, "Invalid DTB detection at 0x%x: size (%u) > remaining (%u)\n", - i, dt_size, header(boot, kernel_size) - i); - continue; - } - - // Check that fdt_header.off_dt_struct does not overflow kernel image size - uint32_t dt_struct_offset = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + 8)); - if (dt_struct_offset > header(boot, kernel_size) - i) { - fprintf(stderr, "Invalid DTB detection at 0x%x: struct offset (%u) > remaining (%u)\n", - i, dt_struct_offset, header(boot, kernel_size) - i); - continue; - } - - // Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE - uint32_t dt_begin_node = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + dt_struct_offset)); - if (dt_begin_node != FDT_BEGIN_NODE) { - fprintf(stderr, "Invalid DTB detection at 0x%x: header tag of first node != FDT_BEGIN_NODE\n", i); - continue; - } - - boot->dtb = boot->kernel + i; - boot->dt_size = header(boot, kernel_size) - i; - lheader(boot, kernel_size, = i); - fprintf(stderr, "DTB [%u]\n", boot->dt_size); - break; - } - } - - boot->k_fmt = check_fmt(boot->kernel, header(boot, kernel_size)); - boot->r_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size)); - - // Check MTK - if (boot->k_fmt == MTK) { - fprintf(stderr, "MTK_KERNEL_HDR\n"); - boot->flags |= MTK_KERNEL; - boot->k_hdr = malloc(sizeof(mtk_hdr)); - memcpy(boot->k_hdr, boot->kernel, sizeof(mtk_hdr)); - fprintf(stderr, "KERNEL [%u]\n", boot->k_hdr->size); - fprintf(stderr, "NAME [%s]\n", boot->k_hdr->name); - boot->kernel += 512; - lheader(boot, kernel_size, -= 512); - boot->k_fmt = check_fmt(boot->kernel, header(boot, kernel_size)); - } - if (boot->r_fmt == MTK) { - fprintf(stderr, "MTK_RAMDISK_HDR\n"); - boot->flags |= MTK_RAMDISK; - boot->r_hdr = malloc(sizeof(mtk_hdr)); - memcpy(boot->r_hdr, boot->ramdisk, sizeof(mtk_hdr)); - fprintf(stderr, "RAMDISK [%u]\n", boot->r_hdr->size); - fprintf(stderr, "NAME [%s]\n", boot->r_hdr->name); - boot->ramdisk += 512; - lheader(boot, ramdisk_size, -= 512); - boot->r_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size)); - } - - char fmt[16]; - get_fmt_name(boot->k_fmt, fmt); - fprintf(stderr, "KERNEL_FMT [%s]\n", fmt); - get_fmt_name(boot->r_fmt, fmt); - fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt); - - return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET : 0; - default: - continue; - } - } - LOGE("No boot image magic found!\n"); - exit(1); -} - -int unpack(const char *image) { - boot_img boot; - int ret = parse_img(image, &boot); - int fd; - - // Dump kernel - if (COMPRESSED(boot.k_fmt)) { - fd = creat(KERNEL_FILE, 0644); - decomp(boot.k_fmt, fd, boot.kernel, header(&boot, kernel_size)); - close(fd); - } else { - dump(boot.kernel, header(&boot, kernel_size), KERNEL_FILE); - } - - // Dump dtb - dump(boot.dtb, boot.dt_size, DTB_FILE); - - // Dump ramdisk - if (COMPRESSED(boot.r_fmt)) { - fd = creat(RAMDISK_FILE, 0644); - decomp(boot.r_fmt, fd, boot.ramdisk, header(&boot, ramdisk_size)); - close(fd); - } else { - dump(boot.ramdisk, header(&boot, ramdisk_size), RAMDISK_FILE); - } - - // Dump second - dump(boot.second, header(&boot, second_size), SECOND_FILE); - - // Dump extra - dump(boot.extra, header(&boot, extra_size), EXTRA_FILE); - - clean_boot(&boot); - return ret; -} - -#define file_align() write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR) - header_off, header(&boot, page_size))) -void repack(const char* orig_image, const char* out_image) { - boot_img boot; - - off_t header_off, kernel_off, ramdisk_off, second_off, extra_off; - - // Parse original image - parse_img(orig_image, &boot); - - // Reset all sizes - lheader(&boot, kernel_size, = 0); - lheader(&boot, ramdisk_size, = 0); - lheader(&boot, second_size, = 0); - lheader(&boot, extra_size, = 0); - boot.dt_size = 0; - - fprintf(stderr, "Repack to boot image: [%s]\n", out_image); - - // Create new image - int fd = creat(out_image, 0644); - - if (boot.flags & DHTB_FLAG) { - // Skip DHTB header - write_zero(fd, 512); - } else if (boot.flags & BLOB_FLAG) { - // Skip blob header - write_zero(fd, sizeof(blob_hdr)); - } else if (boot.flags & NOOKHD_FLAG) { - restore_buf(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ); - } else if (boot.flags & ACCLAIM_FLAG) { - restore_buf(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ); - } - - // Skip a page for header - header_off = lseek(fd, 0, SEEK_CUR); - write_zero(fd, header(&boot, page_size)); - - // kernel - kernel_off = lseek(fd, 0, SEEK_CUR); - if (boot.flags & MTK_KERNEL) { - // Skip MTK header - write_zero(fd, 512); - } - if (access(KERNEL_FILE, R_OK) == 0) { - if (COMPRESSED(boot.k_fmt)) { - size_t raw_size; - void *kernel_raw; - mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size); - lheader(&boot, kernel_size, = comp(boot.k_fmt, fd, kernel_raw, raw_size)); - munmap(kernel_raw, raw_size); - } else { - lheader(&boot, kernel_size, = restore(KERNEL_FILE, fd)); - } - } - - // dtb - if (access(DTB_FILE, R_OK) == 0) { - lheader(&boot, kernel_size, += restore(DTB_FILE, fd)); - } - file_align(); - - // ramdisk - ramdisk_off = lseek(fd, 0, SEEK_CUR); - if (boot.flags & MTK_RAMDISK) { - // Skip MTK header - write_zero(fd, 512); - } - if (access(RAMDISK_FILE, R_OK) == 0) { - if (COMPRESSED(boot.r_fmt)) { - size_t cpio_size; - void *cpio; - mmap_ro(RAMDISK_FILE, &cpio, &cpio_size); - lheader(&boot, ramdisk_size, = comp(boot.r_fmt, fd, cpio, cpio_size)); - munmap(cpio, cpio_size); - } else { - lheader(&boot, ramdisk_size, = restore(RAMDISK_FILE, fd)); - } - file_align(); - } - - // second - second_off = lseek(fd, 0, SEEK_CUR); - if (access(SECOND_FILE, R_OK) == 0) { - lheader(&boot, second_size, = restore(SECOND_FILE, fd)); - file_align(); - } - - // extra - extra_off = lseek(fd, 0, SEEK_CUR); - if (access(EXTRA_FILE, R_OK) == 0) { - lheader(&boot, extra_size, = restore(EXTRA_FILE, fd)); - file_align(); - } - - // Append tail info - if (boot.flags & SEANDROID_FLAG) { - restore_buf(fd, SEANDROID_MAGIC "\xFF\xFF\xFF\xFF", 20); - } - if (boot.flags & LG_BUMP_FLAG) { - restore_buf(fd, LG_BUMP_MAGIC, 16); - } - - close(fd); - - // Map output image as rw - munmap(boot.map_addr, boot.map_size); - mmap_rw(out_image, &boot.map_addr, &boot.map_size); - - // MTK headers - if (boot.flags & MTK_KERNEL) { - boot.k_hdr->size = header(&boot, kernel_size); - lheader(&boot, kernel_size, += 512); - memcpy(boot.map_addr + kernel_off, boot.k_hdr, sizeof(mtk_hdr)); - } - if (boot.flags & MTK_RAMDISK) { - boot.r_hdr->size = header(&boot, ramdisk_size); - lheader(&boot, ramdisk_size, += 512); - memcpy(boot.map_addr + ramdisk_off, boot.r_hdr, sizeof(mtk_hdr)); - } - - // Update checksum - HASH_CTX ctx; - (boot.flags & SHA256_FLAG) ? SHA256_init(&ctx) : SHA_init(&ctx); - uint32_t size = header(&boot, kernel_size); - HASH_update(&ctx, boot.map_addr + kernel_off, size); - HASH_update(&ctx, &size, sizeof(size)); - size = header(&boot, ramdisk_size); - HASH_update(&ctx, boot.map_addr + ramdisk_off, size); - HASH_update(&ctx, &size, sizeof(size)); - size = header(&boot, second_size); - HASH_update(&ctx, boot.map_addr + second_off, size); - HASH_update(&ctx, &size, sizeof(size)); - size = header(&boot, extra_size); - if (size) { - HASH_update(&ctx, boot.map_addr + extra_off, size); - HASH_update(&ctx, &size, sizeof(size)); - } - memset(header(&boot, id), 0, 32); - memcpy(header(&boot, id), HASH_final(&ctx), - (boot.flags & SHA256_FLAG) ? SHA256_DIGEST_SIZE : SHA_DIGEST_SIZE); - - // Print new image info - print_hdr(&boot); - - // Main header - memcpy(boot.map_addr + header_off, boot.hdr, - (boot.flags & PXA_FLAG) ? sizeof(pxa_boot_img_hdr) : sizeof(boot_img_hdr)); - - if (boot.flags & DHTB_FLAG) { - // DHTB header - dhtb_hdr *hdr = boot.map_addr; - memcpy(hdr, DHTB_MAGIC, 8); - hdr->size = boot.map_size - 512; - SHA256_hash(boot.map_addr + 512, hdr->size, hdr->checksum); - } else if (boot.flags & BLOB_FLAG) { - // Blob headers - boot.b_hdr->size = boot.map_size - sizeof(blob_hdr); - memcpy(boot.map_addr, boot.b_hdr, sizeof(blob_hdr)); - } - - clean_boot(&boot); -} diff --git a/native/jni/magiskboot/bootimg.cpp b/native/jni/magiskboot/bootimg.cpp new file mode 100644 index 000000000..de937c68f --- /dev/null +++ b/native/jni/magiskboot/bootimg.cpp @@ -0,0 +1,459 @@ +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include "bootimg.h" +#include "magiskboot.h" +#include "utils.h" +#include "logging.h" +} + +static void dump(void *buf, size_t size, const char *filename) { + if (size == 0) + return; + int fd = creat(filename, 0644); + xwrite(fd, buf, size); + close(fd); +} + +static size_t restore(const char *filename, int fd) { + int ifd = xopen(filename, O_RDONLY); + size_t size = lseek(ifd, 0, SEEK_END); + lseek(ifd, 0, SEEK_SET); + xsendfile(fd, ifd, NULL, size); + close(ifd); + return size; +} + +static void restore_buf(int fd, const void *buf, size_t size) { + xwrite(fd, buf, size); +} + +boot_img::~boot_img() { + munmap(map_addr, map_size); + delete hdr; + delete k_hdr; + delete r_hdr; + delete b_hdr; +} + +#define CHROMEOS_RET 2 +#define ELF32_RET 3 +#define ELF64_RET 4 +#define pos_align() pos = align(pos, page_size()) + +int boot_img::parse_image(const char * image) { + mmap_ro(image, (void **) &map_addr, &map_size); + + // Parse image + fprintf(stderr, "Parsing boot image: [%s]\n", image); + for (uint8_t *head = map_addr; head < map_addr + map_size; ++head) { + size_t pos = 0; + + switch (check_fmt(head, map_size)) { + case CHROMEOS: + // The caller should know it's chromeos, as it needs additional signing + flags |= CHROMEOS_FLAG; + break; + case DHTB: + flags |= DHTB_FLAG; + flags |= SEANDROID_FLAG; + fprintf(stderr, "DHTB_HDR\n"); + break; + case ELF32: + exit(ELF32_RET); + case ELF64: + exit(ELF64_RET); + case BLOB: + flags |= BLOB_FLAG; + fprintf(stderr, "TEGRA_BLOB\n"); + b_hdr = new blob_hdr(); + memcpy(b_hdr, head, sizeof(blob_hdr)); + break; + case AOSP: + // Read the header + if (((boot_img_hdr*) head)->page_size >= 0x02000000) { + flags |= PXA_FLAG; + fprintf(stderr, "PXA_BOOT_HDR\n"); + hdr = new boot_img_hdr_pxa(); + memcpy(hdr, head, sizeof(boot_img_hdr_pxa)); + } else if (memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_MAGIC, 12) == 0 + || memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_NEW_MAGIC, 26) == 0) { + flags |= NOOKHD_FLAG; + fprintf(stderr, "NOOKHD_GREEN_LOADER\n"); + head += NOOKHD_PRE_HEADER_SZ - 1; + continue; + } else if (memcmp(((boot_img_hdr*) head)->name, ACCLAIM_MAGIC, 10) == 0) { + flags |= ACCLAIM_FLAG; + fprintf(stderr, "ACCLAIM_BAUWKSBOOT\n"); + head += ACCLAIM_PRE_HEADER_SZ - 1; + continue; + } else { + hdr = new boot_img_hdr(); + memcpy(hdr, head, sizeof(boot_img_hdr)); + } + pos += page_size(); + + flags |= id()[SHA_DIGEST_SIZE] ? SHA256_FLAG : 0; + + print_hdr(); + + kernel = head + pos; + pos += hdr->kernel_size; + pos_align(); + + ramdisk = head + pos; + pos += hdr->ramdisk_size; + pos_align(); + + second = head + pos; + pos += hdr->second_size; + pos_align(); + + extra = head + pos; + pos += extra_size(); + pos_align(); + + recov_dtbo = head + pos; + pos += recovery_dtbo_size(); + pos_align(); + + if (pos < map_size) { + tail = head + pos; + tail_size = map_size - (tail - map_addr); + } + + // Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE + if (tail_size >= 16 && memcmp(tail, SEANDROID_MAGIC, 16) == 0) { + flags |= SEANDROID_FLAG; + } else if (tail_size >= 16 && memcmp(tail, LG_BUMP_MAGIC, 16) == 0) { + flags |= LG_BUMP_FLAG; + } + + find_dtb(); + + k_fmt = check_fmt(kernel, hdr->kernel_size); + r_fmt = check_fmt(ramdisk, hdr->ramdisk_size); + + // Check MTK + if (k_fmt == MTK) { + fprintf(stderr, "MTK_KERNEL_HDR\n"); + flags |= MTK_KERNEL; + k_hdr = new mtk_hdr(); + memcpy(k_hdr, kernel, sizeof(mtk_hdr)); + fprintf(stderr, "KERNEL [%u]\n", k_hdr->size); + fprintf(stderr, "NAME [%s]\n", k_hdr->name); + kernel += 512; + hdr->kernel_size -= 512; + k_fmt = check_fmt(kernel, hdr->kernel_size); + } + if (r_fmt == MTK) { + fprintf(stderr, "MTK_RAMDISK_HDR\n"); + flags |= MTK_RAMDISK; + r_hdr = new mtk_hdr(); + memcpy(r_hdr, ramdisk, sizeof(mtk_hdr)); + fprintf(stderr, "RAMDISK [%u]\n", r_hdr->size); + fprintf(stderr, "NAME [%s]\n", r_hdr->name); + ramdisk += 512; + hdr->ramdisk_size -= 512; + r_fmt = check_fmt(ramdisk, hdr->ramdisk_size); + } + + char fmt[16]; + get_fmt_name(k_fmt, fmt); + fprintf(stderr, "KERNEL_FMT\t[%s]\n", fmt); + get_fmt_name(r_fmt, fmt); + fprintf(stderr, "RAMDISK_FMT\t[%s]\n", fmt); + + return flags & CHROMEOS_FLAG ? CHROMEOS_RET : 0; + default: + break; + } + } + LOGE("No boot image magic found!\n"); + exit(1); +} + +void boot_img::find_dtb() { + for (uint32_t i = 0; i < hdr->kernel_size; ++i) { + if (memcmp(kernel + i, DTB_MAGIC, 4)) + continue; + // Check that fdt_header.totalsize does not overflow kernel image size + uint32_t dt_sz = fdt32_to_cpu(*(uint32_t *)(kernel + i + 4)); + if (dt_sz > hdr->kernel_size - i) { + fprintf(stderr, "Invalid DTB detection at 0x%x: size (%u) > remaining (%u)\n", + i, dt_sz, hdr->kernel_size - i); + continue; + } + + // Check that fdt_header.off_dt_struct does not overflow kernel image size + uint32_t dt_struct_offset = fdt32_to_cpu(*(uint32_t *)(kernel + i + 8)); + if (dt_struct_offset > hdr->kernel_size - i) { + fprintf(stderr, "Invalid DTB detection at 0x%x: " + "struct offset (%u) > remaining (%u)\n", + i, dt_struct_offset, hdr->kernel_size - i); + continue; + } + + // Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE + uint32_t dt_begin_node = fdt32_to_cpu(*(uint32_t *)(kernel + i + dt_struct_offset)); + if (dt_begin_node != FDT_BEGIN_NODE) { + fprintf(stderr, "Invalid DTB detection at 0x%x: " + "header tag of first node != FDT_BEGIN_NODE\n", i); + continue; + } + + dtb = kernel + i; + dt_size = hdr->kernel_size - i; + hdr->kernel_size = i; + fprintf(stderr, "DTB\t\t[%u]\n", dt_size); + break; + } +} + +void boot_img::print_hdr() { + fprintf(stderr, "HEADER_VER\t[%u]\n", header_version()); + fprintf(stderr, "KERNEL_SZ\t[%u]\n", hdr->kernel_size); + fprintf(stderr, "RAMDISK_SZ\t[%u]\n", hdr->ramdisk_size); + fprintf(stderr, "SECOND_SZ\t[%u]\n", hdr->second_size); + fprintf(stderr, "EXTRA_SZ\t[%u]\n", extra_size()); + fprintf(stderr, "RECOV_DTBO_SZ\t[%u]\n", recovery_dtbo_size()); + + uint32_t ver = os_version(); + if (ver) { + int a,b,c,y,m = 0; + int version, patch_level; + version = ver >> 11; + patch_level = ver & 0x7ff; + + a = (version >> 14) & 0x7f; + b = (version >> 7) & 0x7f; + c = version & 0x7f; + fprintf(stderr, "OS_VERSION\t[%d.%d.%d]\n", a, b, c); + + y = (patch_level >> 4) + 2000; + m = patch_level & 0xf; + fprintf(stderr, "PATCH_LEVEL\t[%d-%02d]\n", y, m); + } + + fprintf(stderr, "PAGESIZE\t[%u]\n", page_size()); + fprintf(stderr, "NAME\t\t[%s]\n", name()); + fprintf(stderr, "CMDLINE\t\t[%s]\n", cmdline()); + fprintf(stderr, "CHECKSUM\t["); + for (int i = 0; id()[i]; ++i) + fprintf(stderr, "%02x", id()[i]); + fprintf(stderr, "]\n"); +} + +int unpack(const char *image) { + boot_img boot; + int ret = boot.parse_image(image); + int fd; + + // Dump kernel + if (COMPRESSED(boot.k_fmt)) { + fd = creat(KERNEL_FILE, 0644); + decomp(boot.k_fmt, fd, boot.kernel, boot.hdr->kernel_size); + close(fd); + } else { + dump(boot.kernel, boot.hdr->kernel_size, KERNEL_FILE); + } + + // Dump dtb + dump(boot.dtb, boot.dt_size, DTB_FILE); + + // Dump ramdisk + if (COMPRESSED(boot.r_fmt)) { + fd = creat(RAMDISK_FILE, 0644); + decomp(boot.r_fmt, fd, boot.ramdisk, boot.hdr->ramdisk_size); + close(fd); + } else { + dump(boot.ramdisk, boot.hdr->ramdisk_size, RAMDISK_FILE); + } + + // Dump second + dump(boot.second, boot.hdr->second_size, SECOND_FILE); + + // Dump extra + dump(boot.extra, boot.extra_size(), EXTRA_FILE); + + // Dump recovery_dtbo + dump(boot.recov_dtbo, boot.recovery_dtbo_size(), RECV_DTBO_FILE); + return ret; +} + +#define file_align() write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR) - header_off, boot.page_size())) +void repack(const char* orig_image, const char* out_image) { + boot_img boot; + + off_t header_off, kernel_off, ramdisk_off, second_off, extra_off; + + // Parse original image + boot.parse_image(orig_image); + + // Reset sizes + boot.hdr->kernel_size = 0; + boot.hdr->ramdisk_size = 0; + boot.hdr->second_size = 0; + boot.dt_size = 0; + + fprintf(stderr, "Repack to boot image: [%s]\n", out_image); + + // Create new image + int fd = creat(out_image, 0644); + + if (boot.flags & DHTB_FLAG) { + // Skip DHTB header + write_zero(fd, 512); + } else if (boot.flags & BLOB_FLAG) { + // Skip blob header + write_zero(fd, sizeof(blob_hdr)); + } else if (boot.flags & NOOKHD_FLAG) { + restore_buf(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ); + } else if (boot.flags & ACCLAIM_FLAG) { + restore_buf(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ); + } + + // Skip a page for header + header_off = lseek(fd, 0, SEEK_CUR); + write_zero(fd, boot.page_size()); + + // kernel + kernel_off = lseek(fd, 0, SEEK_CUR); + if (boot.flags & MTK_KERNEL) { + // Skip MTK header + write_zero(fd, 512); + } + if (access(KERNEL_FILE, R_OK) == 0) { + if (COMPRESSED(boot.k_fmt)) { + size_t raw_size; + void *kernel_raw; + mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size); + boot.hdr->kernel_size = comp(boot.k_fmt, fd, kernel_raw, raw_size); + munmap(kernel_raw, raw_size); + } else { + boot.hdr->kernel_size = restore(KERNEL_FILE, fd); + } + } + + // dtb + if (access(DTB_FILE, R_OK) == 0) + boot.hdr->kernel_size += restore(DTB_FILE, fd); + file_align(); + + // ramdisk + ramdisk_off = lseek(fd, 0, SEEK_CUR); + if (boot.flags & MTK_RAMDISK) { + // Skip MTK header + write_zero(fd, 512); + } + if (access(RAMDISK_FILE, R_OK) == 0) { + if (COMPRESSED(boot.r_fmt)) { + size_t cpio_size; + void *cpio; + mmap_ro(RAMDISK_FILE, &cpio, &cpio_size); + boot.hdr->ramdisk_size = comp(boot.r_fmt, fd, cpio, cpio_size); + munmap(cpio, cpio_size); + } else { + boot.hdr->ramdisk_size = restore(RAMDISK_FILE, fd); + } + file_align(); + } + + // second + second_off = lseek(fd, 0, SEEK_CUR); + if (access(SECOND_FILE, R_OK) == 0) { + boot.hdr->second_size = restore(SECOND_FILE, fd); + file_align(); + } + + // extra + extra_off = lseek(fd, 0, SEEK_CUR); + if (access(EXTRA_FILE, R_OK) == 0) { + boot.extra_size(restore(EXTRA_FILE, fd)); + file_align(); + } + + // recovery_dtbo + if (access(RECV_DTBO_FILE, R_OK) == 0) { + boot.recovery_dtbo_offset(lseek(fd, 0, SEEK_CUR)); + boot.recovery_dtbo_size(restore(RECV_DTBO_FILE, fd)); + file_align(); + } + + // Append tail info + if (boot.flags & SEANDROID_FLAG) { + restore_buf(fd, SEANDROID_MAGIC "\xFF\xFF\xFF\xFF", 20); + } + if (boot.flags & LG_BUMP_FLAG) { + restore_buf(fd, LG_BUMP_MAGIC, 16); + } + + close(fd); + + // Map output image as rw + munmap(boot.map_addr, boot.map_size); + mmap_rw(out_image, reinterpret_cast(&boot.map_addr), &boot.map_size); + + // MTK headers + if (boot.flags & MTK_KERNEL) { + boot.k_hdr->size = boot.hdr->kernel_size; + boot.hdr->kernel_size += 512; + memcpy(boot.map_addr + kernel_off, boot.k_hdr, sizeof(mtk_hdr)); + } + if (boot.flags & MTK_RAMDISK) { + boot.r_hdr->size = boot.hdr->ramdisk_size; + boot.hdr->ramdisk_size += 512; + memcpy(boot.map_addr + ramdisk_off, boot.r_hdr, sizeof(mtk_hdr)); + } + + // Update checksum + HASH_CTX ctx; + (boot.flags & SHA256_FLAG) ? SHA256_init(&ctx) : SHA_init(&ctx); + uint32_t size = boot.hdr->kernel_size; + HASH_update(&ctx, boot.map_addr + kernel_off, size); + HASH_update(&ctx, &size, sizeof(size)); + size = boot.hdr->ramdisk_size; + HASH_update(&ctx, boot.map_addr + ramdisk_off, size); + HASH_update(&ctx, &size, sizeof(size)); + size = boot.hdr->second_size; + HASH_update(&ctx, boot.map_addr + second_off, size); + HASH_update(&ctx, &size, sizeof(size)); + size = boot.extra_size(); + if (size) { + HASH_update(&ctx, boot.map_addr + extra_off, size); + HASH_update(&ctx, &size, sizeof(size)); + } + if (boot.header_version()) { + size = boot.recovery_dtbo_size(); + HASH_update(&ctx, boot.map_addr + boot.recovery_dtbo_offset(), size); + HASH_update(&ctx, &size, sizeof(size)); + } + memset(boot.id(), 0, 32); + memcpy(boot.id(), HASH_final(&ctx), + (boot.flags & SHA256_FLAG) ? SHA256_DIGEST_SIZE : SHA_DIGEST_SIZE); + + // Print new image info + boot.print_hdr(); + + // Main header + memcpy(boot.map_addr + header_off, boot.hdr, boot.hdr_size()); + + if (boot.flags & DHTB_FLAG) { + // DHTB header + dhtb_hdr *hdr = reinterpret_cast(boot.map_addr); + memcpy(hdr, DHTB_MAGIC, 8); + hdr->size = boot.map_size - 512; + SHA256_hash(boot.map_addr + 512, hdr->size, hdr->checksum); + } else if (boot.flags & BLOB_FLAG) { + // Blob headers + boot.b_hdr->size = boot.map_size - sizeof(blob_hdr); + memcpy(boot.map_addr, boot.b_hdr, sizeof(blob_hdr)); + } +} diff --git a/native/jni/magiskboot/bootimg.h b/native/jni/magiskboot/bootimg.h index e71c6fec8..ab89e5f8d 100644 --- a/native/jni/magiskboot/bootimg.h +++ b/native/jni/magiskboot/bootimg.h @@ -4,7 +4,7 @@ #ifndef _BOOT_IMAGE_H_ #define _BOOT_IMAGE_H_ -typedef struct boot_img_hdr { +struct boot_img_hdr_base { char magic[8]; uint32_t kernel_size; /* size in bytes */ @@ -15,10 +15,19 @@ typedef struct boot_img_hdr { uint32_t second_size; /* size in bytes */ uint32_t second_addr; /* physical load addr */ +} __attribute__((packed)); +struct boot_img_hdr_v0 : public boot_img_hdr_base { uint32_t tags_addr; /* physical addr for kernel tags */ uint32_t page_size; /* flash page size we assume */ - uint32_t extra_size; /* extra blob size in bytes */ + + /* In header v1, this field is used for header version + * However, on some devices like Samsung, this field is used to store DTB + * We will treat this field differently based on its value */ + union { + uint32_t header_version; /* the version of the header */ + uint32_t extra_size; /* extra blob size in bytes */ + }; /* operating system version and security patch level; for * version "A.B.C" and patch level "Y-M-D": @@ -34,20 +43,19 @@ typedef struct boot_img_hdr { /* Supplemental command line data; kept here to maintain * binary compatibility with older versions of mkbootimg */ char extra_cmdline[1024]; -} __attribute__((packed)) boot_img_hdr ; +} __attribute__((packed)); -typedef struct pxa_boot_img_hdr { - char magic[8]; +struct boot_img_hdr_v1 : public boot_img_hdr_v0 { + uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */ + uint64_t recovery_dtbo_offset; /* offset to recovery dtbo in boot image */ + uint32_t header_size; +} __attribute__((packed)); - uint32_t kernel_size; /* size in bytes */ - uint32_t kernel_addr; /* physical load addr */ - - uint32_t ramdisk_size; /* size in bytes */ - uint32_t ramdisk_addr; /* physical load addr */ - - uint32_t second_size; /* size in bytes */ - uint32_t second_addr; /* physical load addr */ +// Default to hdr v1 +typedef boot_img_hdr_v1 boot_img_hdr; +// Special Samsung header +struct boot_img_hdr_pxa : public boot_img_hdr_base { uint32_t extra_size; /* extra blob size in bytes */ uint32_t unknown; /* unknown value */ uint32_t tags_addr; /* physical addr for kernel tags */ @@ -60,7 +68,7 @@ typedef struct pxa_boot_img_hdr { /* Supplemental command line data; kept here to maintain * binary compatibility with older versions of mkbootimg */ char extra_cmdline[1024]; -} __attribute__((packed)) pxa_boot_img_hdr; +} __attribute__((packed)); /* ** +-----------------+ @@ -74,11 +82,14 @@ typedef struct pxa_boot_img_hdr { ** +-----------------+ ** | extra blob | p pages ** +-----------------+ +** | recovery dtbo | q pages +** +-----------------+ ** ** n = (kernel_size + page_size - 1) / page_size ** m = (ramdisk_size + page_size - 1) / page_size ** o = (second_size + page_size - 1) / page_size ** p = (extra_size + page_size - 1) / page_size +** q = (recovery_dtbo_size + page_size - 1) / page_size ** ** 0. all entities are page_size aligned in flash ** 1. kernel and ramdisk are required (size != 0) @@ -92,19 +103,19 @@ typedef struct pxa_boot_img_hdr { ** else: jump to kernel_addr */ -typedef struct mtk_hdr { +struct mtk_hdr { uint32_t magic; /* MTK magic */ uint32_t size; /* Size of the content */ char name[32]; /* The type of the header */ -} __attribute__((packed)) mtk_hdr; +} __attribute__((packed)); -typedef struct dhtb_hdr { +struct dhtb_hdr { char magic[8]; /* DHTB magic */ uint8_t checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */ uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */ -} __attribute__((packed)) dhtb_hdr; +} __attribute__((packed)); -typedef struct blob_hdr { +struct blob_hdr { char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */ uint32_t datalen; /* 0x00000000 */ uint32_t signature; /* 0x00000000 */ @@ -118,7 +129,7 @@ typedef struct blob_hdr { uint32_t offset; /* offset in blob where this partition starts */ uint32_t size; /* Size of data */ uint32_t version; /* 0x00000001 */ -} __attribute__((packed)) blob_hdr; +} __attribute__((packed)); // Flags #define MTK_KERNEL 0x0001 @@ -133,16 +144,16 @@ typedef struct blob_hdr { #define NOOKHD_FLAG 0x0200 #define ACCLAIM_FLAG 0x0400 -typedef struct boot_img { +struct boot_img { // Memory map of the whole image - void *map_addr; + uint8_t *map_addr; size_t map_size; // Headers - void *hdr; /* Either boot_img_hdr or pxa_boot_img_hdr */ - mtk_hdr *k_hdr; /* MTK kernel header */ - mtk_hdr *r_hdr; /* MTK ramdisk header */ - blob_hdr *b_hdr; /* Tegra blob header */ + boot_img_hdr_base *hdr; /* Android boot image header */ + mtk_hdr *k_hdr; /* MTK kernel header */ + mtk_hdr *r_hdr; /* MTK ramdisk header */ + blob_hdr *b_hdr; /* Tegra blob header */ // Flags to indicate the state of current boot image uint16_t flags; @@ -152,18 +163,67 @@ typedef struct boot_img { format_t r_fmt; // Pointer to dtb that is appended after kernel - void *dtb; + uint8_t *dtb; uint32_t dt_size; // Pointer to end of image - void *tail; + uint8_t *tail; size_t tail_size; // Pointers to blocks defined in header - void *kernel; - void *ramdisk; - void *second; - void *extra; -} boot_img; + uint8_t *kernel; + uint8_t *ramdisk; + uint8_t *second; + uint8_t *extra; + uint8_t *recov_dtbo; + + ~boot_img(); + + int parse_image(const char *); + void find_dtb(); + void print_hdr(); + + /* Access elements in header */ + +#define IS_PXA (flags & PXA_FLAG) +#define dyn_access(x) (IS_PXA ? \ +static_cast(hdr)->x : \ +static_cast(hdr)->x) + +#define dyn_get(x, t) t x() const { return dyn_access(x); } +#define dyn_set(x, t) void x(t v) { dyn_access(x) = v; } +#define hdr_get(x, t) t x() const { return IS_PXA ? 0 : static_cast(hdr)->x; } +#define hdr_set(x, t) void x(t v) { if (!IS_PXA) static_cast(hdr)->x = v; } + + dyn_set(extra_size, uint32_t); + dyn_get(page_size, uint32_t); + dyn_get(name, char *); + dyn_get(cmdline, char *); + dyn_get(id, char *); + + hdr_get(os_version, uint32_t); + hdr_get(recovery_dtbo_size, uint32_t); + hdr_set(recovery_dtbo_size, uint32_t); + hdr_get(recovery_dtbo_offset, uint32_t); + hdr_set(recovery_dtbo_offset, uint32_t); + + uint32_t header_version() { + if (IS_PXA) + return 0; + uint32_t ver = static_cast(hdr)->header_version; + // There won't be v4 header any time soon... + // If larger than 4, assume this field will be treated as extra_size + return ver > 4 ? 0 : ver; + } + + uint32_t extra_size() { + // If header version > 0, we should treat this field as header_version + return header_version() ? 0 : dyn_access(extra_size); + } + + size_t hdr_size() { + return IS_PXA ? sizeof(boot_img_hdr_pxa) : sizeof(boot_img_hdr); + } +}; #endif diff --git a/native/jni/magiskboot/format.c b/native/jni/magiskboot/format.c index 40b6d7bb3..7dd4add92 100644 --- a/native/jni/magiskboot/format.c +++ b/native/jni/magiskboot/format.c @@ -1,6 +1,5 @@ #include -#include "bootimg.h" #include "format.h" #define MATCH(s) (len >= (sizeof(s) - 1) && memcmp(buf, s, sizeof(s) - 1) == 0) diff --git a/native/jni/magiskboot/magiskboot.h b/native/jni/magiskboot/magiskboot.h index 992e0c0e8..57a29f9e6 100644 --- a/native/jni/magiskboot/magiskboot.h +++ b/native/jni/magiskboot/magiskboot.h @@ -4,20 +4,20 @@ #include #include "logging.h" -#include "bootimg.h" +#include "format.h" #define KERNEL_FILE "kernel" #define RAMDISK_FILE "ramdisk.cpio" #define SECOND_FILE "second" #define EXTRA_FILE "extra" #define DTB_FILE "dtb" +#define RECV_DTBO_FILE "recovery_dtbo" #define NEW_BOOT "new-boot.img" // Main entries int unpack(const char *image); void repack(const char* orig_image, const char* out_image); void hexpatch(const char *image, const char *from, const char *to); -int parse_img(const char *image, boot_img *boot); int cpio_commands(int argc, char *argv[]); void comp_file(const char *method, const char *from, const char *to); void decomp_file(char *from, const char *to);