diff --git a/native/jni/magiskboot/bootimg.cpp b/native/jni/magiskboot/bootimg.cpp index 1f3f438ac..abee0318d 100644 --- a/native/jni/magiskboot/bootimg.cpp +++ b/native/jni/magiskboot/bootimg.cpp @@ -54,10 +54,6 @@ static size_t restore(int fd, const char *filename) { return size; } -static void restore_buf(int fd, const void *buf, size_t size) { - xwrite(fd, buf, size); -} - void dyn_img_hdr::print() { uint32_t ver = header_version(); fprintf(stderr, "%-*s [%u]\n", PADDING, "HEADER_VER", ver); @@ -250,6 +246,8 @@ off += hdr->name##_size(); \ off = do_align(off, hdr->page_size()); \ } +#define CMD_MATCH(s) BUFFER_MATCH(hp->cmdline, s) + void boot_img::parse_image(uint8_t *addr, format_t type) { auto hp = reinterpret_cast(addr); if (type == AOSP_VENDOR) { @@ -259,11 +257,11 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { fprintf(stderr, "PXA_BOOT_HDR\n"); hdr = new dyn_img_pxa(addr); } else { - if (memcmp(hp->cmdline, NOOKHD_RL_MAGIC, 10) == 0 || - memcmp(hp->cmdline, NOOKHD_GL_MAGIC, 12) == 0 || - memcmp(hp->cmdline, NOOKHD_GR_MAGIC, 14) == 0 || - memcmp(hp->cmdline, NOOKHD_EB_MAGIC, 26) == 0 || - memcmp(hp->cmdline, NOOKHD_ER_MAGIC, 30) == 0) { + 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; @@ -309,18 +307,6 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { get_block(recovery_dtbo); get_block(dtb); - if (addr + off < map_addr + map_size) { - tail = addr + off; - tail_size = map_size - (tail - map_addr); - } - - // Check tail info - if (tail_size >= 16 && memcmp(tail, SEANDROID_MAGIC, 16) == 0) { - flags[SEANDROID_FLAG] = true; - } else if (tail_size >= 16 && memcmp(tail, LG_BUMP_MAGIC, 16) == 0) { - flags[LG_BUMP_FLAG] = true; - } - 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; @@ -334,7 +320,7 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { fprintf(stderr, "MTK_KERNEL_HDR\n"); flags[MTK_KERNEL] = true; k_hdr = reinterpret_cast(kernel); - fprintf(stderr, "%-*s [%u]\n", PADDING, "KERNEL", k_hdr->size); + fprintf(stderr, "%-*s [%u]\n", PADDING, "SIZE", k_hdr->size); fprintf(stderr, "%-*s [%s]\n", PADDING, "NAME", k_hdr->name); kernel += sizeof(mtk_hdr); hdr->kernel_size() -= sizeof(mtk_hdr); @@ -348,7 +334,7 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { fprintf(stderr, "MTK_RAMDISK_HDR\n"); flags[MTK_RAMDISK] = true; r_hdr = reinterpret_cast(ramdisk); - fprintf(stderr, "%-*s [%u]\n", PADDING, "RAMDISK", r_hdr->size); + fprintf(stderr, "%-*s [%u]\n", PADDING, "SIZE", r_hdr->size); fprintf(stderr, "%-*s [%s]\n", PADDING, "NAME", r_hdr->name); ramdisk += sizeof(mtk_hdr); hdr->ramdisk_size() -= sizeof(mtk_hdr); @@ -360,6 +346,33 @@ void boot_img::parse_image(uint8_t *addr, format_t type) { e_fmt = check_fmt_lg(extra, size); fprintf(stderr, "%-*s [%s]\n", PADDING, "EXTRA_FMT", fmt2name[e_fmt]); } + + if (addr + off < map_addr + map_size) { + tail = addr + off; + tail_size = map_addr + map_size - tail; + + // Check special flags + if (tail_size >= 16 && BUFFER_MATCH(tail, SEANDROID_MAGIC)) { + fprintf(stderr, "SAMSUNG_SEANDROID\n"); + flags[SEANDROID_FLAG] = true; + } else if (tail_size >= 16 && BUFFER_MATCH(tail, LG_BUMP_MAGIC)) { + fprintf(stderr, "LG_BUMP_IMAGE\n"); + flags[LG_BUMP_FLAG] = true; + } + + // Find AVB structures + void *meta = memmem(tail, tail_size, AVB_MAGIC, AVB_MAGIC_LEN); + if (meta) { + // Double check if footer exists + void *footer = tail + tail_size - sizeof(AvbFooter); + if (BUFFER_MATCH(footer, AVB_FOOTER_MAGIC)) { + fprintf(stderr, "VBMETA\n"); + flags[AVB_FLAG] = true; + avb_meta = reinterpret_cast(meta); + avb_footer = reinterpret_cast(footer); + } + } + } } int split_image_dtb(const char *filename) { @@ -448,6 +461,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { uint32_t extra; uint32_t dtb; uint32_t total; + uint32_t vbmeta; } off{}; // Create a new boot header and reset sizes @@ -472,22 +486,22 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { // Skip DHTB header write_zero(fd, sizeof(dhtb_hdr)); } else if (boot.flags[BLOB_FLAG]) { - restore_buf(fd, boot.map_addr, sizeof(blob_hdr)); + xwrite(fd, boot.map_addr, sizeof(blob_hdr)); } else if (boot.flags[NOOKHD_FLAG]) { - restore_buf(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ); + xwrite(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ); } else if (boot.flags[ACCLAIM_FLAG]) { - restore_buf(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ); + xwrite(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ); } // Copy raw header off.header = lseek(fd, 0, SEEK_CUR); - restore_buf(fd, boot.hdr_addr, hdr->hdr_space()); + xwrite(fd, boot.hdr_addr, hdr->hdr_space()); // kernel off.kernel = lseek(fd, 0, SEEK_CUR); if (boot.flags[MTK_KERNEL]) { // Copy MTK headers - restore_buf(fd, boot.k_hdr, sizeof(mtk_hdr)); + xwrite(fd, boot.k_hdr, sizeof(mtk_hdr)); } if (access(KERNEL_FILE, R_OK) == 0) { size_t raw_size; @@ -510,7 +524,7 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { off.ramdisk = lseek(fd, 0, SEEK_CUR); if (boot.flags[MTK_RAMDISK]) { // Copy MTK headers - restore_buf(fd, boot.r_hdr, sizeof(mtk_hdr)); + xwrite(fd, boot.r_hdr, sizeof(mtk_hdr)); } if (access(RAMDISK_FILE, R_OK) == 0) { size_t raw_size; @@ -561,21 +575,31 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { file_align(); } - // Append tail info + // Proprietary stuffs 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); + xwrite(fd, SEANDROID_MAGIC, 16); + if (boot.flags[DHTB_FLAG]) { + xwrite(fd, "\xFF\xFF\xFF\xFF", 4); + } + } else if (boot.flags[LG_BUMP_FLAG]) { + xwrite(fd, LG_BUMP_MAGIC, 16); } off.total = lseek(fd, 0, SEEK_CUR); + file_align(); - // Pad image to at least original size if not chromeos (as it requires post processing) + // vbmeta + off.vbmeta = lseek(fd, 0, SEEK_CUR); + if (boot.flags[AVB_FLAG]) { + uint64_t vbmeta_size = __builtin_bswap64(boot.avb_footer->vbmeta_size); + xwrite(fd, boot.avb_meta, vbmeta_size); + } + + // Pad image to original size if not chromeos (as it requires post processing) if (!boot.flags[CHROMEOS_FLAG]) { - if (off.total < boot.map_size) { - int padding = boot.map_size - off.total; - write_zero(fd, padding); + off_t current = lseek(fd, 0, SEEK_CUR); + if (current < boot.map_size) { + write_zero(fd, boot.map_size - current); } } @@ -644,6 +668,16 @@ void repack(const char *src_img, const char *out_img, bool skip_comp) { // Copy main header memcpy(new_addr + off.header, hdr->raw_hdr(), hdr->hdr_size()); + if (boot.flags[AVB_FLAG]) { + // Copy and patch AVB structures + auto footer = reinterpret_cast(new_addr + new_size - sizeof(AvbFooter)); + auto vbmeta = reinterpret_cast(new_addr + off.vbmeta); + memcpy(footer, boot.avb_footer, sizeof(AvbFooter)); + footer->original_image_size = __builtin_bswap64(off.total); + footer->vbmeta_offset = __builtin_bswap64(off.vbmeta); + vbmeta->flags = __builtin_bswap32(3); + } + if (boot.flags[DHTB_FLAG]) { // DHTB header auto d_hdr = reinterpret_cast(new_addr); diff --git a/native/jni/magiskboot/bootimg.hpp b/native/jni/magiskboot/bootimg.hpp index ea2288874..3f7b3bfd3 100644 --- a/native/jni/magiskboot/bootimg.hpp +++ b/native/jni/magiskboot/bootimg.hpp @@ -41,6 +41,49 @@ struct blob_hdr { uint32_t version; /* 0x00000001 */ } __attribute__((packed)); +/************** + * AVB Headers + **************/ + +#define AVB_FOOTER_MAGIC_LEN 4 +#define AVB_MAGIC_LEN 4 +#define AVB_RELEASE_STRING_SIZE 48 + +// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_footer.h +struct AvbFooter { + uint8_t magic[AVB_FOOTER_MAGIC_LEN]; + uint32_t version_major; + uint32_t version_minor; + uint64_t original_image_size; + uint64_t vbmeta_offset; + uint64_t vbmeta_size; + uint8_t reserved[28]; +} __attribute__((packed)); + +// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_vbmeta_image.h +struct AvbVBMetaImageHeader { + uint8_t magic[AVB_MAGIC_LEN]; + uint32_t required_libavb_version_major; + uint32_t required_libavb_version_minor; + uint64_t authentication_data_block_size; + uint64_t auxiliary_data_block_size; + uint32_t algorithm_type; + uint64_t hash_offset; + uint64_t hash_size; + uint64_t signature_offset; + uint64_t signature_size; + uint64_t public_key_offset; + uint64_t public_key_size; + uint64_t public_key_metadata_offset; + uint64_t public_key_metadata_size; + uint64_t descriptors_offset; + uint64_t descriptors_size; + uint64_t rollback_index; + uint32_t flags; + uint32_t rollback_index_location; + uint8_t release_string[AVB_RELEASE_STRING_SIZE]; + uint8_t reserved[80]; +} __attribute__((packed)); /********************* * Boot Image Headers @@ -402,6 +445,7 @@ enum { BLOB_FLAG, NOOKHD_FLAG, ACCLAIM_FLAG, + AVB_FLAG, BOOT_FLAGS_MAX }; @@ -436,6 +480,10 @@ struct boot_img { uint8_t *tail; size_t tail_size = 0; + // AVB structs + AvbFooter *avb_footer; + AvbVBMetaImageHeader *avb_meta; + // Pointers to blocks defined in header uint8_t *hdr_addr; uint8_t *kernel; diff --git a/native/jni/magiskboot/dtb.cpp b/native/jni/magiskboot/dtb.cpp index 59811dffb..24bbbad45 100644 --- a/native/jni/magiskboot/dtb.cpp +++ b/native/jni/magiskboot/dtb.cpp @@ -8,6 +8,7 @@ #include "magiskboot.hpp" #include "dtb.hpp" +#include "format.hpp" extern "C" { #include } @@ -105,7 +106,7 @@ static void dtb_print(const char *file, bool fstab) { int dtb_num = 0; uint8_t * const end = dtb + size; for (uint8_t *fdt = dtb; fdt < end;) { - fdt = static_cast(memmem(fdt, end - fdt, FDT_MAGIC_STR, sizeof(fdt32_t))); + fdt = static_cast(memmem(fdt, end - fdt, DTB_MAGIC, sizeof(fdt32_t))); if (fdt == nullptr) break; if (fstab) { @@ -139,7 +140,7 @@ static bool dtb_patch(const char *file) { bool patched = false; uint8_t * const end = dtb + size; for (uint8_t *fdt = dtb; fdt < end;) { - fdt = static_cast(memmem(fdt, end - fdt, FDT_MAGIC_STR, sizeof(fdt32_t))); + fdt = static_cast(memmem(fdt, end - fdt, DTB_MAGIC, sizeof(fdt32_t))); if (fdt == nullptr) break; if (int fstab = find_fstab(fdt); fstab >= 0) { @@ -316,7 +317,7 @@ static bool blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) { uint8_t * const end = dtb + dtb_sz; for (uint8_t *curr = dtb; curr < end;) { - curr = static_cast(memmem(curr, end - curr, FDT_MAGIC_STR, sizeof(fdt32_t))); + curr = static_cast(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t))); if (curr == nullptr) break; auto len = fdt_totalsize(curr); @@ -355,10 +356,10 @@ static bool blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) { return true; } -#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0) +#define DTB_MATCH(s) BUFFER_MATCH(dtb, s) static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { - if (MATCH(QCDT_MAGIC)) { + if (DTB_MATCH(QCDT_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 1: @@ -373,7 +374,7 @@ static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { default: return false; } - } else if (MATCH(DTBH_MAGIC)) { + } else if (DTB_MATCH(DTBH_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 2: @@ -382,7 +383,7 @@ static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { default: return false; } - } else if (MATCH(PXADT_MAGIC)) { + } else if (DTB_MATCH(PXADT_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 1: @@ -391,7 +392,7 @@ static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { default: return false; } - } else if (MATCH(PXA19xx_MAGIC)) { + } else if (DTB_MATCH(PXA19xx_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 1: @@ -400,7 +401,7 @@ static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { default: return false; } - } else if (MATCH(SPRD_MAGIC)) { + } else if (DTB_MATCH(SPRD_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 1: @@ -409,7 +410,7 @@ static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { default: return false; } - } else if (MATCH(DT_TABLE_MAGIC)) { + } else if (DTB_MATCH(DT_TABLE_MAGIC)) { auto hdr = reinterpret_cast(dtb); switch (hdr->version) { case 0: diff --git a/native/jni/magiskboot/dtb.hpp b/native/jni/magiskboot/dtb.hpp index ce2b0d71e..7d2689424 100644 --- a/native/jni/magiskboot/dtb.hpp +++ b/native/jni/magiskboot/dtb.hpp @@ -2,7 +2,6 @@ #include -#define FDT_MAGIC_STR "\xd0\x0d\xfe\xed" #define DT_TABLE_MAGIC "\xd7\xb7\xab\x1e" #define QCDT_MAGIC "QCDT" #define DTBH_MAGIC "DTBH" diff --git a/native/jni/magiskboot/format.cpp b/native/jni/magiskboot/format.cpp index b38414209..0fc9d2e13 100644 --- a/native/jni/magiskboot/format.cpp +++ b/native/jni/magiskboot/format.cpp @@ -21,37 +21,37 @@ public: static FormatInit init; -#define MATCH(s) (len >= (sizeof(s) - 1) && memcmp(buf, s, sizeof(s) - 1) == 0) +#define CHECKED_MATCH(s) (len >= (sizeof(s) - 1) && BUFFER_MATCH(buf, s)) format_t check_fmt(const void *buf, size_t len) { - if (MATCH(CHROMEOS_MAGIC)) { + if (CHECKED_MATCH(CHROMEOS_MAGIC)) { return CHROMEOS; - } else if (MATCH(BOOT_MAGIC)) { + } else if (CHECKED_MATCH(BOOT_MAGIC)) { return AOSP; - } else if (MATCH(VENDOR_BOOT_MAGIC)) { + } else if (CHECKED_MATCH(VENDOR_BOOT_MAGIC)) { return AOSP_VENDOR; - } else if (MATCH(GZIP1_MAGIC) || MATCH(GZIP2_MAGIC)) { + } else if (CHECKED_MATCH(GZIP1_MAGIC) || CHECKED_MATCH(GZIP2_MAGIC)) { return GZIP; - } else if (MATCH(LZOP_MAGIC)) { + } else if (CHECKED_MATCH(LZOP_MAGIC)) { return LZOP; - } else if (MATCH(XZ_MAGIC)) { + } else if (CHECKED_MATCH(XZ_MAGIC)) { return XZ; } else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0 && (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) { return LZMA; - } else if (MATCH(BZIP_MAGIC)) { + } else if (CHECKED_MATCH(BZIP_MAGIC)) { return BZIP2; - } else if (MATCH(LZ41_MAGIC) || MATCH(LZ42_MAGIC)) { + } else if (CHECKED_MATCH(LZ41_MAGIC) || CHECKED_MATCH(LZ42_MAGIC)) { return LZ4; - } else if (MATCH(LZ4_LEG_MAGIC)) { + } else if (CHECKED_MATCH(LZ4_LEG_MAGIC)) { return LZ4_LEGACY; - } else if (MATCH(MTK_MAGIC)) { + } else if (CHECKED_MATCH(MTK_MAGIC)) { return MTK; - } else if (MATCH(DTB_MAGIC)) { + } else if (CHECKED_MATCH(DTB_MAGIC)) { return DTB; - } else if (MATCH(DHTB_MAGIC)) { + } else if (CHECKED_MATCH(DHTB_MAGIC)) { return DHTB; - } else if (MATCH(TEGRABLOB_MAGIC)) { + } else if (CHECKED_MATCH(TEGRABLOB_MAGIC)) { return BLOB; } else { return UNKNOWN; diff --git a/native/jni/magiskboot/format.hpp b/native/jni/magiskboot/format.hpp index 3d7c641f1..da0f3cbb6 100644 --- a/native/jni/magiskboot/format.hpp +++ b/native/jni/magiskboot/format.hpp @@ -29,6 +29,8 @@ typedef enum { #define COMPRESSED(fmt) ((fmt) >= GZIP && (fmt) < LZOP) #define COMPRESSED_ANY(fmt) ((fmt) >= GZIP && (fmt) <= LZOP) +#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0) + #define BOOT_MAGIC "ANDROID!" #define VENDOR_BOOT_MAGIC "VNDRBOOT" #define CHROMEOS_MAGIC "CHROMEOS" @@ -54,6 +56,8 @@ typedef enum { #define NOOKHD_PRE_HEADER_SZ 1048576 #define ACCLAIM_MAGIC "BauwksBoot" #define ACCLAIM_PRE_HEADER_SZ 262144 +#define AVB_FOOTER_MAGIC "AVBf" +#define AVB_MAGIC "AVB0" class Fmt2Name { public: diff --git a/native/jni/magiskboot/pattern.cpp b/native/jni/magiskboot/pattern.cpp index 240915fd5..a56d16762 100644 --- a/native/jni/magiskboot/pattern.cpp +++ b/native/jni/magiskboot/pattern.cpp @@ -5,18 +5,18 @@ #include "magiskboot.hpp" -#define MATCH(p) else if (strncmp(s + skip, p, sizeof(p) - 1) == 0) skip += (sizeof(p) - 1) +#define CHECKED_MATCH(p) else if (strncmp(s + skip, p, sizeof(p) - 1) == 0) skip += (sizeof(p) - 1) static int check_verity_pattern(const char *s) { int skip = s[0] == ','; if (0) {} - MATCH("verifyatboot"); - MATCH("verify"); - MATCH("avb_keys"); - MATCH("avb"); - MATCH("support_scfs"); - MATCH("fsverity"); + CHECKED_MATCH("verifyatboot"); + CHECKED_MATCH("verify"); + CHECKED_MATCH("avb_keys"); + CHECKED_MATCH("avb"); + CHECKED_MATCH("support_scfs"); + CHECKED_MATCH("fsverity"); else return -1; if (s[skip] == '=') { @@ -26,14 +26,14 @@ static int check_verity_pattern(const char *s) { return skip; } -#undef MATCH -#define MATCH(p) else if (strncmp(s, p, sizeof(p) - 1) == 0) return (sizeof(p) - 1) +#undef CHECKED_MATCH +#define CHECKED_MATCH(p) else if (strncmp(s, p, sizeof(p) - 1) == 0) return (sizeof(p) - 1) static int check_encryption_pattern(const char *s) { if (0) {} - MATCH("forceencrypt"); - MATCH("forcefdeorfbe"); - MATCH("fileencryption"); + CHECKED_MATCH("forceencrypt"); + CHECKED_MATCH("forcefdeorfbe"); + CHECKED_MATCH("fileencryption"); else return -1; }