diff --git a/native/jni/magiskboot/bootimg.cpp b/native/jni/magiskboot/bootimg.cpp index df5fa2723..2fa81571f 100644 --- a/native/jni/magiskboot/bootimg.cpp +++ b/native/jni/magiskboot/bootimg.cpp @@ -323,40 +323,32 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { } if (k_fmt == ZIMAGE) { z_hdr = reinterpret_cast(kernel); - uint32_t zimage_hdr_size = 0; - uint32_t end = z_hdr->end_addr; - if (z_hdr->endianess == 0x01020304) { - // Not supported - fprintf(stderr, "%-*s [%s]\n", PADDING, "ZIMAGE_HDR", "big-endian"); - } - else if (z_hdr->endianess == 0x04030201) { - fprintf(stderr, "%-*s [%s]\n", PADDING, "ZIMAGE_HDR", "little-endian"); - uint8_t *gzip_offset = 0; - if ((gzip_offset = (uint8_t *)memmem(kernel, hdr->kernel_size(), GZIP1_MAGIC, 2))) { - zimage_hdr_size = gzip_offset - kernel; - fprintf(stderr, "%-*s [%u]\n", PADDING, "ZIMAGE_HDR_SZ", zimage_hdr_size); - for (uint8_t * end_ptr = kernel + z_hdr->end_addr - 4; end_ptr >= kernel + z_hdr->end_addr - 64; end_ptr -= 4) { - uint32_t tmp_end = *(uint32_t*)end_ptr; - if (z_hdr->end_addr - tmp_end < 0xFF && tmp_end < end) { - end = tmp_end; - } - } - if (end == z_hdr->end_addr) { - LOGW("Could not find end of zImage gzip data\n"); - } - else { - flags[ZIMAGE_KERNEL] = true; - uint32_t gzip_size = end - zimage_hdr_size; - fprintf(stderr, "%-*s [%u]\n", PADDING, "ZIMAGE_GZIP_SZ", gzip_size); - hdr->kernel_size() -= zimage_hdr_size; - z_tail.size = hdr->kernel_size() - gzip_size; - hdr->kernel_size() -= z_tail.size; - kernel += zimage_hdr_size; - z_tail.data = kernel + hdr->kernel_size(); - fprintf(stderr, "%-*s [%u]\n", PADDING, "ZIMAGE_TAIL_SZ", z_tail.size); - k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); + uint32_t end = z_hdr->end_offset; + if (void *gzip_offset = memmem(kernel, hdr->kernel_size(), GZIP1_MAGIC, 2)) { + 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; } } + if (end == z_hdr->end_offset) { + fprintf(stderr, "Could not find end of zImage gzip data\n"); + exit(1); + } else { + flags[ZIMAGE_KERNEL] = true; + z_info.tail = kernel + end; + z_info.tail_sz = hdr->kernel_size() - end; + kernel += z_info.hdr_sz; + hdr->kernel_size() = end - z_info.hdr_sz; + k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); + } + } else { + fprintf(stderr, "Could not find zImage gzip data\n"); + exit(1); } } fprintf(stderr, "%-*s [%s]\n", PADDING, "KERNEL_FMT", fmt2name[k_fmt]); @@ -537,8 +529,8 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { xwrite(fd, boot.k_hdr, sizeof(mtk_hdr)); } if (boot.flags[ZIMAGE_KERNEL]) { - // Copy ZIMAGE headers - xwrite(fd, boot.z_hdr, (uint32_t)((uintptr_t)boot.kernel - (uintptr_t)boot.z_hdr)); + // Copy zImage headers + xwrite(fd, boot.z_hdr, boot.z_info.hdr_sz); } size_t raw_size; if (access(KERNEL_FILE, R_OK) == 0) { @@ -553,17 +545,17 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { } if (boot.flags[ZIMAGE_KERNEL]) { if (hdr->kernel_size() > boot.hdr->kernel_size()) { - LOGW("Recompressed kernel is %d bytes too large, using original kernel\n", hdr->kernel_size() - boot.hdr->kernel_size()); - lseek(fd, -hdr->kernel_size(), SEEK_CUR); - hdr->kernel_size() = xwrite(fd, boot.z_tail.data - boot.hdr->kernel_size(), boot.hdr->kernel_size()); - } - else { + LOGW("Recompressed kernel is too large, using original kernel\n"); + ftruncate(fd, lseek(fd, -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); - xwrite(fd, &raw_size, 4); - hdr->kernel_size() += boot.hdr->kernel_size() - hdr->kernel_size(); + uint32_t sz = raw_size; + xwrite(fd, &sz, sizeof(sz)); + hdr->kernel_size() = boot.hdr->kernel_size(); } - hdr->kernel_size() += (uint32_t)((uintptr_t)boot.kernel - (uintptr_t)boot.z_hdr); - hdr->kernel_size() += xwrite(fd, boot.z_tail.data, boot.z_tail.size); + hdr->kernel_size() += boot.z_info.hdr_sz; + hdr->kernel_size() += xwrite(fd, boot.z_info.tail, boot.z_info.tail_sz); } // kernel dtb diff --git a/native/jni/magiskboot/bootimg.hpp b/native/jni/magiskboot/bootimg.hpp index 14fbf606e..b472d2d31 100644 --- a/native/jni/magiskboot/bootimg.hpp +++ b/native/jni/magiskboot/bootimg.hpp @@ -45,16 +45,11 @@ struct zimage_hdr { uint8_t head[36]; uint32_t magic; /* zImage magic */ uint32_t load_addr; /* absolute load/run zImage address */ - uint32_t end_addr; /* zImage end address */ + uint32_t end_offset; /* zImage end offset */ uint32_t endianess; /* endianess flag */ uint8_t code[]; } __attribute__((packed)); -struct zimage_tail { - uint8_t *data; - uint32_t size; -} __attribute__((packed)); - /************** * AVB Headers **************/ @@ -488,9 +483,20 @@ struct boot_img { mtk_hdr *k_hdr; mtk_hdr *r_hdr; - // ZIMAGE data + // The pointers/values after parse_image + // +---------------+ + // | z_hdr | z_info.hdr_sz + // +---------------+ + // | kernel | hdr->kernel_size() + // +---------------+ + // | z_info.tail | z_info.tail_sz + // +---------------+ zimage_hdr *z_hdr; - zimage_tail z_tail; + struct { + uint32_t hdr_sz; + uint32_t tail_sz = 0; + uint8_t *tail = nullptr; + } z_info; // Pointer to dtb that is embedded in kernel uint8_t *kernel_dtb; diff --git a/native/jni/magiskboot/compress.cpp b/native/jni/magiskboot/compress.cpp index d1b19775d..c8dea2fe1 100644 --- a/native/jni/magiskboot/compress.cpp +++ b/native/jni/magiskboot/compress.cpp @@ -114,129 +114,100 @@ public: explicit gz_encoder(stream_ptr &&base) : gz_strm(ENCODE, std::move(base)) {}; }; -class zopfli_gz_strm : public cpr_stream { +class zopfli_encoder : public cpr_stream { public: - int write(const void *buf, size_t len) override { + ssize_t write(const void *buf, size_t len) override { return len ? write(buf, len, 0) : 0; } - ~zopfli_gz_strm() override { - switch(mode) { - case ENCODE: - write(nullptr, 0, 1); - break; - } + explicit zopfli_encoder(stream_ptr &&base) : cpr_stream(std::move(base)), + zo({}), out(nullptr), outsize(0), bp(0), crcvalue(crc32_z(0L, Z_NULL, 0)), in_read(0) { + ZopfliInitOptions(&zo); + + // Speed things up a bit, this still leads to better compression than zlib + zo.numiterations = 1; + zo.blocksplitting = 0; + + ZOPFLI_APPEND_DATA(31, &out, &outsize); /* ID1 */ + ZOPFLI_APPEND_DATA(139, &out, &outsize); /* ID2 */ + ZOPFLI_APPEND_DATA(8, &out, &outsize); /* CM */ + ZOPFLI_APPEND_DATA(0, &out, &outsize); /* FLG */ + /* MTIME */ + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0, &out, &outsize); + + ZOPFLI_APPEND_DATA(2, &out, &outsize); /* XFL, 2 indicates best compression. */ + ZOPFLI_APPEND_DATA(3, &out, &outsize); /* OS follows Unix conventions. */ } -protected: - enum mode_t { - ENCODE - } mode; - - ZopfliOptions zo; - - zopfli_gz_strm(mode_t mode, stream_ptr &&base) : - cpr_stream(std::move(base)), mode(mode), out(nullptr), outsize(0), bp(0), crcvalue(0xffffffffu), in_read(0) { - switch(mode) { - case ENCODE: - out = 0; - outsize = 0; - bp = 0; - crcvalue = crc32_z(0L, Z_NULL, 0); - - ZopfliInitOptions(&zo); - - // Speed things up a bit, this still leads to better compression than zlib - zo.numiterations = 1; - zo.blocksplitting = 0; - - ZOPFLI_APPEND_DATA(31, &out, &outsize); /* ID1 */ - ZOPFLI_APPEND_DATA(139, &out, &outsize); /* ID2 */ - ZOPFLI_APPEND_DATA(8, &out, &outsize); /* CM */ - ZOPFLI_APPEND_DATA(0, &out, &outsize); /* FLG */ - /* MTIME */ - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0, &out, &outsize); - - ZOPFLI_APPEND_DATA(2, &out, &outsize); /* XFL, 2 indicates best compression. */ - ZOPFLI_APPEND_DATA(3, &out, &outsize); /* OS follows Unix conventions. */ - break; - } + ~zopfli_encoder() override { + write(nullptr, 0, 1); } private: - unsigned char* out = nullptr; - size_t outsize = 0; - unsigned char bp = 0; - unsigned long crcvalue = 0xffffffffu; - uint32_t in_read = 0; + ZopfliOptions zo; + unsigned char *out; + size_t outsize; + unsigned char bp; + unsigned long crcvalue; + uint32_t in_read; - int write(const void *buf, size_t len, int flush) { - int ret = 0; - switch(mode) { - case ENCODE: - in_read += len; - if (len) - crcvalue = crc32_z(crcvalue, (Bytef *)buf, len); - if (flush) { - ZopfliDeflate(&zo, 2, 1, (const unsigned char *)buf, len, &bp, &out, &outsize); + ssize_t write(const void *buf, size_t len, int flush) { + ssize_t ret = 0; + in_read += len; + if (len) + crcvalue = crc32_z(crcvalue, (Bytef *)buf, len); + if (flush) { + ZopfliDeflate(&zo, 2, 1, (const unsigned char *)buf, len, &bp, &out, &outsize); - /* CRC */ - ZOPFLI_APPEND_DATA(crcvalue % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((crcvalue >> 8) % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((crcvalue >> 16) % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((crcvalue >> 24) % 256, &out, &outsize); + /* CRC */ + ZOPFLI_APPEND_DATA(crcvalue % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((crcvalue >> 8) % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((crcvalue >> 16) % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((crcvalue >> 24) % 256, &out, &outsize); - /* ISIZE */ - ZOPFLI_APPEND_DATA(in_read % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((in_read >> 8) % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((in_read >> 16) % 256, &out, &outsize); - ZOPFLI_APPEND_DATA((in_read >> 24) % 256, &out, &outsize); - ret += bwrite(out, outsize); - free(out); - out = nullptr; - bp = 0; - outsize = 0; + /* ISIZE */ + ZOPFLI_APPEND_DATA(in_read % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((in_read >> 8) % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((in_read >> 16) % 256, &out, &outsize); + ZOPFLI_APPEND_DATA((in_read >> 24) % 256, &out, &outsize); + ret += bwrite(out, outsize); + free(out); + out = nullptr; + bp = 0; + outsize = 0; + } else { + for (size_t offset = 0; offset < len; offset += ZOPFLI_CHUNK) { + ZopfliDeflatePart(&zo, 2, 0, (const unsigned char *)buf, offset, offset + ((len - offset) < ZOPFLI_CHUNK ? len - offset : ZOPFLI_CHUNK), &bp, &out, &outsize); + bp &= 7; + if (bp & 1) { + if (bp == 7) + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0, &out, &outsize); + ZOPFLI_APPEND_DATA(0xff, &out, &outsize); + ZOPFLI_APPEND_DATA(0xff, &out, &outsize); + } else if (bp) { + do { + out[outsize - 1] += 2 << bp; + ZOPFLI_APPEND_DATA(0, &out, &outsize); + bp += 2; + } while (bp < 8); } - else { - for(size_t offset = 0; offset < len; offset += ZOPFLI_CHUNK) { - ZopfliDeflatePart(&zo, 2, 0, (const unsigned char *)buf, offset, offset + ((len - offset) < ZOPFLI_CHUNK ? len - offset : ZOPFLI_CHUNK), &bp, &out, &outsize); - bp &= 7; - if (bp & 1) { - if (bp == 7) - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0, &out, &outsize); - ZOPFLI_APPEND_DATA(0xff, &out, &outsize); - ZOPFLI_APPEND_DATA(0xff, &out, &outsize); - } - else if (bp) { - do { - out[outsize - 1] += 2 << bp; - ZOPFLI_APPEND_DATA(0, &out, &outsize); - bp += 2; - } while (bp < 8); - } - ret += bwrite(out, outsize); - free(out); - out = nullptr; - bp = 0; - outsize = 0; - } - } - return ret; + ret += bwrite(out, outsize); + free(out); + out = nullptr; + bp = 0; + outsize = 0; + } } + return ret; } }; -class zopfli_gz_encoder : public zopfli_gz_strm { -public: - explicit zopfli_gz_encoder(stream_ptr &&base) : zopfli_gz_strm(ENCODE, std::move(base)) {}; -}; - class bz_strm : public cpr_stream { public: ssize_t write(const void *buf, size_t len) override { @@ -666,7 +637,7 @@ stream_ptr get_encoder(format_t type, stream_ptr &&base) { case LZ4_LG: return make_unique(std::move(base), true); case GZIP: - return make_unique(std::move(base)); + return make_unique(std::move(base)); default: return make_unique(std::move(base)); }