From 01ebe5724ad75bd6bfedeb62458f846a069279f8 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 23 Nov 2021 13:39:15 -0800 Subject: [PATCH] Cleanup zImage parsing code --- native/jni/magiskboot/bootimg.cpp | 84 +++++++++++++++++-------------- native/jni/magiskboot/bootimg.hpp | 12 ++--- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/native/jni/magiskboot/bootimg.cpp b/native/jni/magiskboot/bootimg.cpp index 743bec824..e926a1979 100644 --- a/native/jni/magiskboot/bootimg.cpp +++ b/native/jni/magiskboot/bootimg.cpp @@ -327,15 +327,15 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { get_ignore(vendor_ramdisk_table) get_ignore(bootconfig) - if (int dtb_off = find_dtb_offset(kernel, hdr->kernel_size()); dtb_off > 0) { - kernel_dtb = kernel + dtb_off; - hdr->kernel_dt_size = hdr->kernel_size() - dtb_off; - hdr->kernel_size() = dtb_off; - fprintf(stderr, "%-*s [%u]\n", PADDING, "KERNEL_DTB_SZ", hdr->kernel_dt_size); - } - if (auto size = hdr->kernel_size()) { - k_fmt = check_fmt_lg(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; + hdr->kernel_size() = dtb_off; + fprintf(stderr, "%-*s [%u]\n", PADDING, "KERNEL_DTB_SZ", hdr->kernel_dt_size); + } + + k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); if (k_fmt == MTK) { fprintf(stderr, "MTK_KERNEL_HDR\n"); flags[MTK_KERNEL] = true; @@ -348,30 +348,34 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { } if (k_fmt == ZIMAGE) { z_hdr = reinterpret_cast(kernel); - uint32_t end = z_hdr->end_offset; 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; - uint8_t *end_addr = kernel + z_hdr->end_offset; - for (uint8_t *end_ptr = end_addr - 4; end_ptr >= end_addr - 64; end_ptr -= 4) { - uint32_t val; - memcpy(&val, end_ptr, sizeof(val)); - if (z_hdr->end_offset - val < 0xFF && val < end) { - end = val; + + // Find end of piggy + uint32_t zImage_size = z_hdr->end - z_hdr->start; + uint32_t piggy_end = zImage_size; + uint32_t offsets[16]; + memcpy(offsets, kernel + zImage_size - sizeof(offsets), sizeof(offsets)); + for (int i = 15; i >= 0; --i) { + if (offsets[i] > (zImage_size - 0xFF) && offsets[i] < zImage_size) { + piggy_end = offsets[i]; + break; } } - if (end == z_hdr->end_offset) { - fprintf(stderr, "Could not find end of zImage gzip data, keeping raw kernel\n"); + + if (piggy_end == zImage_size) { + fprintf(stderr, "! Could not find end of zImage piggy, keeping raw kernel\n"); } else { flags[ZIMAGE_KERNEL] = true; - z_info.tail = kernel + end; - z_info.tail_sz = hdr->kernel_size() - end; + z_info.tail = kernel + piggy_end; + z_info.tail_sz = hdr->kernel_size() - piggy_end; kernel += z_info.hdr_sz; - hdr->kernel_size() = end - z_info.hdr_sz; + hdr->kernel_size() = piggy_end - z_info.hdr_sz; k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); } } else { - fprintf(stderr, "Could not find zImage gzip data, keeping raw kernel\n"); + fprintf(stderr, "! Could not find zImage gzip piggy, keeping raw kernel\n"); } } fprintf(stderr, "%-*s [%s]\n", PADDING, "KERNEL_FMT", fmt2name[k_fmt]); @@ -561,8 +565,8 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { // Copy zImage headers xwrite(fd, boot.z_hdr, boot.z_info.hdr_sz); } - size_t raw_size; if (access(KERNEL_FILE, R_OK) == 0) { + size_t raw_size; void *raw_buf; mmap_ro(KERNEL_FILE, raw_buf, raw_size); if (!COMPRESSED_ANY(check_fmt(raw_buf, raw_size)) && COMPRESSED(boot.k_fmt)) { @@ -571,26 +575,32 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { hdr->kernel_size() = xwrite(fd, raw_buf, raw_size); } - if (boot.flags[ZIMAGE_KERNEL] && - boot.k_fmt == GZIP && hdr->kernel_size() > boot.hdr->kernel_size()) { - // Revert and try zipfoli - ftruncate64(fd, lseek64(fd, -(off64_t)hdr->kernel_size(), SEEK_CUR)); - hdr->kernel_size() = compress(ZOPFLI, fd, raw_buf, raw_size); + if (boot.flags[ZIMAGE_KERNEL]) { + if (boot.k_fmt == GZIP && hdr->kernel_size() > boot.hdr->kernel_size()) { + // Revert and try zopfli + ftruncate64(fd, lseek64(fd, -(off64_t)hdr->kernel_size(), SEEK_CUR)); + hdr->kernel_size() = compress(ZOPFLI, fd, raw_buf, raw_size); + } + if (hdr->kernel_size() > boot.hdr->kernel_size()) { + LOGW("! Recompressed kernel is too large, using original kernel\n"); + ftruncate64(fd, lseek64(fd, -(off64_t)hdr->kernel_size(), SEEK_CUR)); + xwrite(fd, boot.kernel, boot.hdr->kernel_size()); + } else { + // Pad zeros to make sure the zImage file size does not change + // Also ensure the last 4 bytes are the uncompressed vmlinux size + uint32_t sz = raw_size; + write_zero(fd, boot.hdr->kernel_size() - hdr->kernel_size() - sizeof(sz)); + xwrite(fd, &sz, sizeof(sz)); + } + + // zImage size shall remain the same + hdr->kernel_size() = boot.hdr->kernel_size(); } munmap(raw_buf, raw_size); } if (boot.flags[ZIMAGE_KERNEL]) { - if (hdr->kernel_size() > boot.hdr->kernel_size()) { - LOGW("Recompressed kernel is too large, using original kernel\n"); - ftruncate64(fd, lseek64(fd, -(off64_t)hdr->kernel_size(), SEEK_CUR)); - hdr->kernel_size() = xwrite(fd, boot.z_info.tail - boot.hdr->kernel_size(), boot.hdr->kernel_size()); - } else { - write_zero(fd, boot.hdr->kernel_size() - hdr->kernel_size() - 4); - uint32_t sz = raw_size; - xwrite(fd, &sz, sizeof(sz)); - hdr->kernel_size() = boot.hdr->kernel_size(); - } + // 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); } diff --git a/native/jni/magiskboot/bootimg.hpp b/native/jni/magiskboot/bootimg.hpp index 4893848fb..5bf02b912 100644 --- a/native/jni/magiskboot/bootimg.hpp +++ b/native/jni/magiskboot/bootimg.hpp @@ -42,12 +42,12 @@ struct blob_hdr { } __attribute__((packed)); struct zimage_hdr { - uint8_t head[36]; - uint32_t magic; /* zImage magic */ - uint32_t load_addr; /* absolute load/run zImage address */ - uint32_t end_offset; /* zImage end offset */ - uint32_t endianess; /* endianess flag */ - uint8_t code[]; + uint32_t code[9]; + uint32_t magic; /* zImage magic */ + uint32_t start; /* absolute load/run zImage address */ + uint32_t end; /* zImage end address */ + uint32_t endian; /* endianess flag */ + // There could be more fields, but we don't care } __attribute__((packed)); /**************