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:
parent
dbf8c41209
commit
02dc1172be
@ -4,45 +4,16 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <libfdt.h>
|
|
||||||
}
|
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
#include "magiskboot.hpp"
|
#include "magiskboot.hpp"
|
||||||
#include "dtb.hpp"
|
#include "dtb.hpp"
|
||||||
|
extern "C" {
|
||||||
|
#include <libfdt.h>
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std;
|
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;
|
constexpr int MAX_DEPTH = 32;
|
||||||
static bitset<MAX_DEPTH> depth_set;
|
static bitset<MAX_DEPTH> depth_set;
|
||||||
|
|
||||||
@ -153,249 +124,38 @@ static void dtb_print(const char *file, bool fstab) {
|
|||||||
munmap(dtb, size);
|
munmap(dtb, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iter>
|
static bool dtb_patch(const char *file) {
|
||||||
static bool fdt_patch(Iter first, Iter last) {
|
|
||||||
bool keepverity = check_env("KEEPVERITY");
|
bool keepverity = check_env("KEEPVERITY");
|
||||||
bool redirect = check_env("TWOSTAGEINIT");
|
bool patched = false;
|
||||||
bool modified = false;
|
size_t size;
|
||||||
|
uint8_t *dtb;
|
||||||
int idx = 0;
|
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||||
for (auto it = first; it != last; ++it) {
|
mmap_rw(file, dtb, size);
|
||||||
++idx;
|
// Loop through all the dtbs
|
||||||
auto fdt = *it;
|
int dtb_num = 0;
|
||||||
int fstab = find_fstab(fdt);
|
for (int i = 0; i < size; ++i) {
|
||||||
if (fstab < 0)
|
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||||
continue;
|
auto fdt = dtb + i;
|
||||||
fprintf(stderr, "Found fstab in dtb.%04d\n", idx - 1);
|
fprintf(stderr, "Loading dtb.%04d\n", dtb_num);
|
||||||
int block;
|
if (int fstab = find_fstab(fdt); fstab >= 0) {
|
||||||
fdt_for_each_subnode(block, fdt, fstab) {
|
int node;
|
||||||
const char *name = fdt_get_name(fdt, block, nullptr);
|
fdt_for_each_subnode(node, fdt, fstab) {
|
||||||
fprintf(stderr, "Found entry [%s] in fstab\n", name);
|
const char *name = fdt_get_name(fdt, node, nullptr);
|
||||||
if (!keepverity) {
|
fprintf(stderr, "Found fstab entry [%s]\n", name);
|
||||||
uint32_t size;
|
if (!keepverity) {
|
||||||
auto value = static_cast<const char *>(
|
int len;
|
||||||
fdt_getprop(fdt, block, "fsmgr_flags", reinterpret_cast<int *>(&size)));
|
auto value = fdt_getprop(fdt, node, "fsmgr_flags", &len);
|
||||||
char *pval = patch_verity(value, size);
|
patched |= patch_verity(const_cast<void *>(value), len) != len;
|
||||||
if (pval) {
|
}
|
||||||
modified = true;
|
|
||||||
fdt_setprop_string(fdt, block, "fsmgr_flags", pval);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (redirect && name == "system"sv) {
|
++dtb_num;
|
||||||
modified = true;
|
i += fdt_totalsize(fdt) - 1;
|
||||||
fprintf(stderr, "Changing mnt_point to /system_root\n");
|
|
||||||
fdt_setprop_string(fdt, block, "mnt_point", "/system_root");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return modified;
|
fprintf(stderr, "\n");
|
||||||
}
|
munmap(dtb, size);
|
||||||
|
return patched;
|
||||||
#define MAX_FDT_GROWTH 256
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
constexpr bool is_dt_table = std::is_same_v<Header, dt_table_header>;
|
|
||||||
|
|
||||||
using endian_conv = uint32_t (*)(uint32_t);
|
|
||||||
endian_conv be_to_le;
|
|
||||||
endian_conv le_to_be;
|
|
||||||
if constexpr (is_dt_table) {
|
|
||||||
be_to_le = fdt32_to_cpu;
|
|
||||||
le_to_be = cpu_to_fdt32;
|
|
||||||
} else {
|
|
||||||
be_to_le = le_to_be = [](uint32_t x) -> auto { 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 = xmalloc(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 1;
|
|
||||||
|
|
||||||
// Patch fdt
|
|
||||||
if (!fdt_patch(make_iter(dtb_map.begin()), make_iter(dtb_map.end())))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
unlink(out);
|
|
||||||
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
|
||||||
|
|
||||||
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
|
|
||||||
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
|
|
||||||
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
|
|
||||||
// Guess alignment using gcd
|
|
||||||
uint32_t align = 1;
|
|
||||||
if constexpr (!is_dt_table) {
|
|
||||||
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);
|
|
||||||
val.second.len = do_align(size, align);
|
|
||||||
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), align));
|
|
||||||
// total_size += align_off(lseek(fd, 0, SEEK_CUR), align); /* Not needed */
|
|
||||||
free(fdt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patch headers
|
|
||||||
if constexpr (is_dt_table) {
|
|
||||||
auto hdr_rw = reinterpret_cast<Header *>(addr);
|
|
||||||
hdr_rw->total_size = le_to_be(total_size);
|
|
||||||
}
|
|
||||||
auto tables_rw = reinterpret_cast<Table *>(addr + 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
munmap(addr, mmap_sz);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
|
||||||
auto len = fdt_totalsize(dtb + i);
|
|
||||||
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
|
|
||||||
memcpy(fdt, dtb + i, 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);
|
|
||||||
i += len - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
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 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0)
|
|
||||||
|
|
||||||
static int dtb_patch(const char *in, const char *out) {
|
|
||||||
if (!out)
|
|
||||||
out = in;
|
|
||||||
size_t dtb_sz ;
|
|
||||||
uint8_t *dtb;
|
|
||||||
fprintf(stderr, "Loading dtbs from [%s]\n", in);
|
|
||||||
mmap_ro(in, dtb, dtb_sz);
|
|
||||||
run_finally f([&]{ munmap(dtb, dtb_sz); });
|
|
||||||
|
|
||||||
if (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, out);
|
|
||||||
case 2:
|
|
||||||
fprintf(stderr, "QCDT v2\n");
|
|
||||||
return dt_table_patch<qctable_v2>(hdr, out);
|
|
||||||
case 3:
|
|
||||||
fprintf(stderr, "QCDT v3\n");
|
|
||||||
return dt_table_patch<qctable_v3>(hdr, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (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, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (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, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (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, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (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, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (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, out);
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return blob_patch(dtb, dtb_sz, out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dtb_commands(int argc, char *argv[]) {
|
int dtb_commands(int argc, char *argv[]) {
|
||||||
@ -407,10 +167,288 @@ int dtb_commands(int argc, char *argv[]) {
|
|||||||
dtb_print(dtb, argc > 1 && argv[1] == "-f"sv);
|
dtb_print(dtb, argc > 1 && argv[1] == "-f"sv);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argv[0] == "patch"sv) {
|
} else if (argv[0] == "patch"sv) {
|
||||||
if (dtb_patch(dtb, argv[1]))
|
if (!dtb_patch(dtb))
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
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;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (auto it = first; it != last; ++it) {
|
||||||
|
++idx;
|
||||||
|
auto fdt = *it;
|
||||||
|
int fstab = find_fstab(fdt);
|
||||||
|
if (fstab < 0)
|
||||||
|
continue;
|
||||||
|
fprintf(stderr, "Found fstab in dtb.%04d\n", idx - 1);
|
||||||
|
int block;
|
||||||
|
fdt_for_each_subnode(block, fdt, fstab) {
|
||||||
|
const char *name = fdt_get_name(fdt, block, nullptr);
|
||||||
|
fprintf(stderr, "Found entry [%s] in fstab\n", name);
|
||||||
|
if (!keepverity) {
|
||||||
|
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", copy);
|
||||||
|
}
|
||||||
|
free(copy);
|
||||||
|
}
|
||||||
|
if (redirect && name == "system"sv) {
|
||||||
|
modified = true;
|
||||||
|
fprintf(stderr, "Changing mnt_point to /system_root\n");
|
||||||
|
fdt_setprop_string(fdt, block, "mnt_point", "/system_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_FDT_GROWTH 256
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
constexpr bool is_dt_table = std::is_same_v<Header, dt_table_header>;
|
||||||
|
|
||||||
|
using endian_conv = uint32_t (*)(uint32_t);
|
||||||
|
endian_conv be_to_le;
|
||||||
|
endian_conv le_to_be;
|
||||||
|
if constexpr (is_dt_table) {
|
||||||
|
be_to_le = fdt32_to_cpu;
|
||||||
|
le_to_be = cpu_to_fdt32;
|
||||||
|
} else {
|
||||||
|
be_to_le = le_to_be = [](uint32_t x) -> auto { 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 = xmalloc(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 1;
|
||||||
|
|
||||||
|
// Patch fdt
|
||||||
|
if (!fdt_patch(make_iter(dtb_map.begin()), make_iter(dtb_map.end())))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unlink(out);
|
||||||
|
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
||||||
|
|
||||||
|
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
|
||||||
|
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
|
||||||
|
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
|
// Guess alignment using gcd
|
||||||
|
uint32_t align = 1;
|
||||||
|
if constexpr (!is_dt_table) {
|
||||||
|
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);
|
||||||
|
val.second.len = do_align(size, align);
|
||||||
|
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), align));
|
||||||
|
// total_size += align_off(lseek(fd, 0, SEEK_CUR), align); /* Not needed */
|
||||||
|
free(fdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch headers
|
||||||
|
if constexpr (is_dt_table) {
|
||||||
|
auto hdr_rw = reinterpret_cast<Header *>(addr);
|
||||||
|
hdr_rw->total_size = le_to_be(total_size);
|
||||||
|
}
|
||||||
|
auto tables_rw = reinterpret_cast<Table *>(addr + 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(addr, mmap_sz);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||||
|
auto len = fdt_totalsize(dtb + i);
|
||||||
|
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
|
||||||
|
memcpy(fdt, dtb + i, 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);
|
||||||
|
i += len - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
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 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0)
|
||||||
|
|
||||||
|
[[maybe_unused]] static int dtb_patch(const char *in, const char *out) {
|
||||||
|
if (!out)
|
||||||
|
out = in;
|
||||||
|
size_t dtb_sz ;
|
||||||
|
uint8_t *dtb;
|
||||||
|
fprintf(stderr, "Loading dtbs from [%s]\n", in);
|
||||||
|
mmap_ro(in, dtb, dtb_sz);
|
||||||
|
run_finally f([&]{ munmap(dtb, dtb_sz); });
|
||||||
|
|
||||||
|
if (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, out);
|
||||||
|
case 2:
|
||||||
|
fprintf(stderr, "QCDT v2\n");
|
||||||
|
return dt_table_patch<qctable_v2>(hdr, out);
|
||||||
|
case 3:
|
||||||
|
fprintf(stderr, "QCDT v3\n");
|
||||||
|
return dt_table_patch<qctable_v3>(hdr, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (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, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (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, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (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, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (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, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (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, out);
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return blob_patch(dtb, dtb_sz, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,6 @@ int hexpatch(const char *image, const char *from, const char *to);
|
|||||||
int cpio_commands(int argc, char *argv[]);
|
int cpio_commands(int argc, char *argv[]);
|
||||||
int dtb_commands(int argc, char *argv[]);
|
int dtb_commands(int argc, char *argv[]);
|
||||||
|
|
||||||
char *patch_verity(const void *buf, uint32_t &size, bool inplace = false);
|
uint32_t patch_verity(void *buf, uint32_t size);
|
||||||
void patch_encryption(void *buf, uint32_t &size);
|
uint32_t patch_encryption(void *buf, uint32_t size);
|
||||||
bool check_env(const char *name);
|
bool check_env(const char *name);
|
||||||
|
@ -42,7 +42,7 @@ Supported actions:
|
|||||||
Search <hexpattern1> in <file>, and replace with <hexpattern2>
|
Search <hexpattern1> in <file>, and replace with <hexpattern2>
|
||||||
|
|
||||||
cpio <incpio> [commands...]
|
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
|
Each command is a single argument, add quotes for each command
|
||||||
Supported commands:
|
Supported commands:
|
||||||
exists ENTRY
|
exists ENTRY
|
||||||
@ -64,8 +64,8 @@ Supported actions:
|
|||||||
Return values:
|
Return values:
|
||||||
0:stock 1:Magisk 2:unsupported (phh, SuperSU, Xposed)
|
0:stock 1:Magisk 2:unsupported (phh, SuperSU, Xposed)
|
||||||
patch
|
patch
|
||||||
Apply ramdisk patches. Configure settings with env variables:
|
Apply ramdisk patches
|
||||||
KEEPVERITY KEEPFORCEENCRYPT
|
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
|
||||||
backup ORIG
|
backup ORIG
|
||||||
Create ramdisk backups from ORIG
|
Create ramdisk backups from ORIG
|
||||||
restore
|
restore
|
||||||
@ -79,10 +79,10 @@ Supported actions:
|
|||||||
print [-f]
|
print [-f]
|
||||||
Print all contents of dtb for debugging
|
Print all contents of dtb for debugging
|
||||||
Specify [-f] to only print fstab nodes
|
Specify [-f] to only print fstab nodes
|
||||||
patch [OUT]
|
patch
|
||||||
Search for fstab and remove verity/avb
|
Search for fstab and remove verity/avb
|
||||||
If [OUT] is not specified, it will directly output to <input>
|
Modifications are done directly to the file in-place
|
||||||
Configure with env variables: KEEPVERITY TWOSTAGEINIT
|
Configure with env variables: KEEPVERITY
|
||||||
|
|
||||||
split <input>
|
split <input>
|
||||||
Split image.*-dtb into kernel + kernel_dtb
|
Split image.*-dtb into kernel + kernel_dtb
|
||||||
@ -186,7 +186,7 @@ int main(int argc, char *argv[]) {
|
|||||||
} else if (argc > 2 && action == "cpio"sv) {
|
} else if (argc > 2 && action == "cpio"sv) {
|
||||||
if (cpio_commands(argc - 2, argv + 2))
|
if (cpio_commands(argc - 2, argv + 2))
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
} else if (argc > 2 && action == "dtb") {
|
} else if (argc > 3 && action == "dtb") {
|
||||||
if (dtb_commands(argc - 2, argv + 2))
|
if (dtb_commands(argc - 2, argv + 2))
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,42 +37,27 @@ static int check_encryption_pattern(const char *s) {
|
|||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *patch_verity(const void *buf, uint32_t &size, bool inplace) {
|
static uint32_t remove_pattern(void *buf, uint32_t size, int(*pattern_skip)(const char *)) {
|
||||||
auto src = static_cast<const char *>(buf);
|
auto src = static_cast<char *>(buf);
|
||||||
auto dest = (char *)(inplace ? buf : xmalloc(size));
|
int orig_sz = size;
|
||||||
int src_size = size;
|
|
||||||
bool found = false;
|
|
||||||
int write = 0;
|
int write = 0;
|
||||||
for (int read = 0; read < src_size;) {
|
for (int read = 0; read < orig_sz;) {
|
||||||
if (int skip; (skip = check_verity_pattern(src + read)) > 0) {
|
if (int skip = pattern_skip(src + read); skip > 0) {
|
||||||
fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read);
|
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
|
||||||
size -= skip;
|
size -= skip;
|
||||||
read += skip;
|
read += skip;
|
||||||
found = true;
|
|
||||||
} else {
|
} else {
|
||||||
dest[write++] = src[read++];
|
src[write++] = src[read++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dest[write] = '\0';
|
memset(src + write, 0, orig_sz - write);
|
||||||
if (!found) {
|
return size;
|
||||||
if (!inplace)
|
|
||||||
free(dest);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void patch_encryption(void *buf, uint32_t &size) {
|
uint32_t patch_verity(void *buf, uint32_t size) {
|
||||||
auto src = static_cast<char *>(buf);
|
return remove_pattern(buf, size, check_verity_pattern);
|
||||||
int src_size = size;
|
}
|
||||||
int write = 0;
|
|
||||||
for (int read = 0; read < src_size; ++read, ++write) {
|
uint32_t patch_encryption(void *buf, uint32_t size) {
|
||||||
if (int skip; (skip = check_encryption_pattern(src + read)) > 0) {
|
return remove_pattern(buf, size, check_encryption_pattern);
|
||||||
fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read);
|
|
||||||
size -= skip;
|
|
||||||
read += skip;
|
|
||||||
}
|
|
||||||
src[write] = src[read];
|
|
||||||
}
|
|
||||||
src[write] = '\0';
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ void magisk_cpio::patch() {
|
|||||||
if (!keepverity) {
|
if (!keepverity) {
|
||||||
if (fstab) {
|
if (fstab) {
|
||||||
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
|
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") {
|
} else if (cur->first == "verity_key") {
|
||||||
rm(cur);
|
rm(cur);
|
||||||
continue;
|
continue;
|
||||||
@ -63,7 +63,7 @@ void magisk_cpio::patch() {
|
|||||||
}
|
}
|
||||||
if (!keepforceencrypt) {
|
if (!keepforceencrypt) {
|
||||||
if (fstab) {
|
if (fstab) {
|
||||||
patch_encryption(cur->second->data, cur->second->filesize);
|
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user