From 8d7c7c3dfb03c3d17f0b0aee50160710dc6e993a Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 19 Sep 2023 00:12:49 -0700 Subject: [PATCH] Refactor dtb in rust --- .gitmodules | 3 - native/src/Android.mk | 2 - native/src/Cargo.lock | 39 +-- native/src/Cargo.toml | 1 + native/src/boot/Cargo.toml | 1 + native/src/boot/bootimg.cpp | 53 +++- native/src/boot/dtb.cpp | 452 --------------------------------- native/src/boot/dtb.hpp | 103 -------- native/src/boot/dtb.rs | 316 +++++++++++++++++++++++ native/src/boot/lib.rs | 14 +- native/src/boot/main.cpp | 20 +- native/src/boot/ramdisk.rs | 7 +- native/src/external/Android.mk | 17 -- native/src/external/dtc | 1 - 14 files changed, 403 insertions(+), 626 deletions(-) delete mode 100644 native/src/boot/dtb.cpp delete mode 100644 native/src/boot/dtb.hpp create mode 100644 native/src/boot/dtb.rs delete mode 160000 native/src/external/dtc diff --git a/.gitmodules b/.gitmodules index 209276091..191ffd656 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "busybox"] path = native/src/external/busybox url = https://github.com/topjohnwu/ndk-busybox.git -[submodule "dtc"] - path = native/src/external/dtc - url = https://github.com/dgibson/dtc.git [submodule "lz4"] path = native/src/external/lz4 url = https://github.com/lz4/lz4.git diff --git a/native/src/Android.mk b/native/src/Android.mk index 9f49efd88..0b7ef2d60 100644 --- a/native/src/Android.mk +++ b/native/src/Android.mk @@ -99,7 +99,6 @@ LOCAL_STATIC_LIBRARIES := \ liblzma \ liblz4 \ libbz2 \ - libfdt \ libz \ libzopfli \ libboot-rs @@ -109,7 +108,6 @@ LOCAL_SRC_FILES := \ boot/bootimg.cpp \ boot/compress.cpp \ boot/format.cpp \ - boot/dtb.cpp \ boot/boot-rs.cpp include $(BUILD_EXECUTABLE) diff --git a/native/src/Cargo.lock b/native/src/Cargo.lock index 23998ee5d..79b81f325 100644 --- a/native/src/Cargo.lock +++ b/native/src/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" dependencies = [ "memchr", ] @@ -324,6 +324,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fdt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" + [[package]] name = "ff" version = "0.13.0" @@ -336,9 +342,9 @@ dependencies = [ [[package]] name = "flagset" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" [[package]] name = "generic-array" @@ -420,9 +426,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libm" @@ -461,6 +467,7 @@ dependencies = [ "cxx-gen", "der", "digest", + "fdt", "p256", "p384", "pb-rs", @@ -654,9 +661,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -883,9 +890,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.31" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -894,9 +901,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] @@ -932,15 +939,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" diff --git a/native/src/Cargo.toml b/native/src/Cargo.toml index 84f5322cd..0aef4317f 100644 --- a/native/src/Cargo.toml +++ b/native/src/Cargo.toml @@ -22,6 +22,7 @@ rsa = "0.9" x509-cert = "0.2" der = "0.7" bytemuck = "1.14" +fdt = "0.1" [workspace.dependencies.argh] git = "https://github.com/topjohnwu/argh.git" diff --git a/native/src/boot/Cargo.toml b/native/src/boot/Cargo.toml index bcf3b258f..5034c6c65 100644 --- a/native/src/boot/Cargo.toml +++ b/native/src/boot/Cargo.toml @@ -26,3 +26,4 @@ p384 = { workspace = true } rsa = { workspace = true, features = ["sha2"] } x509-cert = { workspace = true } der = { workspace = true, features = ["derive"] } +fdt = { workspace = true } diff --git a/native/src/boot/bootimg.cpp b/native/src/boot/bootimg.cpp index a539c80f6..170b8df4b 100644 --- a/native/src/boot/bootimg.cpp +++ b/native/src/boot/bootimg.cpp @@ -1,7 +1,7 @@ +#include #include #include -#include #include #include "boot-rs.hpp" @@ -183,29 +183,70 @@ boot_img::~boot_img() { delete hdr; } +struct [[gnu::packed]] fdt_header { + struct fdt32_t { + uint32_t byte0: 8; + uint32_t byte1: 8; + uint32_t byte2: 8; + uint32_t byte3: 8; + + constexpr operator uint32_t() const { + return bit_cast(fdt32_t { + .byte0 = byte3, + .byte1 = byte2, + .byte2 = byte1, + .byte3 = byte0 + }); + } + }; + + struct node_header { + fdt32_t tag; + char name[0]; + }; + + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ +}; + + static int find_dtb_offset(const uint8_t *buf, unsigned sz) { const uint8_t * const end = buf + sz; for (auto curr = buf; curr < end; curr += sizeof(fdt_header)) { - curr = static_cast(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t))); + curr = static_cast(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt_header::fdt32_t))); if (curr == nullptr) return -1; auto fdt_hdr = reinterpret_cast(curr); // Check that fdt_header.totalsize does not overflow kernel image size - uint32_t totalsize = fdt32_to_cpu(fdt_hdr->totalsize); + uint32_t totalsize = fdt_hdr->totalsize; if (totalsize > end - curr) continue; // Check that fdt_header.off_dt_struct does not overflow kernel image size - uint32_t off_dt_struct = fdt32_to_cpu(fdt_hdr->off_dt_struct); + uint32_t off_dt_struct = fdt_hdr->off_dt_struct; if (off_dt_struct > end - curr) continue; // Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE - auto fdt_node_hdr = reinterpret_cast(curr + off_dt_struct); - if (fdt32_to_cpu(fdt_node_hdr->tag) != FDT_BEGIN_NODE) + auto fdt_node_hdr = reinterpret_cast(curr + off_dt_struct); + if (fdt_node_hdr->tag != 0x1u) continue; return curr - buf; diff --git a/native/src/boot/dtb.cpp b/native/src/boot/dtb.cpp deleted file mode 100644 index d648a9016..000000000 --- a/native/src/boot/dtb.cpp +++ /dev/null @@ -1,452 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "magiskboot.hpp" -#include "dtb.hpp" -#include "format.hpp" -#include "boot-rs.hpp" - -using namespace std; - -constexpr int MAX_DEPTH = 32; -static bitset depth_set; - -static void pretty_node(int depth) { - if (depth == 0) - return; - - for (int i = 0; i < depth - 1; ++i) - printf(depth_set[i] ? "│ " : " "); - - printf(depth_set[depth - 1] ? "├── " : "└── "); -} - -static void pretty_prop(int depth) { - for (int i = 0; i < depth; ++i) - printf(depth_set[i] ? "│ " : " "); - - printf(depth_set[depth] ? "│ " : " "); -} - -static void print_node(const void *fdt, int node = 0, int depth = 0) { - // Print node itself - pretty_node(depth); - printf("#%d: %s\n", node, fdt_get_name(fdt, node, nullptr)); - - // Print properties - depth_set[depth] = fdt_first_subnode(fdt, node) >= 0; - int prop; - fdt_for_each_property_offset(prop, fdt, node) { - pretty_prop(depth); - int size; - const char *name; - auto value = static_cast(fdt_getprop_by_offset(fdt, prop, &name, &size)); - - bool is_str = !(size > 1 && value[0] == 0); - if (is_str) { - // Scan through value to see if printable - for (int i = 0; i < size; ++i) { - char c = value[i]; - if (i == size - 1) { - // Make sure null terminate - is_str = c == '\0'; - } else if ((c > 0 && c < 32) || c >= 127) { - is_str = false; - break; - } - } - } - - if (is_str) { - printf("[%s]: [%s]\n", name, value); - } else { - printf("[%s]: (%d)\n", name, size); - } - } - - // Recursive - if (depth_set[depth]) { - int child; - int prev = -1; - fdt_for_each_subnode(child, fdt, node) { - if (prev >= 0) - print_node(fdt, prev, depth + 1); - prev = child; - } - depth_set[depth] = false; - print_node(fdt, prev, depth + 1); - } -} - -static int find_fstab(const void *fdt, int node = 0) { - if (auto name = fdt_get_name(fdt, node, nullptr); name && name == "fstab"sv) - return node; - int child; - fdt_for_each_subnode(child, fdt, node) { - int fstab = find_fstab(fdt, child); - if (fstab >= 0) - return fstab; - } - return -1; -} - -template -static void for_each_fdt(const char *file, bool rw, Func fn) { - mmap_data m(file, rw); - uint8_t *end = m.buf() + m.sz(); - for (uint8_t *fdt = m.buf(); fdt < end;) { - fdt = static_cast(memmem(fdt, end - fdt, DTB_MAGIC, sizeof(fdt32_t))); - if (fdt == nullptr) - break; - fn(fdt); - fdt += fdt_totalsize(fdt); - } -} - -static void dtb_print(const char *file, bool fstab) { - fprintf(stderr, "Loading dtbs from [%s]\n", file); - int dtb_num = 0; - for_each_fdt(file, false, [&](uint8_t *fdt) { - if (fstab) { - if (int node = find_fstab(fdt); node >= 0) { - fprintf(stderr, "Found fstab in dtb.%04d\n", dtb_num); - print_node(fdt, node); - } - } else { - fprintf(stderr, "Printing dtb.%04d\n", dtb_num); - print_node(fdt); - } - ++dtb_num; - }); - fprintf(stderr, "\n"); -} - -static bool dtb_patch(const char *file) { - fprintf(stderr, "Loading dtbs from [%s]\n", file); - - bool keep_verity = check_env("KEEPVERITY"); - bool patched = false; - for_each_fdt(file, true, [&](uint8_t *fdt) { - int node; - // Patch the chosen node for bootargs - fdt_for_each_subnode(node, fdt, 0) { - if (auto name = fdt_get_name(fdt, node, nullptr); !name || name != "chosen"sv) - continue; - int len; - if (auto value = fdt_getprop(fdt, node, "bootargs", &len)) { - if (void *skip = memmem(value, len, "skip_initramfs", 14)) { - fprintf(stderr, "Patch [skip_initramfs] -> [want_initramfs]\n"); - memcpy(skip, "want", 4); - patched = true; - } - } - break; - } - if (!keep_verity) { - if (int fstab = find_fstab(fdt); fstab >= 0) { - fdt_for_each_subnode(node, fdt, fstab) { - int len; - char *value = (char *) fdt_getprop(fdt, node, "fsmgr_flags", &len); - byte_data data(value, len); - patched |= (patch_verity(data) != len); - } - } - } - }); - return patched; -} - -[[noreturn]] -static void dtb_test(const char *file) { - for_each_fdt(file, false, [&](uint8_t *fdt) { - // Find the system node in fstab - if (int fstab = find_fstab(fdt); fstab >= 0) { - int node; - fdt_for_each_subnode(node, fdt, fstab) { - if (auto name = fdt_get_name(fdt, node, nullptr); !name || name != "system"sv) - continue; - int len; - if (auto value = fdt_getprop(fdt, node, "mnt_point", &len)) { - // If mnt_point is set to /system_root, abort! - if (strncmp(static_cast(value), "/system_root", len) == 0) { - exit(1); - } - } - } - } - }); - exit(0); -} - -int dtb_commands(int argc, char *argv[]) { - char *dtb = argv[0]; - ++argv; - --argc; - - if (argv[0] == "print"sv) { - dtb_print(dtb, argc > 1 && argv[1] == "-f"sv); - return 0; - } else if (argv[0] == "patch"sv) { - if (!dtb_patch(dtb)) - exit(1); - return 0; - } else if (argv[0] == "test"sv) { - dtb_test(dtb); - } else { - return 1; - } -} - -// The following code is unused, left here for historical purpose. Since the code is -// extremely complicated, I won't want to rewrite this whole thing if somehow we need -// to use it in the future... - -namespace { - -struct fdt_blob { - void *fdt; - uint32_t offset; - uint32_t len; -}; - -static bool fdt_patch(void *fdt) { - int fstab = find_fstab(fdt); - if (fstab < 0) - return false; - bool modified = false; - int node; - fdt_for_each_subnode(node, fdt, fstab) { - const char *name = fdt_get_name(fdt, node, nullptr); - // Force remove AVB for 2SI since it may bootloop some devices - int len; - const void *value = fdt_getprop(fdt, node, "fsmgr_flags", &len); - heap_data copy = byte_view(value, len).clone(); - auto patched_sz = patch_verity(copy); - if (patched_sz != len) { - modified = true; - fdt_setprop(fdt, node, "fsmgr_flags", copy.buf(), patched_sz); - } - if (name == "system"sv) { - fprintf(stderr, "Setting [mnt_point] to [/system_root]\n"); - fdt_setprop_string(fdt, node, "mnt_point", "/system_root"); - modified = true; - } - } - return modified; -} - -#define MAX_FDT_GROWTH 256 - -template -static bool dt_table_patch(const Header *hdr, const char *out) { - map dtb_map; - auto buf = reinterpret_cast(hdr); - auto tables = reinterpret_cast(buf + sizeof(Header)); - - constexpr bool is_aosp = std::is_same_v; - - // AOSP DTB store ints in big endian - using endian_conv = uint32_t (*)(uint32_t); - endian_conv be_to_le; - endian_conv le_to_be; - if constexpr (is_aosp) { - be_to_le = fdt32_to_cpu; - le_to_be = cpu_to_fdt32; - } else { - be_to_le = le_to_be = [](uint32_t x) { return x; }; - } - - // Collect all dtbs - auto num_dtb = be_to_le(hdr->num_dtbs); - for (int i = 0; i < num_dtb; ++i) { - auto offset = be_to_le(tables[i].offset); - if (dtb_map.count(offset) == 0) { - auto blob = buf + offset; - uint32_t size = fdt_totalsize(blob); - auto fdt = malloc(size + MAX_FDT_GROWTH); - memcpy(fdt, blob, size); - fdt_open_into(fdt, fdt, size + MAX_FDT_GROWTH); - dtb_map[offset] = { fdt, offset }; - } - } - if (dtb_map.empty()) - return false; - - // Patch fdt - bool modified = false; - for (auto &[_, blob] : dtb_map) - modified |= fdt_patch(blob.fdt); - if (!modified) - return false; - - unlink(out); - int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644); - - // This value is only used if AOSP DTB - uint32_t total_size = 0; - - // Copy headers and tables - total_size += xwrite(fd, buf, dtb_map.begin()->first); - - // mmap rw to patch table values retroactively - mmap_data m(fd, lseek(fd, 0, SEEK_CUR), true); - - // Guess alignment using gcd - uint32_t align = 1; - if constexpr (!is_aosp) { - auto it = dtb_map.begin(); - align = (it++)->first; - for (; it != dtb_map.end(); ++it) - align = binary_gcd(align, it->first); - } - - // Write dtbs - for (auto &val : dtb_map) { - val.second.offset = lseek(fd, 0, SEEK_CUR); - auto fdt = val.second.fdt; - fdt_pack(fdt); - auto size = fdt_totalsize(fdt); - total_size += xwrite(fd, fdt, size); - if constexpr (!is_aosp) { - val.second.len = align_to(size, align); - write_zero(fd, align_padding(lseek(fd, 0, SEEK_CUR), align)); - } - free(fdt); - } - - // Patch headers - if constexpr (is_aosp) { - auto hdr_rw = reinterpret_cast
(m.buf()); - hdr_rw->total_size = le_to_be(total_size); - } - auto tables_rw = reinterpret_cast(m.buf() + sizeof(Header)); - for (int i = 0; i < num_dtb; ++i) { - auto &blob = dtb_map[be_to_le(tables_rw[i].offset)]; - tables_rw[i].offset = le_to_be(blob.offset); - tables_rw[i].len = le_to_be(blob.len); - } - - close(fd); - - return true; -} - -static bool blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) { - vector fdt_list; - vector padding_list; - - uint8_t * const end = dtb + dtb_sz; - for (uint8_t *curr = dtb; curr < end;) { - curr = static_cast(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t))); - if (curr == nullptr) - break; - auto len = fdt_totalsize(curr); - auto fdt = static_cast(malloc(len + MAX_FDT_GROWTH)); - memcpy(fdt, curr, len); - fdt_pack(fdt); - uint32_t padding = len - fdt_totalsize(fdt); - padding_list.push_back(padding); - fdt_open_into(fdt, fdt, len + MAX_FDT_GROWTH); - fdt_list.push_back(fdt); - curr += len; - } - - bool modified = false; - for (auto fdt : fdt_list) - modified |= fdt_patch(fdt); - if (!modified) - return false; - - unlink(out); - int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644); - - for (int i = 0; i < fdt_list.size(); ++i) { - auto fdt = fdt_list[i]; - fdt_pack(fdt); - // Only add padding back if it is anything meaningful - if (padding_list[i] > 4) { - auto len = fdt_totalsize(fdt); - fdt_set_totalsize(fdt, len + padding_list[i]); - } - xwrite(fd, fdt, fdt_totalsize(fdt)); - free(fdt); - } - close(fd); - - return true; -} - -#define DTB_MATCH(s) BUFFER_MATCH(dtb, s) - -[[maybe_unused]] -static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) { - if (DTB_MATCH(QCDT_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 1: - fprintf(stderr, "QCDT v1\n"); - return dt_table_patch(hdr, file); - case 2: - fprintf(stderr, "QCDT v2\n"); - return dt_table_patch(hdr, file); - case 3: - fprintf(stderr, "QCDT v3\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else if (DTB_MATCH(DTBH_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 2: - fprintf(stderr, "DTBH v2\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else if (DTB_MATCH(PXADT_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 1: - fprintf(stderr, "PXA-DT v1\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else if (DTB_MATCH(PXA19xx_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 1: - fprintf(stderr, "PXA-19xx v1\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else if (DTB_MATCH(SPRD_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 1: - fprintf(stderr, "SPRD v1\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else if (DTB_MATCH(DT_TABLE_MAGIC)) { - auto hdr = reinterpret_cast(dtb); - switch (hdr->version) { - case 0: - fprintf(stderr, "DT_TABLE v0\n"); - return dt_table_patch(hdr, file); - default: - return false; - } - } else { - return blob_patch(dtb, dtb_sz, file); - } -} - -} // namespace diff --git a/native/src/boot/dtb.hpp b/native/src/boot/dtb.hpp deleted file mode 100644 index 7d2689424..000000000 --- a/native/src/boot/dtb.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include - -#define DT_TABLE_MAGIC "\xd7\xb7\xab\x1e" -#define QCDT_MAGIC "QCDT" -#define DTBH_MAGIC "DTBH" -#define PXADT_MAGIC "PXA-DT" -#define PXA19xx_MAGIC "PXA-19xx" -#define SPRD_MAGIC "SPRD" - -struct qcdt_hdr { - char magic[4]; /* "QCDT" */ - uint32_t version; /* QCDT version */ - uint32_t num_dtbs; /* Number of DTBs */ -} __attribute__((packed)); - -struct qctable_v1 { - uint32_t cpu_info[3]; /* Some CPU info */ - uint32_t offset; /* DTB offset in QCDT */ - uint32_t len; /* DTB size */ -} __attribute__((packed)); - -struct qctable_v2 { - uint32_t cpu_info[4]; /* Some CPU info */ - uint32_t offset; /* DTB offset in QCDT */ - uint32_t len; /* DTB size */ -} __attribute__((packed)); - -struct qctable_v3 { - uint32_t cpu_info[8]; /* Some CPU info */ - uint32_t offset; /* DTB offset in QCDT */ - uint32_t len; /* DTB size */ -} __attribute__((packed)); - -struct dtbh_hdr { - char magic[4]; /* "DTBH" */ - uint32_t version; /* DTBH version */ - uint32_t num_dtbs; /* Number of DTBs */ -} __attribute__((packed)); - -struct bhtable_v2 { - uint32_t cpu_info[5]; /* Some CPU info */ - uint32_t offset; /* DTB offset in DTBH */ - uint32_t len; /* DTB size */ - uint32_t space; /* 0x00000020 */ -} __attribute__((packed)); - -struct pxadt_hdr { - char magic[6]; /* "PXA-DT" */ - uint32_t version; /* PXA-* version */ - uint32_t num_dtbs; /* Number of DTBs */ -} __attribute__((packed)); - -struct pxa19xx_hdr { - char magic[8]; /* "PXA-19xx" */ - uint32_t version; /* PXA-* version */ - uint32_t num_dtbs; /* Number of DTBs */ -} __attribute__((packed)); - -struct pxatable_v1 { - uint32_t cpu_info[2]; /* Some CPU info */ - uint32_t offset; /* DTB offset in PXA-* */ - uint32_t len; /* DTB size */ -} __attribute__((packed)); - -struct sprd_hdr { - char magic[4]; /* "SPRD" */ - uint32_t version; /* SPRD version */ - uint32_t num_dtbs; /* Number of DTBs */ -} __attribute__((packed)); - -struct sprdtable_v1 { - uint32_t cpu_info[3]; /* Some CPU info */ - uint32_t offset; /* DTB offset in SPRD */ - uint32_t len; /* DTB size */ -} __attribute__((packed)); - -/* AOSP DTB/DTBO partition layout */ - -struct dt_table_header { - uint32_t magic; /* DT_TABLE_MAGIC */ - uint32_t total_size; /* includes dt_table_header + all dt_table_entry */ - uint32_t header_size; /* sizeof(dt_table_header) */ - - uint32_t dt_entry_size; /* sizeof(dt_table_entry) */ - uint32_t num_dtbs; /* number of dt_table_entry */ - uint32_t dt_entries_offset; /* offset to the first dt_table_entry */ - - uint32_t page_size; /* flash page size we assume */ - uint32_t version; /* DTBO image version */ -} __attribute__((packed)); - -struct dt_table_entry { - uint32_t len; /* DTB size */ - uint32_t offset; - - uint32_t id; - uint32_t rev; - uint32_t flags; - - uint32_t custom[3]; -} __attribute__((packed)); diff --git a/native/src/boot/dtb.rs b/native/src/boot/dtb.rs new file mode 100644 index 000000000..829c7177f --- /dev/null +++ b/native/src/boot/dtb.rs @@ -0,0 +1,316 @@ +use crate::{check_env, patch::patch_verity}; +use argh::FromArgs; +use base::{ + libc::c_char, log_err, map_args, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, +}; +use fdt::{ + node::{FdtNode, NodeProperty}, + Fdt, +}; +use std::{cell::UnsafeCell, fmt::Write, process::exit}; + +#[derive(FromArgs)] +struct DtbCli { + #[argh(positional)] + file: String, + #[argh(subcommand)] + action: DtbAction, +} + +#[derive(FromArgs)] +#[argh(subcommand)] +enum DtbAction { + Print(Print), + Patch(Patch), + Test(Test), +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "print")] +struct Print { + #[argh(switch, short = 'f')] + fstab: bool, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "patch")] +struct Patch {} + +#[derive(FromArgs)] +#[argh(subcommand, name = "test")] +struct Test {} + +fn print_dtb_usage() { + eprintln!( + r#"Usage: magiskboot dtb [args...] +Do dtb related actions to . + +Supported actions: + print [-f] Print all contents of dtb for debugging + Specify [-f] to only print fstab nodes + patch + Search for fstab and remove verity/avb + Modifications are done directly to the file in-place + Configure with env variables: KEEPVERITY + test + Test the fstab's status + Return values: + 0:valid 1:error"# + ); +} + +const MAX_PRINT_LEN: usize = 32; + +fn print_node(node: &FdtNode) { + fn pretty_node(depth_set: &Vec) { + let mut depth_set = depth_set.iter().peekable(); + while let Some(depth) = depth_set.next() { + let last = depth_set.peek().is_none(); + if *depth { + if last { + print!("├── "); + } else { + print!("│ "); + } + } else { + if last { + print!("└── "); + } else { + print!(" "); + } + } + } + } + + fn pretty_prop(depth_set: &Vec) { + let mut depth_set = depth_set.iter().peekable(); + while let Some(depth) = depth_set.next() { + let last = depth_set.peek().is_none(); + if *depth { + if last { + print!("│ "); + } else { + print!("│ "); + } + } else { + if last { + print!("└─ "); + } else { + print!(" "); + } + } + } + } + + fn do_print_node(node: &FdtNode, depth_set: &mut Vec) { + pretty_node(depth_set); + let depth = depth_set.len(); + depth_set.push(true); + println!("{}", node.name); + let mut properties = node.properties().peekable(); + let mut children = node.children().peekable(); + while let Some(NodeProperty { name, value }) = properties.next() { + let size = value.len(); + let is_str = !(size > 1 && value[0] == 0) + && matches!(value.last(), Some(0u8) | None) + && value.iter().all(|c| *c == 0 || (*c >= 32 && *c < 127)); + + if depth_set[depth] && properties.peek().is_none() && children.peek().is_none() { + depth_set[depth] = false; + } + + pretty_prop(depth_set); + if is_str { + println!( + "[{}]: [\"{}\"]", + name, + if value.is_empty() { + "" + } else { + unsafe { Utf8CStr::from_bytes_unchecked(value) } + } + ); + } else { + if size > MAX_PRINT_LEN { + println!("[{}]: ({})", name, size); + } else { + println!("[{}]: {:02x?}", name, value); + } + } + } + + while let Some(child) = children.next() { + if depth_set[depth] && children.peek().is_none() { + depth_set[depth] = false; + } + do_print_node(&child, depth_set); + } + depth_set.pop(); + } + + do_print_node(node, &mut vec![]); +} + +fn for_each_fdt LoggedResult<()>>( + file: &Utf8CStr, + rw: bool, + mut f: F, +) -> LoggedResult<()> { + eprintln!("Loading dtbs from [{}]", file); + let file = if rw { + MappedFile::open_rw(file)? + } else { + MappedFile::open(file)? + }; + let mut buf = Some(file.as_ref()); + let mut dtb_num = 0usize; + while let Some(slice) = buf { + let slice = if let Some(pos) = slice.windows(4).position(|w| w == b"\xd0\x0d\xfe\xed") { + &slice[pos..] + } else { + break; + }; + if slice.len() < 40 { + break; + } + let fdt = Fdt::new(slice)?; + + let size = fdt.total_size(); + + if size > slice.len() { + eprintln!("dtb.{:04} is truncated", dtb_num); + break; + } + + f(dtb_num, fdt)?; + + dtb_num += 1; + buf = Some(&slice[size..]); + } + Ok(()) +} + +fn find_fstab<'b, 'a: 'b>(fdt: &'b Fdt<'a>) -> Option> { + for node in fdt.all_nodes() { + if node.name == "fstab" { + return Some(node); + } + } + None +} + +fn dtb_print(file: &Utf8CStr, fstab: bool) -> LoggedResult<()> { + for_each_fdt(file, false, |n, fdt| { + if fstab { + if let Some(fstab) = find_fstab(&fdt) { + eprintln!("Found fstab in dtb.{:04}", n); + print_node(&fstab); + } + } else { + if let Some(mut root) = fdt.find_node("/") { + eprintln!("Printing dtb.{:04}", n); + if root.name.is_empty() { + root.name = "/"; + } + print_node(&root); + } + } + Ok(()) + }) +} + +fn dtb_test(file: &Utf8CStr) -> LoggedResult { + let mut ret = true; + for_each_fdt(file, false, |_, fdt| { + if let Some(fstab) = find_fstab(&fdt) { + for child in fstab.children() { + if child.name != "system" { + continue; + } + if let Some(mount_point) = child.property("mnt_point") { + if mount_point.value == b"/system_root\0" { + ret = false; + break; + } + } + } + } + Ok(()) + })?; + Ok(ret) +} + +fn dtb_patch(file: &Utf8CStr) -> LoggedResult { + let keep_verity = check_env("KEEPVERITY"); + let mut patched = false; + for_each_fdt(file, true, |n, fdt| { + for node in fdt.all_nodes() { + if node.name != "chosen" { + continue; + } + if let Some(boot_args) = node.property("bootargs") { + boot_args.value.windows(14).for_each(|w| { + if w == b"skip_initramfs" { + let w = unsafe { + &mut *std::mem::transmute::<&[u8], &UnsafeCell<[u8]>>(w).get() + }; + w[..=4].copy_from_slice(b"want"); + eprintln!("Patch [skip_initramfs] -> [want_initramfs] in dtb.{:04}", n); + patched = true; + } + }); + } + } + if keep_verity { + return Ok(()); + } + if let Some(fstab) = find_fstab(&fdt) { + for child in fstab.children() { + if let Some(flags) = child.property("fsmgr_flags") { + let flags = unsafe { + &mut *std::mem::transmute::<&[u8], &UnsafeCell<[u8]>>(flags.value).get() + }; + if patch_verity(flags) != flags.len() { + patched = true; + } + } + } + } + Ok(()) + })?; + Ok(patched) +} + +pub fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool { + fn inner(argc: i32, argv: *const *const c_char) -> LoggedResult<()> { + if argc < 1 { + return Err(log_err!("No arguments")); + } + let cmds = map_args(argc, argv)?; + + let mut cli = + DtbCli::from_args(&["magiskboot", "dtb"], &cmds).on_early_exit(print_dtb_usage); + + let file = Utf8CStr::from_string(&mut cli.file); + + match cli.action { + DtbAction::Print(Print { fstab }) => { + dtb_print(file, fstab)?; + } + DtbAction::Test(_) => { + if !dtb_test(file)? { + exit(1); + } + } + DtbAction::Patch(_) => { + if !dtb_patch(file)? { + exit(1); + } + } + } + Ok(()) + } + inner(argc, argv) + .log_with_msg(|w| w.write_str("Failed to process dtb")) + .is_ok() +} diff --git a/native/src/boot/lib.rs b/native/src/boot/lib.rs index 8dc7e1a33..0f8aa3ed6 100644 --- a/native/src/boot/lib.rs +++ b/native/src/boot/lib.rs @@ -3,11 +3,14 @@ pub use base; use cpio::cpio_commands; -use patch::{hexpatch, patch_encryption, patch_verity}; +use dtb::dtb_commands; +use patch::hexpatch; use payload::extract_boot_from_payload; use sign::{get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image, SHA}; +use std::env; mod cpio; +mod dtb; mod patch; mod payload; // Suppress warnings in generated code @@ -41,8 +44,6 @@ pub mod ffi { fn sha256_hash(data: &[u8], out: &mut [u8]); fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool; - fn patch_encryption(buf: &mut [u8]) -> usize; - fn patch_verity(buf: &mut [u8]) -> usize; } #[namespace = "rust"] @@ -52,7 +53,6 @@ pub mod ffi { in_path: *const c_char, out_path: *const c_char, ) -> bool; - unsafe fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool; unsafe fn verify_boot_image(img: &BootImage, cert: *const c_char) -> bool; unsafe fn sign_boot_image( @@ -61,5 +61,11 @@ pub mod ffi { cert: *const c_char, key: *const c_char, ) -> Vec; + unsafe fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool; } } + +#[inline(always)] +pub(crate) fn check_env(env: &str) -> bool { + env::var(env).map_or(false, |var| var == "true") +} diff --git a/native/src/boot/main.cpp b/native/src/boot/main.cpp index 62c37131e..782ca2cf9 100644 --- a/native/src/boot/main.cpp +++ b/native/src/boot/main.cpp @@ -76,19 +76,8 @@ Supported actions: See "cpio --help" for supported commands. dtb [args...] - Do dtb related actions to - Supported actions: - print [-f] - Print all contents of dtb for debugging - Specify [-f] to only print fstab nodes - patch - Search for fstab and remove verity/avb - Modifications are done directly to the file in-place - Configure with env variables: KEEPVERITY - test - Test the fstab's status - Return values: - 0:valid 1:error + Do dtb related actions to . + See "dtb --help" for supported actions. split Split image.*-dtb into kernel + kernel_dtb @@ -202,9 +191,8 @@ int main(int argc, char *argv[]) { return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1; } else if (argc > 2 && action == "cpio") { return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1; - } else if (argc > 3 && action == "dtb") { - if (dtb_commands(argc - 2, argv + 2)) - usage(argv[0]); + } else if (argc > 2 && action == "dtb") { + return rust::dtb_commands(argc - 2, argv + 2) ? 0 : 1; } else if (argc > 2 && action == "extract") { return rust::extract_boot_from_payload( argv[2], diff --git a/native/src/boot/ramdisk.rs b/native/src/boot/ramdisk.rs index db47417d9..e3f1f541c 100644 --- a/native/src/boot/ramdisk.rs +++ b/native/src/boot/ramdisk.rs @@ -1,11 +1,11 @@ use std::cmp::Ordering; use std::collections::HashMap; -use std::env; use std::str::from_utf8; use base::libc::{S_IFDIR, S_IFMT, S_IFREG}; use base::{LoggedResult, Utf8CStr}; +use crate::check_env; use crate::cpio::{Cpio, CpioEntry}; use crate::patch::{patch_encryption, patch_verity}; @@ -20,11 +20,6 @@ const MAGISK_PATCHED: i32 = 1 << 0; const UNSUPPORTED_CPIO: i32 = 1 << 1; const SONY_INIT: i32 = 1 << 2; -#[inline(always)] -fn check_env(env: &str) -> bool { - env::var(env).map_or(false, |var| var == "true") -} - impl MagiskCpio for Cpio { fn patch(&mut self) { let keep_verity = check_env("KEEPVERITY"); diff --git a/native/src/external/Android.mk b/native/src/external/Android.mk index 5e1fed627..42cdb39ef 100644 --- a/native/src/external/Android.mk +++ b/native/src/external/Android.mk @@ -17,23 +17,6 @@ LOCAL_SRC_FILES := \ xz-embedded/xz_dec_stream.c include $(BUILD_STATIC_LIBRARY) -# libfdt.a -include $(CLEAR_VARS) -LOCAL_MODULE:= libfdt -LOCAL_C_INCLUDES := $(LOCAL_PATH)/dtc/libfdt -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) -LOCAL_SRC_FILES := \ - dtc/libfdt/fdt.c \ - dtc/libfdt/fdt_addresses.c \ - dtc/libfdt/fdt_empty_tree.c \ - dtc/libfdt/fdt_overlay.c \ - dtc/libfdt/fdt_ro.c \ - dtc/libfdt/fdt_rw.c \ - dtc/libfdt/fdt_strerror.c \ - dtc/libfdt/fdt_sw.c \ - dtc/libfdt/fdt_wip.c -include $(BUILD_STATIC_LIBRARY) - # liblz4.a include $(CLEAR_VARS) LOCAL_MODULE := liblz4 diff --git a/native/src/external/dtc b/native/src/external/dtc deleted file mode 160000 index c0c2e115f..000000000 --- a/native/src/external/dtc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c0c2e115f82ed3bc5f9d3f9e5380f0f7e81a1c21