mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Refactor dtb in rust
This commit is contained in:
parent
8e1a91509c
commit
8d7c7c3dfb
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,9 +4,6 @@
|
|||||||
[submodule "busybox"]
|
[submodule "busybox"]
|
||||||
path = native/src/external/busybox
|
path = native/src/external/busybox
|
||||||
url = https://github.com/topjohnwu/ndk-busybox.git
|
url = https://github.com/topjohnwu/ndk-busybox.git
|
||||||
[submodule "dtc"]
|
|
||||||
path = native/src/external/dtc
|
|
||||||
url = https://github.com/dgibson/dtc.git
|
|
||||||
[submodule "lz4"]
|
[submodule "lz4"]
|
||||||
path = native/src/external/lz4
|
path = native/src/external/lz4
|
||||||
url = https://github.com/lz4/lz4.git
|
url = https://github.com/lz4/lz4.git
|
||||||
|
@ -99,7 +99,6 @@ LOCAL_STATIC_LIBRARIES := \
|
|||||||
liblzma \
|
liblzma \
|
||||||
liblz4 \
|
liblz4 \
|
||||||
libbz2 \
|
libbz2 \
|
||||||
libfdt \
|
|
||||||
libz \
|
libz \
|
||||||
libzopfli \
|
libzopfli \
|
||||||
libboot-rs
|
libboot-rs
|
||||||
@ -109,7 +108,6 @@ LOCAL_SRC_FILES := \
|
|||||||
boot/bootimg.cpp \
|
boot/bootimg.cpp \
|
||||||
boot/compress.cpp \
|
boot/compress.cpp \
|
||||||
boot/format.cpp \
|
boot/format.cpp \
|
||||||
boot/dtb.cpp \
|
|
||||||
boot/boot-rs.cpp
|
boot/boot-rs.cpp
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
39
native/src/Cargo.lock
generated
39
native/src/Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.0.5"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
|
checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -324,6 +324,12 @@ dependencies = [
|
|||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fdt"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "ff"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@ -336,9 +342,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flagset"
|
name = "flagset"
|
||||||
version = "0.4.3"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"
|
checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
@ -420,9 +426,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@ -461,6 +467,7 @@ dependencies = [
|
|||||||
"cxx-gen",
|
"cxx-gen",
|
||||||
"der",
|
"der",
|
||||||
"digest",
|
"digest",
|
||||||
|
"fdt",
|
||||||
"p256",
|
"p256",
|
||||||
"p384",
|
"p384",
|
||||||
"pb-rs",
|
"pb-rs",
|
||||||
@ -654,9 +661,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.66"
|
version = "1.0.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -883,9 +890,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.31"
|
version = "2.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -894,9 +901,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
@ -932,15 +939,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.11"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
|
@ -22,6 +22,7 @@ rsa = "0.9"
|
|||||||
x509-cert = "0.2"
|
x509-cert = "0.2"
|
||||||
der = "0.7"
|
der = "0.7"
|
||||||
bytemuck = "1.14"
|
bytemuck = "1.14"
|
||||||
|
fdt = "0.1"
|
||||||
|
|
||||||
[workspace.dependencies.argh]
|
[workspace.dependencies.argh]
|
||||||
git = "https://github.com/topjohnwu/argh.git"
|
git = "https://github.com/topjohnwu/argh.git"
|
||||||
|
@ -26,3 +26,4 @@ p384 = { workspace = true }
|
|||||||
rsa = { workspace = true, features = ["sha2"] }
|
rsa = { workspace = true, features = ["sha2"] }
|
||||||
x509-cert = { workspace = true }
|
x509-cert = { workspace = true }
|
||||||
der = { workspace = true, features = ["derive"] }
|
der = { workspace = true, features = ["derive"] }
|
||||||
|
fdt = { workspace = true }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
#include <bit>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <libfdt.h>
|
|
||||||
#include <base.hpp>
|
#include <base.hpp>
|
||||||
|
|
||||||
#include "boot-rs.hpp"
|
#include "boot-rs.hpp"
|
||||||
@ -183,29 +183,70 @@ boot_img::~boot_img() {
|
|||||||
delete hdr;
|
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<uint32_t>(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) {
|
static int find_dtb_offset(const uint8_t *buf, unsigned sz) {
|
||||||
const uint8_t * const end = buf + sz;
|
const uint8_t * const end = buf + sz;
|
||||||
|
|
||||||
for (auto curr = buf; curr < end; curr += sizeof(fdt_header)) {
|
for (auto curr = buf; curr < end; curr += sizeof(fdt_header)) {
|
||||||
curr = static_cast<uint8_t*>(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t)));
|
curr = static_cast<uint8_t*>(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt_header::fdt32_t)));
|
||||||
if (curr == nullptr)
|
if (curr == nullptr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
auto fdt_hdr = reinterpret_cast<const fdt_header *>(curr);
|
auto fdt_hdr = reinterpret_cast<const fdt_header *>(curr);
|
||||||
|
|
||||||
// Check that fdt_header.totalsize does not overflow kernel image size
|
// 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)
|
if (totalsize > end - curr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check that fdt_header.off_dt_struct does not overflow kernel image size
|
// 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)
|
if (off_dt_struct > end - curr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE
|
// Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE
|
||||||
auto fdt_node_hdr = reinterpret_cast<const fdt_node_header *>(curr + off_dt_struct);
|
auto fdt_node_hdr = reinterpret_cast<const fdt_header::node_header *>(curr + off_dt_struct);
|
||||||
if (fdt32_to_cpu(fdt_node_hdr->tag) != FDT_BEGIN_NODE)
|
if (fdt_node_hdr->tag != 0x1u)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return curr - buf;
|
return curr - buf;
|
||||||
|
@ -1,452 +0,0 @@
|
|||||||
#include <bitset>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <libfdt.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
|
|
||||||
#include "magiskboot.hpp"
|
|
||||||
#include "dtb.hpp"
|
|
||||||
#include "format.hpp"
|
|
||||||
#include "boot-rs.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
constexpr int MAX_DEPTH = 32;
|
|
||||||
static bitset<MAX_DEPTH> 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<const char *>(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]: <bytes>(%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<typename Func>
|
|
||||||
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<uint8_t*>(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<const char *>(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 <class Table, class Header>
|
|
||||||
static bool dt_table_patch(const Header *hdr, const char *out) {
|
|
||||||
map<uint32_t, fdt_blob> dtb_map;
|
|
||||||
auto buf = reinterpret_cast<const uint8_t *>(hdr);
|
|
||||||
auto tables = reinterpret_cast<const Table *>(buf + sizeof(Header));
|
|
||||||
|
|
||||||
constexpr bool is_aosp = std::is_same_v<Header, dt_table_header>;
|
|
||||||
|
|
||||||
// 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<Header *>(m.buf());
|
|
||||||
hdr_rw->total_size = le_to_be(total_size);
|
|
||||||
}
|
|
||||||
auto tables_rw = reinterpret_cast<Table *>(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<uint8_t *> fdt_list;
|
|
||||||
vector<uint32_t> padding_list;
|
|
||||||
|
|
||||||
uint8_t * const end = dtb + dtb_sz;
|
|
||||||
for (uint8_t *curr = dtb; curr < end;) {
|
|
||||||
curr = static_cast<uint8_t*>(memmem(curr, end - curr, DTB_MAGIC, sizeof(fdt32_t)));
|
|
||||||
if (curr == nullptr)
|
|
||||||
break;
|
|
||||||
auto len = fdt_totalsize(curr);
|
|
||||||
auto fdt = static_cast<uint8_t *>(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<qcdt_hdr*>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 1:
|
|
||||||
fprintf(stderr, "QCDT v1\n");
|
|
||||||
return dt_table_patch<qctable_v1>(hdr, file);
|
|
||||||
case 2:
|
|
||||||
fprintf(stderr, "QCDT v2\n");
|
|
||||||
return dt_table_patch<qctable_v2>(hdr, file);
|
|
||||||
case 3:
|
|
||||||
fprintf(stderr, "QCDT v3\n");
|
|
||||||
return dt_table_patch<qctable_v3>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (DTB_MATCH(DTBH_MAGIC)) {
|
|
||||||
auto hdr = reinterpret_cast<dtbh_hdr *>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 2:
|
|
||||||
fprintf(stderr, "DTBH v2\n");
|
|
||||||
return dt_table_patch<bhtable_v2>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (DTB_MATCH(PXADT_MAGIC)) {
|
|
||||||
auto hdr = reinterpret_cast<pxadt_hdr *>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 1:
|
|
||||||
fprintf(stderr, "PXA-DT v1\n");
|
|
||||||
return dt_table_patch<pxatable_v1>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (DTB_MATCH(PXA19xx_MAGIC)) {
|
|
||||||
auto hdr = reinterpret_cast<pxa19xx_hdr *>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 1:
|
|
||||||
fprintf(stderr, "PXA-19xx v1\n");
|
|
||||||
return dt_table_patch<pxatable_v1>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (DTB_MATCH(SPRD_MAGIC)) {
|
|
||||||
auto hdr = reinterpret_cast<sprd_hdr *>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 1:
|
|
||||||
fprintf(stderr, "SPRD v1\n");
|
|
||||||
return dt_table_patch<sprdtable_v1>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (DTB_MATCH(DT_TABLE_MAGIC)) {
|
|
||||||
auto hdr = reinterpret_cast<dt_table_header *>(dtb);
|
|
||||||
switch (hdr->version) {
|
|
||||||
case 0:
|
|
||||||
fprintf(stderr, "DT_TABLE v0\n");
|
|
||||||
return dt_table_patch<dt_table_entry>(hdr, file);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return blob_patch(dtb, dtb_sz, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
@ -1,103 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#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));
|
|
316
native/src/boot/dtb.rs
Normal file
316
native/src/boot/dtb.rs
Normal file
@ -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 <file> <action> [args...]
|
||||||
|
Do dtb related actions to <file>.
|
||||||
|
|
||||||
|
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<bool>) {
|
||||||
|
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<bool>) {
|
||||||
|
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<bool>) {
|
||||||
|
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!("[{}]: <bytes>({})", 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<F: FnMut(usize, 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<FdtNode<'b, 'a>> {
|
||||||
|
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<bool> {
|
||||||
|
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<bool> {
|
||||||
|
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()
|
||||||
|
}
|
@ -3,11 +3,14 @@
|
|||||||
|
|
||||||
pub use base;
|
pub use base;
|
||||||
use cpio::cpio_commands;
|
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 payload::extract_boot_from_payload;
|
||||||
use sign::{get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image, SHA};
|
use sign::{get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image, SHA};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
mod cpio;
|
mod cpio;
|
||||||
|
mod dtb;
|
||||||
mod patch;
|
mod patch;
|
||||||
mod payload;
|
mod payload;
|
||||||
// Suppress warnings in generated code
|
// Suppress warnings in generated code
|
||||||
@ -41,8 +44,6 @@ pub mod ffi {
|
|||||||
fn sha256_hash(data: &[u8], out: &mut [u8]);
|
fn sha256_hash(data: &[u8], out: &mut [u8]);
|
||||||
|
|
||||||
fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool;
|
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"]
|
#[namespace = "rust"]
|
||||||
@ -52,7 +53,6 @@ pub mod ffi {
|
|||||||
in_path: *const c_char,
|
in_path: *const c_char,
|
||||||
out_path: *const c_char,
|
out_path: *const c_char,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
unsafe fn cpio_commands(argc: i32, argv: *const *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 verify_boot_image(img: &BootImage, cert: *const c_char) -> bool;
|
||||||
unsafe fn sign_boot_image(
|
unsafe fn sign_boot_image(
|
||||||
@ -61,5 +61,11 @@ pub mod ffi {
|
|||||||
cert: *const c_char,
|
cert: *const c_char,
|
||||||
key: *const c_char,
|
key: *const c_char,
|
||||||
) -> Vec<u8>;
|
) -> Vec<u8>;
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
@ -76,19 +76,8 @@ Supported actions:
|
|||||||
See "cpio --help" for supported commands.
|
See "cpio --help" for supported commands.
|
||||||
|
|
||||||
dtb <file> <action> [args...]
|
dtb <file> <action> [args...]
|
||||||
Do dtb related actions to <file>
|
Do dtb related actions to <file>.
|
||||||
Supported actions:
|
See "dtb --help" for 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
|
|
||||||
|
|
||||||
split <file>
|
split <file>
|
||||||
Split image.*-dtb into kernel + kernel_dtb
|
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;
|
return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1;
|
||||||
} else if (argc > 2 && action == "cpio") {
|
} else if (argc > 2 && action == "cpio") {
|
||||||
return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1;
|
return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1;
|
||||||
} else if (argc > 3 && action == "dtb") {
|
} else if (argc > 2 && action == "dtb") {
|
||||||
if (dtb_commands(argc - 2, argv + 2))
|
return rust::dtb_commands(argc - 2, argv + 2) ? 0 : 1;
|
||||||
usage(argv[0]);
|
|
||||||
} else if (argc > 2 && action == "extract") {
|
} else if (argc > 2 && action == "extract") {
|
||||||
return rust::extract_boot_from_payload(
|
return rust::extract_boot_from_payload(
|
||||||
argv[2],
|
argv[2],
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use base::libc::{S_IFDIR, S_IFMT, S_IFREG};
|
use base::libc::{S_IFDIR, S_IFMT, S_IFREG};
|
||||||
use base::{LoggedResult, Utf8CStr};
|
use base::{LoggedResult, Utf8CStr};
|
||||||
|
|
||||||
|
use crate::check_env;
|
||||||
use crate::cpio::{Cpio, CpioEntry};
|
use crate::cpio::{Cpio, CpioEntry};
|
||||||
use crate::patch::{patch_encryption, patch_verity};
|
use crate::patch::{patch_encryption, patch_verity};
|
||||||
|
|
||||||
@ -20,11 +20,6 @@ const MAGISK_PATCHED: i32 = 1 << 0;
|
|||||||
const UNSUPPORTED_CPIO: i32 = 1 << 1;
|
const UNSUPPORTED_CPIO: i32 = 1 << 1;
|
||||||
const SONY_INIT: i32 = 1 << 2;
|
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 {
|
impl MagiskCpio for Cpio {
|
||||||
fn patch(&mut self) {
|
fn patch(&mut self) {
|
||||||
let keep_verity = check_env("KEEPVERITY");
|
let keep_verity = check_env("KEEPVERITY");
|
||||||
|
17
native/src/external/Android.mk
vendored
17
native/src/external/Android.mk
vendored
@ -17,23 +17,6 @@ LOCAL_SRC_FILES := \
|
|||||||
xz-embedded/xz_dec_stream.c
|
xz-embedded/xz_dec_stream.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
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
|
# liblz4.a
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := liblz4
|
LOCAL_MODULE := liblz4
|
||||||
|
1
native/src/external/dtc
vendored
1
native/src/external/dtc
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit c0c2e115f82ed3bc5f9d3f9e5380f0f7e81a1c21
|
|
Loading…
x
Reference in New Issue
Block a user