Revert DTB patches to in-place binary patches

Since we no longer need to add new properties in the device tree, and
all the patches we do removes strings, we can just directly patch
the flat device tree in-place, ignoring basically all the higher level
DTB structure and format to accomplish 100% compatibility.
This commit is contained in:
topjohnwu 2020-05-05 01:03:09 -07:00
parent dbf8c41209
commit 02dc1172be
5 changed files with 335 additions and 312 deletions

View File

@ -4,45 +4,16 @@
#include <vector>
#include <map>
extern "C" {
#include <libfdt.h>
}
#include <utils.hpp>
#include "magiskboot.hpp"
#include "dtb.hpp"
extern "C" {
#include <libfdt.h>
}
using namespace std;
struct fdt_blob {
void *fdt;
uint32_t offset;
uint32_t len;
};
template <class Iter>
class fdt_map_iter {
public:
typedef decltype(std::declval<typename Iter::value_type::second_type>().fdt) value_type;
typedef value_type* pointer;
typedef value_type& reference;
explicit fdt_map_iter(Iter j) : i(j) {}
fdt_map_iter& operator++() { ++i; return *this; }
fdt_map_iter operator++(int) { auto tmp = *this; ++(*this); return tmp; }
fdt_map_iter& operator--() { --i; return *this; }
fdt_map_iter operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(fdt_map_iter j) const { return i == j.i; }
bool operator!=(fdt_map_iter j) const { return !(*this == j); }
reference operator*() { return i->second.fdt; }
pointer operator->() { return &i->second.fdt; }
private:
Iter i;
};
template<class Iter>
inline fdt_map_iter<Iter> make_iter(Iter j) { return fdt_map_iter<Iter>(j); }
constexpr int MAX_DEPTH = 32;
static bitset<MAX_DEPTH> depth_set;
@ -153,8 +124,91 @@ static void dtb_print(const char *file, bool fstab) {
munmap(dtb, size);
}
template <typename Iter>
static bool fdt_patch(Iter first, Iter last) {
static bool dtb_patch(const char *file) {
bool keepverity = check_env("KEEPVERITY");
bool patched = false;
size_t size;
uint8_t *dtb;
fprintf(stderr, "Loading dtbs from [%s]\n", file);
mmap_rw(file, dtb, size);
// Loop through all the dtbs
int dtb_num = 0;
for (int i = 0; i < size; ++i) {
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
auto fdt = dtb + i;
fprintf(stderr, "Loading dtb.%04d\n", dtb_num);
if (int fstab = find_fstab(fdt); fstab >= 0) {
int node;
fdt_for_each_subnode(node, fdt, fstab) {
const char *name = fdt_get_name(fdt, node, nullptr);
fprintf(stderr, "Found fstab entry [%s]\n", name);
if (!keepverity) {
int len;
auto value = fdt_getprop(fdt, node, "fsmgr_flags", &len);
patched |= patch_verity(const_cast<void *>(value), len) != len;
}
}
}
++dtb_num;
i += fdt_totalsize(fdt) - 1;
}
}
fprintf(stderr, "\n");
munmap(dtb, size);
return patched;
}
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 {
return 1;
}
}
namespace {
// Unused, but keep these precious code as they took TONs of effort to write
struct fdt_blob {
void *fdt;
uint32_t offset;
uint32_t len;
};
template <class Iter>
class fdt_map_iter {
public:
typedef decltype(std::declval<typename Iter::value_type::second_type>().fdt) value_type;
typedef value_type* pointer;
typedef value_type& reference;
explicit fdt_map_iter(Iter j) : i(j) {}
fdt_map_iter& operator++() { ++i; return *this; }
fdt_map_iter operator++(int) { auto tmp = *this; ++(*this); return tmp; }
fdt_map_iter& operator--() { --i; return *this; }
fdt_map_iter operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(fdt_map_iter j) const { return i == j.i; }
bool operator!=(fdt_map_iter j) const { return !(*this == j); }
reference operator*() { return i->second.fdt; }
pointer operator->() { return &i->second.fdt; }
private:
Iter i;
};
template<class Iter>
inline fdt_map_iter<Iter> make_iter(Iter j) { return fdt_map_iter<Iter>(j); }
template <typename Iter>
static bool fdt_patch(Iter first, Iter last) {
bool keepverity = check_env("KEEPVERITY");
bool redirect = check_env("TWOSTAGEINIT");
bool modified = false;
@ -172,14 +226,14 @@ static bool fdt_patch(Iter first, Iter last) {
const char *name = fdt_get_name(fdt, block, nullptr);
fprintf(stderr, "Found entry [%s] in fstab\n", name);
if (!keepverity) {
uint32_t size;
auto value = static_cast<const char *>(
fdt_getprop(fdt, block, "fsmgr_flags", reinterpret_cast<int *>(&size)));
char *pval = patch_verity(value, size);
if (pval) {
int size;
auto value = fdt_getprop(fdt, block, "fsmgr_flags", &size);
char *copy = static_cast<char *>(memcpy(malloc(size), value, size));
if (patch_verity(copy, size) != size) {
modified = true;
fdt_setprop_string(fdt, block, "fsmgr_flags", pval);
fdt_setprop_string(fdt, block, "fsmgr_flags", copy);
}
free(copy);
}
if (redirect && name == "system"sv) {
modified = true;
@ -189,12 +243,12 @@ static bool fdt_patch(Iter first, Iter last) {
}
}
return modified;
}
}
#define MAX_FDT_GROWTH 256
template <class Table, class Header>
static int dt_table_patch(const Header *hdr, const char *out) {
template <class Table, class Header>
static int 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 *>(hdr + 1);
@ -281,9 +335,9 @@ static int dt_table_patch(const Header *hdr, const char *out) {
close(fd);
return 0;
}
}
static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
vector<uint8_t *> fdt_list;
vector<uint32_t> padding_list;
for (int i = 0; i < dtb_sz; ++i) {
@ -320,11 +374,11 @@ static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
close(fd);
return 0;
}
}
#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0)
static int dtb_patch(const char *in, const char *out) {
[[maybe_unused]] static int dtb_patch(const char *in, const char *out) {
if (!out)
out = in;
size_t dtb_sz ;
@ -396,21 +450,5 @@ static int dtb_patch(const char *in, const char *out) {
} else {
return blob_patch(dtb, dtb_sz, out);
}
}
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, argv[1]))
exit(1);
return 0;
} else {
return 1;
}
}

View File

@ -19,6 +19,6 @@ int hexpatch(const char *image, const char *from, const char *to);
int cpio_commands(int argc, char *argv[]);
int dtb_commands(int argc, char *argv[]);
char *patch_verity(const void *buf, uint32_t &size, bool inplace = false);
void patch_encryption(void *buf, uint32_t &size);
uint32_t patch_verity(void *buf, uint32_t size);
uint32_t patch_encryption(void *buf, uint32_t size);
bool check_env(const char *name);

View File

@ -42,7 +42,7 @@ Supported actions:
Search <hexpattern1> in <file>, and replace with <hexpattern2>
cpio <incpio> [commands...]
Do cpio commands to <incpio> (modifications are done directly)
Do cpio commands to <incpio> (modifications are done in-place)
Each command is a single argument, add quotes for each command
Supported commands:
exists ENTRY
@ -64,8 +64,8 @@ Supported actions:
Return values:
0:stock 1:Magisk 2:unsupported (phh, SuperSU, Xposed)
patch
Apply ramdisk patches. Configure settings with env variables:
KEEPVERITY KEEPFORCEENCRYPT
Apply ramdisk patches
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
backup ORIG
Create ramdisk backups from ORIG
restore
@ -79,10 +79,10 @@ Supported actions:
print [-f]
Print all contents of dtb for debugging
Specify [-f] to only print fstab nodes
patch [OUT]
patch
Search for fstab and remove verity/avb
If [OUT] is not specified, it will directly output to <input>
Configure with env variables: KEEPVERITY TWOSTAGEINIT
Modifications are done directly to the file in-place
Configure with env variables: KEEPVERITY
split <input>
Split image.*-dtb into kernel + kernel_dtb
@ -186,7 +186,7 @@ int main(int argc, char *argv[]) {
} else if (argc > 2 && action == "cpio"sv) {
if (cpio_commands(argc - 2, argv + 2))
usage(argv[0]);
} else if (argc > 2 && action == "dtb") {
} else if (argc > 3 && action == "dtb") {
if (dtb_commands(argc - 2, argv + 2))
usage(argv[0]);
} else {

View File

@ -37,42 +37,27 @@ static int check_encryption_pattern(const char *s) {
else return -1;
}
char *patch_verity(const void *buf, uint32_t &size, bool inplace) {
auto src = static_cast<const char *>(buf);
auto dest = (char *)(inplace ? buf : xmalloc(size));
int src_size = size;
bool found = false;
static uint32_t remove_pattern(void *buf, uint32_t size, int(*pattern_skip)(const char *)) {
auto src = static_cast<char *>(buf);
int orig_sz = size;
int write = 0;
for (int read = 0; read < src_size;) {
if (int skip; (skip = check_verity_pattern(src + read)) > 0) {
fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read);
for (int read = 0; read < orig_sz;) {
if (int skip = pattern_skip(src + read); skip > 0) {
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
size -= skip;
read += skip;
found = true;
} else {
dest[write++] = src[read++];
src[write++] = src[read++];
}
}
dest[write] = '\0';
if (!found) {
if (!inplace)
free(dest);
return nullptr;
}
return dest;
memset(src + write, 0, orig_sz - write);
return size;
}
void patch_encryption(void *buf, uint32_t &size) {
auto src = static_cast<char *>(buf);
int src_size = size;
int write = 0;
for (int read = 0; read < src_size; ++read, ++write) {
if (int skip; (skip = check_encryption_pattern(src + read)) > 0) {
fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read);
size -= skip;
read += skip;
}
src[write] = src[read];
}
src[write] = '\0';
uint32_t patch_verity(void *buf, uint32_t size) {
return remove_pattern(buf, size, check_verity_pattern);
}
uint32_t patch_encryption(void *buf, uint32_t size) {
return remove_pattern(buf, size, check_encryption_pattern);
}

View File

@ -55,7 +55,7 @@ void magisk_cpio::patch() {
if (!keepverity) {
if (fstab) {
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
patch_verity(cur->second->data, cur->second->filesize, true);
cur->second->filesize = patch_verity(cur->second->data, cur->second->filesize);
} else if (cur->first == "verity_key") {
rm(cur);
continue;
@ -63,7 +63,7 @@ void magisk_cpio::patch() {
}
if (!keepforceencrypt) {
if (fstab) {
patch_encryption(cur->second->data, cur->second->filesize);
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
}
}
}