Convert indentation to spaces

The tab war is lost
This commit is contained in:
topjohnwu
2020-12-30 22:11:24 -08:00
parent 947a7d6a2f
commit f9bde347bc
78 changed files with 10945 additions and 10945 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,35 +9,35 @@
*****************/
struct mtk_hdr {
uint32_t magic; /* MTK magic */
uint32_t size; /* Size of the content */
char name[32]; /* The type of the header */
uint32_t magic; /* MTK magic */
uint32_t size; /* Size of the content */
char name[32]; /* The type of the header */
char padding[472]; /* Padding to 512 bytes */
char padding[472]; /* Padding to 512 bytes */
} __attribute__((packed));
struct dhtb_hdr {
char magic[8]; /* DHTB magic */
uint8_t checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
char magic[8]; /* DHTB magic */
uint8_t checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
char padding[460]; /* Padding to 512 bytes */
char padding[460]; /* Padding to 512 bytes */
} __attribute__((packed));
struct blob_hdr {
char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */
uint32_t datalen; /* 0x00000000 */
uint32_t signature; /* 0x00000000 */
char magic[16]; /* "MSM-RADIO-UPDATE" */
uint32_t hdr_version; /* 0x00010000 */
uint32_t hdr_size; /* Size of header */
uint32_t part_offset; /* Same as size */
uint32_t num_parts; /* Number of partitions */
uint32_t unknown[7]; /* All 0x00000000 */
char name[4]; /* Name of partition */
uint32_t offset; /* offset in blob where this partition starts */
uint32_t size; /* Size of data */
uint32_t version; /* 0x00000001 */
char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */
uint32_t datalen; /* 0x00000000 */
uint32_t signature; /* 0x00000000 */
char magic[16]; /* "MSM-RADIO-UPDATE" */
uint32_t hdr_version; /* 0x00010000 */
uint32_t hdr_size; /* Size of header */
uint32_t part_offset; /* Same as size */
uint32_t num_parts; /* Number of partitions */
uint32_t unknown[7]; /* All 0x00000000 */
char name[4]; /* Name of partition */
uint32_t offset; /* offset in blob where this partition starts */
uint32_t size; /* Size of data */
uint32_t version; /* 0x00000001 */
} __attribute__((packed));
@@ -78,54 +78,54 @@ struct blob_hdr {
*/
struct boot_img_hdr_common {
char magic[BOOT_MAGIC_SIZE];
char magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
} __attribute__((packed));
struct boot_img_hdr_v0 : public boot_img_hdr_common {
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
// In header v1, this field is used for header version
// However, on some devices like Samsung, this field is used to store DTB
// We treat this field differently based on its value
union {
uint32_t header_version; /* the version of the header */
uint32_t extra_size; /* extra blob size in bytes */
};
// In header v1, this field is used for header version
// However, on some devices like Samsung, this field is used to store DTB
// We treat this field differently based on its value
union {
uint32_t header_version; /* the version of the header */
uint32_t extra_size; /* extra blob size in bytes */
};
// Operating system version and security patch level.
// For version "A.B.C" and patch level "Y-M-D":
// (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
// os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
uint32_t os_version;
// Operating system version and security patch level.
// For version "A.B.C" and patch level "Y-M-D":
// (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
// os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
uint32_t os_version;
char name[BOOT_NAME_SIZE]; /* asciiz product name */
char cmdline[BOOT_ARGS_SIZE];
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
char name[BOOT_NAME_SIZE]; /* asciiz product name */
char cmdline[BOOT_ARGS_SIZE];
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
// Supplemental command line data; kept here to maintain
// binary compatibility with older versions of mkbootimg.
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
// Supplemental command line data; kept here to maintain
// binary compatibility with older versions of mkbootimg.
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
uint32_t header_size;
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
uint32_t header_size;
} __attribute__((packed));
struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
uint32_t dtb_size; /* size in bytes for DTB image */
uint64_t dtb_addr; /* physical load address for DTB image */
uint32_t dtb_size; /* size in bytes for DTB image */
uint64_t dtb_addr; /* physical load address for DTB image */
} __attribute__((packed));
// Default to hdr v2
@@ -133,16 +133,16 @@ using boot_img_hdr = boot_img_hdr_v2;
// Special Samsung header
struct boot_img_hdr_pxa : public boot_img_hdr_common {
uint32_t extra_size; /* extra blob size in bytes */
uint32_t unknown;
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t extra_size; /* extra blob size in bytes */
uint32_t unknown;
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
char name[24]; /* asciiz product name */
char cmdline[BOOT_ARGS_SIZE];
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
char name[24]; /* asciiz product name */
char cmdline[BOOT_ARGS_SIZE];
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
/* When the boot image header has a version of 3, the structure of the boot
@@ -178,34 +178,34 @@ struct boot_img_hdr_pxa : public boot_img_hdr_common {
*/
struct boot_img_hdr_v3 {
uint8_t magic[BOOT_MAGIC_SIZE];
uint8_t magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
uint32_t ramdisk_size; /* size in bytes */
uint32_t os_version;
uint32_t header_size;
uint32_t reserved[4];
uint32_t kernel_size; /* size in bytes */
uint32_t ramdisk_size; /* size in bytes */
uint32_t os_version;
uint32_t header_size;
uint32_t reserved[4];
uint32_t header_version;
uint32_t header_version;
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
struct boot_img_hdr_vnd_v3 {
// Must be VENDOR_BOOT_MAGIC.
uint8_t magic[BOOT_MAGIC_SIZE];
// Version of the vendor boot image header.
uint32_t header_version;
uint32_t page_size; /* flash page size we assume */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
char cmdline[VENDOR_BOOT_ARGS_SIZE];
uint32_t tags_addr; /* physical addr for kernel tags (if required) */
char name[BOOT_NAME_SIZE]; /* asciiz product name */
uint32_t header_size;
uint32_t dtb_size; /* size in bytes for DTB image */
uint64_t dtb_addr; /* physical load address for DTB image */
// Must be VENDOR_BOOT_MAGIC.
uint8_t magic[BOOT_MAGIC_SIZE];
// Version of the vendor boot image header.
uint32_t header_version;
uint32_t page_size; /* flash page size we assume */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
char cmdline[VENDOR_BOOT_ARGS_SIZE];
uint32_t tags_addr; /* physical addr for kernel tags (if required) */
char name[BOOT_NAME_SIZE]; /* asciiz product name */
uint32_t header_size;
uint32_t dtb_size; /* size in bytes for DTB image */
uint64_t dtb_addr; /* physical load address for DTB image */
} __attribute__((packed));
/*******************************
@@ -219,51 +219,51 @@ virtual type name() { return 0; }
struct dyn_img_hdr {
// Standard entries
decl_var(kernel_size, 32)
decl_var(ramdisk_size, 32)
decl_var(second_size, 32)
decl_var(page_size, 32)
decl_val(header_version, uint32_t)
decl_var(extra_size, 32)
decl_var(os_version, 32)
decl_val(name, char *)
decl_val(cmdline, char *)
decl_val(id, char *)
decl_val(extra_cmdline, char *)
// Standard entries
decl_var(kernel_size, 32)
decl_var(ramdisk_size, 32)
decl_var(second_size, 32)
decl_var(page_size, 32)
decl_val(header_version, uint32_t)
decl_var(extra_size, 32)
decl_var(os_version, 32)
decl_val(name, char *)
decl_val(cmdline, char *)
decl_val(id, char *)
decl_val(extra_cmdline, char *)
// v1/v2 specific
decl_var(recovery_dtbo_size, 32)
decl_var(recovery_dtbo_offset, 64)
decl_var(header_size, 32)
decl_var(dtb_size, 32)
// v1/v2 specific
decl_var(recovery_dtbo_size, 32)
decl_var(recovery_dtbo_offset, 64)
decl_var(header_size, 32)
decl_var(dtb_size, 32)
virtual ~dyn_img_hdr() {
free(raw);
}
virtual ~dyn_img_hdr() {
free(raw);
}
virtual size_t hdr_size() = 0;
virtual size_t hdr_space() { return page_size(); }
virtual size_t hdr_size() = 0;
virtual size_t hdr_space() { return page_size(); }
const void *raw_hdr() const { return raw; }
void print();
void dump_hdr_file();
void load_hdr_file();
const void *raw_hdr() const { return raw; }
void print();
void dump_hdr_file();
void load_hdr_file();
protected:
union {
// Main header could be either AOSP or PXA
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
boot_img_hdr_vnd_v3 *vnd; /* AOSP vendor v3 header */
void *raw; /* Raw pointer */
};
union {
// Main header could be either AOSP or PXA
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
boot_img_hdr_vnd_v3 *vnd; /* AOSP vendor v3 header */
void *raw; /* Raw pointer */
};
private:
// Junk for references
static uint32_t j32;
static uint64_t j64;
// Junk for references
static uint32_t j32;
static uint64_t j64;
};
#undef decl_var
@@ -273,8 +273,8 @@ private:
protected: name() = default; \
public: \
name(void *ptr) { \
raw = xmalloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \
raw = xmalloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \
} \
size_t hdr_size() override { return sizeof(hdr); }
@@ -285,93 +285,93 @@ decltype(std::declval<dyn_img_hdr>().name()) name() override { return hdr_name->
#define impl_val(name) __impl_val(name, v2_hdr)
struct dyn_img_common : public dyn_img_hdr {
impl_val(kernel_size)
impl_val(ramdisk_size)
impl_val(second_size)
impl_val(kernel_size)
impl_val(ramdisk_size)
impl_val(second_size)
};
struct dyn_img_v0 : public dyn_img_common {
impl_cls(v0)
impl_cls(v0)
impl_val(page_size)
impl_val(extra_size)
impl_val(os_version)
impl_val(name)
impl_val(cmdline)
impl_val(id)
impl_val(extra_cmdline)
impl_val(page_size)
impl_val(extra_size)
impl_val(os_version)
impl_val(name)
impl_val(cmdline)
impl_val(id)
impl_val(extra_cmdline)
};
struct dyn_img_v1 : public dyn_img_v0 {
impl_cls(v1)
impl_cls(v1)
impl_val(header_version)
impl_val(recovery_dtbo_size)
impl_val(recovery_dtbo_offset)
impl_val(header_size)
impl_val(header_version)
impl_val(recovery_dtbo_size)
impl_val(recovery_dtbo_offset)
impl_val(header_size)
uint32_t &extra_size() override { return dyn_img_hdr::extra_size(); }
uint32_t &extra_size() override { return dyn_img_hdr::extra_size(); }
};
struct dyn_img_v2 : public dyn_img_v1 {
impl_cls(v2)
impl_cls(v2)
impl_val(dtb_size)
impl_val(dtb_size)
};
#undef impl_val
#define impl_val(name) __impl_val(name, hdr_pxa)
struct dyn_img_pxa : public dyn_img_common {
impl_cls(pxa)
impl_cls(pxa)
impl_val(extra_size)
impl_val(page_size)
impl_val(name)
impl_val(cmdline)
impl_val(id)
impl_val(extra_cmdline)
impl_val(extra_size)
impl_val(page_size)
impl_val(name)
impl_val(cmdline)
impl_val(id)
impl_val(extra_cmdline)
};
#undef impl_val
#define impl_val(name) __impl_val(name, v3_hdr)
struct dyn_img_v3 : public dyn_img_hdr {
impl_cls(v3)
impl_cls(v3)
impl_val(kernel_size)
impl_val(ramdisk_size)
impl_val(os_version)
impl_val(header_size)
impl_val(header_version)
impl_val(cmdline)
impl_val(kernel_size)
impl_val(ramdisk_size)
impl_val(os_version)
impl_val(header_size)
impl_val(header_version)
impl_val(cmdline)
// Make API compatible
uint32_t &page_size() override { page_sz = 4096; return page_sz; }
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; }
// Make API compatible
uint32_t &page_size() override { page_sz = 4096; return page_sz; }
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; }
private:
uint32_t page_sz;
uint32_t page_sz;
};
#undef impl_val
#define impl_val(name) __impl_val(name, vnd)
struct dyn_img_vnd_v3 : public dyn_img_hdr {
impl_cls(vnd_v3)
impl_cls(vnd_v3)
impl_val(header_version)
impl_val(page_size)
impl_val(ramdisk_size)
impl_val(cmdline)
impl_val(name)
impl_val(header_size)
impl_val(dtb_size)
impl_val(header_version)
impl_val(page_size)
impl_val(ramdisk_size)
impl_val(cmdline)
impl_val(name)
impl_val(header_size)
impl_val(dtb_size)
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
// Make API compatible
char *extra_cmdline() override { return &vnd->cmdline[BOOT_ARGS_SIZE]; }
// Make API compatible
char *extra_cmdline() override { return &vnd->cmdline[BOOT_ARGS_SIZE]; }
};
#undef __impl_cls
@@ -395,48 +395,48 @@ struct dyn_img_vnd_v3 : public dyn_img_hdr {
#define ACCLAIM_FLAG (1 << 9)
struct boot_img {
// Memory map of the whole image
uint8_t *map_addr;
size_t map_size;
// Memory map of the whole image
uint8_t *map_addr;
size_t map_size;
// Android image header
dyn_img_hdr *hdr;
// Android image header
dyn_img_hdr *hdr;
// Flags to indicate the state of current boot image
uint16_t flags = 0;
// Flags to indicate the state of current boot image
uint16_t flags = 0;
// The format of kernel, ramdisk and extra
format_t k_fmt = UNKNOWN;
format_t r_fmt = UNKNOWN;
format_t e_fmt = UNKNOWN;
// The format of kernel, ramdisk and extra
format_t k_fmt = UNKNOWN;
format_t r_fmt = UNKNOWN;
format_t e_fmt = UNKNOWN;
/***************************************************
* Following pointers points within the mmap region
***************************************************/
/***************************************************
* Following pointers points within the mmap region
***************************************************/
// MTK headers
mtk_hdr *k_hdr;
mtk_hdr *r_hdr;
// MTK headers
mtk_hdr *k_hdr;
mtk_hdr *r_hdr;
// Pointer to dtb that is embedded in kernel
uint8_t *kernel_dtb;
uint32_t kernel_dt_size = 0;
// Pointer to dtb that is embedded in kernel
uint8_t *kernel_dtb;
uint32_t kernel_dt_size = 0;
// Pointer to end of image
uint8_t *tail;
size_t tail_size = 0;
// Pointer to end of image
uint8_t *tail;
size_t tail_size = 0;
// Pointers to blocks defined in header
uint8_t *hdr_addr;
uint8_t *kernel;
uint8_t *ramdisk;
uint8_t *second;
uint8_t *extra;
uint8_t *recovery_dtbo;
uint8_t *dtb;
// Pointers to blocks defined in header
uint8_t *hdr_addr;
uint8_t *kernel;
uint8_t *ramdisk;
uint8_t *second;
uint8_t *extra;
uint8_t *recovery_dtbo;
uint8_t *dtb;
boot_img(const char *);
~boot_img();
boot_img(const char *);
~boot_img();
void parse_image(uint8_t *addr, format_t type);
void parse_image(uint8_t *addr, format_t type);
};

File diff suppressed because it is too large Load Diff

View File

@@ -18,437 +18,437 @@ constexpr int MAX_DEPTH = 32;
static bitset<MAX_DEPTH> depth_set;
static void pretty_node(int depth) {
if (depth == 0)
return;
if (depth == 0)
return;
for (int i = 0; i < depth - 1; ++i)
printf(depth_set[i] ? "" : " ");
for (int i = 0; i < depth - 1; ++i)
printf(depth_set[i] ? "" : " ");
printf(depth_set[depth - 1] ? "├── " : "└── ");
printf(depth_set[depth - 1] ? "├── " : "└── ");
}
static void pretty_prop(int depth) {
for (int i = 0; i < depth; ++i)
printf(depth_set[i] ? "" : " ");
for (int i = 0; i < depth; ++i)
printf(depth_set[i] ? "" : " ");
printf(depth_set[depth] ? "" : " ");
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 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));
// 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;
}
}
}
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);
}
}
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);
}
// 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 (fdt_get_name(fdt, node, nullptr) == "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;
if (fdt_get_name(fdt, node, nullptr) == "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;
}
static void dtb_print(const char *file, bool fstab) {
size_t size;
uint8_t *dtb;
fprintf(stderr, "Loading dtbs from [%s]\n", file);
mmap_ro(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;
if (fstab) {
int node = find_fstab(fdt);
if (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;
i += fdt_totalsize(fdt) - 1;
}
}
fprintf(stderr, "\n");
munmap(dtb, size);
size_t size;
uint8_t *dtb;
fprintf(stderr, "Loading dtbs from [%s]\n", file);
mmap_ro(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;
if (fstab) {
int node = find_fstab(fdt);
if (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;
i += fdt_totalsize(fdt) - 1;
}
}
fprintf(stderr, "\n");
munmap(dtb, size);
}
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;
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;
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;
}
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
// 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;
};
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;
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;
};
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<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;
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;
}
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);
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>;
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; };
}
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;
// 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;
// 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);
unlink(out);
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
uint32_t total_size = 0;
uint32_t total_size = 0;
// Copy headers and tables
total_size += xwrite(fd, buf, dtb_map.begin()->first);
// 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);
// 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);
}
// 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);
}
// 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);
}
// 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);
munmap(addr, mmap_sz);
close(fd);
return 0;
}
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;
}
}
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;
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
return 1;
unlink(out);
int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
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);
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;
}
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); });
[[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);
}
}
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);
}
}
}

View File

@@ -11,94 +11,94 @@
#define SPRD_MAGIC "SPRD"
struct qcdt_hdr {
char magic[4]; /* "QCDT" */
uint32_t version; /* QCDT version */
uint32_t num_dtbs; /* Number of DTBs */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 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 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 */
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 len; /* DTB size */
uint32_t offset;
uint32_t id;
uint32_t rev;
uint32_t flags;
uint32_t id;
uint32_t rev;
uint32_t flags;
uint32_t custom[3];
uint32_t custom[3];
} __attribute__((packed));

View File

@@ -8,15 +8,15 @@ Fmt2Ext fmt2ext;
class FormatInit {
public:
FormatInit() {
name2fmt["gzip"] = GZIP;
name2fmt["xz"] = XZ;
name2fmt["lzma"] = LZMA;
name2fmt["bzip2"] = BZIP2;
name2fmt["lz4"] = LZ4;
name2fmt["lz4_legacy"] = LZ4_LEGACY;
name2fmt["lz4_lg"] = LZ4_LG;
}
FormatInit() {
name2fmt["gzip"] = GZIP;
name2fmt["xz"] = XZ;
name2fmt["lzma"] = LZMA;
name2fmt["bzip2"] = BZIP2;
name2fmt["lz4"] = LZ4;
name2fmt["lz4_legacy"] = LZ4_LEGACY;
name2fmt["lz4_lg"] = LZ4_LG;
}
};
static FormatInit init;
@@ -24,82 +24,82 @@ static FormatInit init;
#define MATCH(s) (len >= (sizeof(s) - 1) && memcmp(buf, s, sizeof(s) - 1) == 0)
format_t check_fmt(const void *buf, size_t len) {
if (MATCH(CHROMEOS_MAGIC)) {
return CHROMEOS;
} else if (MATCH(BOOT_MAGIC)) {
return AOSP;
} else if (MATCH(VENDOR_BOOT_MAGIC)) {
return AOSP_VENDOR;
} else if (MATCH(GZIP1_MAGIC) || MATCH(GZIP2_MAGIC)) {
return GZIP;
} else if (MATCH(LZOP_MAGIC)) {
return LZOP;
} else if (MATCH(XZ_MAGIC)) {
return XZ;
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
return LZMA;
} else if (MATCH(BZIP_MAGIC)) {
return BZIP2;
} else if (MATCH(LZ41_MAGIC) || MATCH(LZ42_MAGIC)) {
return LZ4;
} else if (MATCH(LZ4_LEG_MAGIC)) {
return LZ4_LEGACY;
} else if (MATCH(MTK_MAGIC)) {
return MTK;
} else if (MATCH(DTB_MAGIC)) {
return DTB;
} else if (MATCH(DHTB_MAGIC)) {
return DHTB;
} else if (MATCH(TEGRABLOB_MAGIC)) {
return BLOB;
} else {
return UNKNOWN;
}
if (MATCH(CHROMEOS_MAGIC)) {
return CHROMEOS;
} else if (MATCH(BOOT_MAGIC)) {
return AOSP;
} else if (MATCH(VENDOR_BOOT_MAGIC)) {
return AOSP_VENDOR;
} else if (MATCH(GZIP1_MAGIC) || MATCH(GZIP2_MAGIC)) {
return GZIP;
} else if (MATCH(LZOP_MAGIC)) {
return LZOP;
} else if (MATCH(XZ_MAGIC)) {
return XZ;
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
return LZMA;
} else if (MATCH(BZIP_MAGIC)) {
return BZIP2;
} else if (MATCH(LZ41_MAGIC) || MATCH(LZ42_MAGIC)) {
return LZ4;
} else if (MATCH(LZ4_LEG_MAGIC)) {
return LZ4_LEGACY;
} else if (MATCH(MTK_MAGIC)) {
return MTK;
} else if (MATCH(DTB_MAGIC)) {
return DTB;
} else if (MATCH(DHTB_MAGIC)) {
return DHTB;
} else if (MATCH(TEGRABLOB_MAGIC)) {
return BLOB;
} else {
return UNKNOWN;
}
}
const char *Fmt2Name::operator[](format_t fmt) {
switch (fmt) {
case GZIP:
return "gzip";
case LZOP:
return "lzop";
case XZ:
return "xz";
case LZMA:
return "lzma";
case BZIP2:
return "bzip2";
case LZ4:
return "lz4";
case LZ4_LEGACY:
return "lz4_legacy";
case LZ4_LG:
return "lz4_lg";
case DTB:
return "dtb";
default:
return "raw";
}
switch (fmt) {
case GZIP:
return "gzip";
case LZOP:
return "lzop";
case XZ:
return "xz";
case LZMA:
return "lzma";
case BZIP2:
return "bzip2";
case LZ4:
return "lz4";
case LZ4_LEGACY:
return "lz4_legacy";
case LZ4_LG:
return "lz4_lg";
case DTB:
return "dtb";
default:
return "raw";
}
}
const char *Fmt2Ext::operator[](format_t fmt) {
switch (fmt) {
case GZIP:
return ".gz";
case LZOP:
return ".lzo";
case XZ:
return ".xz";
case LZMA:
return ".lzma";
case BZIP2:
return ".bz2";
case LZ4:
case LZ4_LEGACY:
case LZ4_LG:
return ".lz4";
default:
return "";
}
switch (fmt) {
case GZIP:
return ".gz";
case LZOP:
return ".lzo";
case XZ:
return ".xz";
case LZMA:
return ".lzma";
case BZIP2:
return ".bz2";
case LZ4:
case LZ4_LEGACY:
case LZ4_LG:
return ".lz4";
default:
return "";
}
}

View File

@@ -4,26 +4,26 @@
#include <string_view>
typedef enum {
UNKNOWN,
UNKNOWN,
/* Boot formats */
CHROMEOS,
AOSP,
AOSP_VENDOR,
DHTB,
BLOB,
CHROMEOS,
AOSP,
AOSP_VENDOR,
DHTB,
BLOB,
/* Compression formats */
GZIP,
XZ,
LZMA,
BZIP2,
LZ4,
LZ4_LEGACY,
LZ4_LG,
GZIP,
XZ,
LZMA,
BZIP2,
LZ4,
LZ4_LEGACY,
LZ4_LG,
/* Unsupported compression */
LZOP,
LZOP,
/* Misc */
MTK,
DTB,
MTK,
DTB,
} format_t;
#define COMPRESSED(fmt) ((fmt) >= GZIP && (fmt) < LZOP)
@@ -57,12 +57,12 @@ typedef enum {
class Fmt2Name {
public:
const char *operator[](format_t fmt);
const char *operator[](format_t fmt);
};
class Fmt2Ext {
public:
const char *operator[](format_t fmt);
const char *operator[](format_t fmt);
};
format_t check_fmt(const void *buf, size_t len);

View File

@@ -8,36 +8,36 @@
#include "magiskboot.hpp"
static void hex2byte(uint8_t *hex, uint8_t *str) {
char high, low;
for (int i = 0, length = strlen((char *) hex); i < length; i += 2) {
high = toupper(hex[i]) - '0';
low = toupper(hex[i + 1]) - '0';
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
}
char high, low;
for (int i = 0, length = strlen((char *) hex); i < length; i += 2) {
high = toupper(hex[i]) - '0';
low = toupper(hex[i + 1]) - '0';
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
}
}
int hexpatch(const char *image, const char *from, const char *to) {
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
int patched = 1;
size_t filesize;
uint8_t *file, *pattern, *patch;
mmap_rw(image, file, filesize);
pattern = (uint8_t *) xmalloc(patternsize);
patch = (uint8_t *) xmalloc(patchsize);
hex2byte((uint8_t *) from, pattern);
hex2byte((uint8_t *) to, patch);
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
if (memcmp(file + i, pattern, patternsize) == 0) {
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
memset(file + i, 0, patternsize);
memcpy(file + i, patch, patchsize);
i += patternsize - 1;
patched = 0;
}
}
munmap(file, filesize);
free(pattern);
free(patch);
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
int patched = 1;
size_t filesize;
uint8_t *file, *pattern, *patch;
mmap_rw(image, file, filesize);
pattern = (uint8_t *) xmalloc(patternsize);
patch = (uint8_t *) xmalloc(patchsize);
hex2byte((uint8_t *) from, pattern);
hex2byte((uint8_t *) to, patch);
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
if (memcmp(file + i, pattern, patternsize) == 0) {
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
memset(file + i, 0, patternsize);
memcpy(file + i, patch, patchsize);
i += patternsize - 1;
patched = 0;
}
}
munmap(file, filesize);
free(pattern);
free(patch);
return patched;
return patched;
}

View File

@@ -13,7 +13,7 @@
using namespace std;
static void usage(char *arg0) {
fprintf(stderr,
fprintf(stderr,
R"EOF(MagiskBoot - Boot Image Modification Tool
Usage: %s <action> [args...]
@@ -96,100 +96,100 @@ Supported actions:
<infile>/[outfile] can be '-' to be STDIN/STDOUT
Supported methods: )EOF", arg0);
for (auto &it : name2fmt)
fprintf(stderr, "%s ", it.first.data());
for (auto &it : name2fmt)
fprintf(stderr, "%s ", it.first.data());
fprintf(stderr, R"EOF(
fprintf(stderr, R"EOF(
decompress <infile> [outfile]
Detect method and decompress <infile>, optionally to [outfile]
<infile>/[outfile] can be '-' to be STDIN/STDOUT
Supported methods: )EOF");
for (auto &it : name2fmt)
fprintf(stderr, "%s ", it.first.data());
for (auto &it : name2fmt)
fprintf(stderr, "%s ", it.first.data());
fprintf(stderr, "\n\n");
exit(1);
fprintf(stderr, "\n\n");
exit(1);
}
int main(int argc, char *argv[]) {
cmdline_logging();
umask(0);
cmdline_logging();
umask(0);
if (argc < 2)
usage(argv[0]);
if (argc < 2)
usage(argv[0]);
// Skip '--' for backwards compatibility
string_view action(argv[1]);
if (str_starts(action, "--"))
action = argv[1] + 2;
// Skip '--' for backwards compatibility
string_view action(argv[1]);
if (str_starts(action, "--"))
action = argv[1] + 2;
if (action == "cleanup") {
fprintf(stderr, "Cleaning up...\n");
unlink(HEADER_FILE);
unlink(KERNEL_FILE);
unlink(RAMDISK_FILE);
unlink(SECOND_FILE);
unlink(KER_DTB_FILE);
unlink(EXTRA_FILE);
unlink(RECV_DTBO_FILE);
unlink(DTB_FILE);
} else if (argc > 2 && action == "sha1") {
uint8_t sha1[SHA_DIGEST_SIZE];
void *buf;
size_t size;
mmap_ro(argv[2], buf, size);
SHA_hash(buf, size, sha1);
for (uint8_t i : sha1)
printf("%02x", i);
printf("\n");
munmap(buf, size);
} else if (argc > 2 && action == "split") {
return split_image_dtb(argv[2]);
} else if (argc > 2 && action == "unpack") {
int idx = 2;
bool nodecomp = false;
bool hdr = false;
for (;;) {
if (idx >= argc)
usage(argv[0]);
if (argv[idx][0] != '-')
break;
for (char *flag = &argv[idx][1]; *flag; ++flag) {
if (*flag == 'n')
nodecomp = true;
else if (*flag == 'h')
hdr = true;
else
usage(argv[0]);
}
++idx;
}
return unpack(argv[idx], nodecomp, hdr);
} else if (argc > 2 && action == "repack") {
if (argv[2] == "-n"sv) {
if (argc == 3)
usage(argv[0]);
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
} else {
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
}
} else if (argc > 2 && action == "decompress") {
decompress(argv[2], argv[3]);
} else if (argc > 2 && str_starts(action, "compress")) {
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
} else if (argc > 4 && action == "hexpatch") {
return hexpatch(argv[2], argv[3], argv[4]);
} else if (argc > 2 && action == "cpio"sv) {
if (cpio_commands(argc - 2, argv + 2))
usage(argv[0]);
} else if (argc > 3 && action == "dtb") {
if (dtb_commands(argc - 2, argv + 2))
usage(argv[0]);
} else {
usage(argv[0]);
}
if (action == "cleanup") {
fprintf(stderr, "Cleaning up...\n");
unlink(HEADER_FILE);
unlink(KERNEL_FILE);
unlink(RAMDISK_FILE);
unlink(SECOND_FILE);
unlink(KER_DTB_FILE);
unlink(EXTRA_FILE);
unlink(RECV_DTBO_FILE);
unlink(DTB_FILE);
} else if (argc > 2 && action == "sha1") {
uint8_t sha1[SHA_DIGEST_SIZE];
void *buf;
size_t size;
mmap_ro(argv[2], buf, size);
SHA_hash(buf, size, sha1);
for (uint8_t i : sha1)
printf("%02x", i);
printf("\n");
munmap(buf, size);
} else if (argc > 2 && action == "split") {
return split_image_dtb(argv[2]);
} else if (argc > 2 && action == "unpack") {
int idx = 2;
bool nodecomp = false;
bool hdr = false;
for (;;) {
if (idx >= argc)
usage(argv[0]);
if (argv[idx][0] != '-')
break;
for (char *flag = &argv[idx][1]; *flag; ++flag) {
if (*flag == 'n')
nodecomp = true;
else if (*flag == 'h')
hdr = true;
else
usage(argv[0]);
}
++idx;
}
return unpack(argv[idx], nodecomp, hdr);
} else if (argc > 2 && action == "repack") {
if (argv[2] == "-n"sv) {
if (argc == 3)
usage(argv[0]);
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
} else {
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
}
} else if (argc > 2 && action == "decompress") {
decompress(argv[2], argv[3]);
} else if (argc > 2 && str_starts(action, "compress")) {
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
} else if (argc > 4 && action == "hexpatch") {
return hexpatch(argv[2], argv[3], argv[4]);
} else if (argc > 2 && action == "cpio"sv) {
if (cpio_commands(argc - 2, argv + 2))
usage(argv[0]);
} else if (argc > 3 && action == "dtb") {
if (dtb_commands(argc - 2, argv + 2))
usage(argv[0]);
} else {
usage(argv[0]);
}
return 0;
return 0;
}

View File

@@ -8,56 +8,56 @@
#define MATCH(p) else if (strncmp(s + skip, p, sizeof(p) - 1) == 0) skip += (sizeof(p) - 1)
static int check_verity_pattern(const char *s) {
int skip = s[0] == ',';
int skip = s[0] == ',';
if (0) {}
MATCH("verifyatboot");
MATCH("verify");
MATCH("avb_keys");
MATCH("avb");
MATCH("support_scfs");
MATCH("fsverity");
else return -1;
if (0) {}
MATCH("verifyatboot");
MATCH("verify");
MATCH("avb_keys");
MATCH("avb");
MATCH("support_scfs");
MATCH("fsverity");
else return -1;
if (s[skip] == '=') {
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',')
++skip;
}
return skip;
if (s[skip] == '=') {
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',')
++skip;
}
return skip;
}
#undef MATCH
#define MATCH(p) else if (strncmp(s, p, sizeof(p) - 1) == 0) return (sizeof(p) - 1)
static int check_encryption_pattern(const char *s) {
if (0) {}
MATCH("forceencrypt");
MATCH("forcefdeorfbe");
MATCH("fileencryption");
else return -1;
if (0) {}
MATCH("forceencrypt");
MATCH("forcefdeorfbe");
MATCH("fileencryption");
else return -1;
}
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 < orig_sz;) {
if (int skip = pattern_skip(src + read); skip > 0) {
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
size -= skip;
read += skip;
} else {
src[write++] = src[read++];
}
}
memset(src + write, 0, orig_sz - write);
return size;
auto src = static_cast<char *>(buf);
int orig_sz = size;
int write = 0;
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;
} else {
src[write++] = src[read++];
}
}
memset(src + write, 0, orig_sz - write);
return size;
}
uint32_t patch_verity(void *buf, uint32_t size) {
return remove_pattern(buf, size, check_verity_pattern);
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);
return remove_pattern(buf, size, check_encryption_pattern);
}

View File

@@ -13,60 +13,60 @@ using namespace std;
constexpr char RAMDISK_XZ[] = "ramdisk.cpio.xz";
static const char *UNSUPPORT_LIST[] =
{ "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc",
"boot/sbin/launch_daemonsu.sh" };
{ "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc",
"boot/sbin/launch_daemonsu.sh" };
static const char *MAGISK_LIST[] =
{ ".backup/.magisk", "init.magisk.rc",
"overlay/init.magisk.rc" };
{ ".backup/.magisk", "init.magisk.rc",
"overlay/init.magisk.rc" };
class magisk_cpio : public cpio_rw {
public:
magisk_cpio() = default;
explicit magisk_cpio(const char *filename) : cpio_rw(filename) {}
void patch();
int test();
char *sha1();
void restore();
void backup(const char *orig);
void compress();
void decompress();
magisk_cpio() = default;
explicit magisk_cpio(const char *filename) : cpio_rw(filename) {}
void patch();
int test();
char *sha1();
void restore();
void backup(const char *orig);
void compress();
void decompress();
};
bool check_env(const char *name) {
const char *val = getenv(name);
return val ? strcmp(val, "true") == 0 : false;
const char *val = getenv(name);
return val ? strcmp(val, "true") == 0 : false;
}
void magisk_cpio::patch() {
bool keepverity = check_env("KEEPVERITY");
bool keepforceencrypt = check_env("KEEPFORCEENCRYPT");
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
bool keepverity = check_env("KEEPVERITY");
bool keepforceencrypt = check_env("KEEPFORCEENCRYPT");
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
for (auto it = entries.begin(); it != entries.end();) {
auto cur = it++;
bool fstab = (!keepverity || !keepforceencrypt) &&
S_ISREG(cur->second->mode) &&
!str_starts(cur->first, ".backup") &&
!str_contains(cur->first, "twrp") &&
!str_contains(cur->first, "recovery") &&
str_contains(cur->first, "fstab");
if (!keepverity) {
if (fstab) {
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
cur->second->filesize = patch_verity(cur->second->data, cur->second->filesize);
} else if (cur->first == "verity_key") {
rm(cur);
continue;
}
}
if (!keepforceencrypt) {
if (fstab) {
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
}
}
}
for (auto it = entries.begin(); it != entries.end();) {
auto cur = it++;
bool fstab = (!keepverity || !keepforceencrypt) &&
S_ISREG(cur->second->mode) &&
!str_starts(cur->first, ".backup") &&
!str_contains(cur->first, "twrp") &&
!str_contains(cur->first, "recovery") &&
str_contains(cur->first, "fstab");
if (!keepverity) {
if (fstab) {
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
cur->second->filesize = patch_verity(cur->second->data, cur->second->filesize);
} else if (cur->first == "verity_key") {
rm(cur);
continue;
}
}
if (!keepforceencrypt) {
if (fstab) {
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
}
}
}
}
#define STOCK_BOOT 0
@@ -76,274 +76,274 @@ void magisk_cpio::patch() {
#define TWO_STAGE_INIT (1 << 3)
int magisk_cpio::test() {
for (auto file : UNSUPPORT_LIST)
if (exists(file))
return UNSUPPORTED_CPIO;
for (auto file : UNSUPPORT_LIST)
if (exists(file))
return UNSUPPORTED_CPIO;
int flags = STOCK_BOOT;
int flags = STOCK_BOOT;
if (exists(RAMDISK_XZ)) {
flags |= COMPRESSED_CPIO | MAGISK_PATCHED;
decompress();
}
if (exists(RAMDISK_XZ)) {
flags |= COMPRESSED_CPIO | MAGISK_PATCHED;
decompress();
}
if (exists("apex") || exists("first_stage_ramdisk"))
flags |= TWO_STAGE_INIT;
if (exists("apex") || exists("first_stage_ramdisk"))
flags |= TWO_STAGE_INIT;
for (auto file : MAGISK_LIST) {
if (exists(file)) {
flags |= MAGISK_PATCHED;
break;
}
}
for (auto file : MAGISK_LIST) {
if (exists(file)) {
flags |= MAGISK_PATCHED;
break;
}
}
return flags;
return flags;
}
#define for_each_line(line, buf, size) \
for (line = (char *) buf; line < (char *) buf + size && line[0]; line = strchr(line + 1, '\n') + 1)
char *magisk_cpio::sha1() {
decompress();
char sha1[41];
char *line;
for (auto &e : entries) {
if (e.first == "init.magisk.rc" || e.first == "overlay/init.magisk.rc") {
for_each_line(line, e.second->data, e.second->filesize) {
if (strncmp(line, "#STOCKSHA1=", 11) == 0) {
strncpy(sha1, line + 12, 40);
sha1[40] = '\0';
return strdup(sha1);
}
}
} else if (e.first == ".backup/.magisk") {
for_each_line(line, e.second->data, e.second->filesize) {
if (strncmp(line, "SHA1=", 5) == 0) {
strncpy(sha1, line + 5, 40);
sha1[40] = '\0';
return strdup(sha1);
}
}
} else if (e.first == ".backup/.sha1") {
return (char *) e.second->data;
}
}
return nullptr;
decompress();
char sha1[41];
char *line;
for (auto &e : entries) {
if (e.first == "init.magisk.rc" || e.first == "overlay/init.magisk.rc") {
for_each_line(line, e.second->data, e.second->filesize) {
if (strncmp(line, "#STOCKSHA1=", 11) == 0) {
strncpy(sha1, line + 12, 40);
sha1[40] = '\0';
return strdup(sha1);
}
}
} else if (e.first == ".backup/.magisk") {
for_each_line(line, e.second->data, e.second->filesize) {
if (strncmp(line, "SHA1=", 5) == 0) {
strncpy(sha1, line + 5, 40);
sha1[40] = '\0';
return strdup(sha1);
}
}
} else if (e.first == ".backup/.sha1") {
return (char *) e.second->data;
}
}
return nullptr;
}
#define for_each_str(str, buf, size) \
for (str = (char *) buf; str < (char *) buf + size; str = str += strlen(str) + 1)
void magisk_cpio::restore() {
decompress();
decompress();
if (auto it = entries.find(".backup/.rmlist"); it != entries.end()) {
char *file;
for_each_str(file, it->second->data, it->second->filesize)
rm(file, false);
rm(it);
}
if (auto it = entries.find(".backup/.rmlist"); it != entries.end()) {
char *file;
for_each_str(file, it->second->data, it->second->filesize)
rm(file, false);
rm(it);
}
for (auto it = entries.begin(); it != entries.end();) {
auto cur = it++;
if (str_starts(cur->first, ".backup")) {
if (cur->first.length() == 7 || cur->first.substr(8) == ".magisk") {
rm(cur);
} else {
mv(cur, &cur->first[8]);
}
} else if (str_starts(cur->first, "magisk") ||
cur->first == "overlay/init.magisk.rc" ||
cur->first == "sbin/magic_mask.sh" ||
cur->first == "init.magisk.rc") {
// Some known stuff we can remove
rm(cur);
}
}
for (auto it = entries.begin(); it != entries.end();) {
auto cur = it++;
if (str_starts(cur->first, ".backup")) {
if (cur->first.length() == 7 || cur->first.substr(8) == ".magisk") {
rm(cur);
} else {
mv(cur, &cur->first[8]);
}
} else if (str_starts(cur->first, "magisk") ||
cur->first == "overlay/init.magisk.rc" ||
cur->first == "sbin/magic_mask.sh" ||
cur->first == "init.magisk.rc") {
// Some known stuff we can remove
rm(cur);
}
}
}
void magisk_cpio::backup(const char *orig) {
if (access(orig, R_OK))
return;
entry_map bkup_entries;
string remv;
if (access(orig, R_OK))
return;
entry_map bkup_entries;
string remv;
auto b = new cpio_entry(".backup", S_IFDIR);
bkup_entries[b->filename].reset(b);
auto b = new cpio_entry(".backup", S_IFDIR);
bkup_entries[b->filename].reset(b);
magisk_cpio o(orig);
magisk_cpio o(orig);
// Remove possible backups in original ramdisk
o.rm(".backup", true);
rm(".backup", true);
// Remove possible backups in original ramdisk
o.rm(".backup", true);
rm(".backup", true);
auto lhs = o.entries.begin();
auto rhs = entries.begin();
auto lhs = o.entries.begin();
auto rhs = entries.begin();
while (lhs != o.entries.end() || rhs != entries.end()) {
int res;
bool backup = false;
if (lhs != o.entries.end() && rhs != entries.end()) {
res = lhs->first.compare(rhs->first);
} else if (lhs == o.entries.end()) {
res = 1;
} else {
res = -1;
}
while (lhs != o.entries.end() || rhs != entries.end()) {
int res;
bool backup = false;
if (lhs != o.entries.end() && rhs != entries.end()) {
res = lhs->first.compare(rhs->first);
} else if (lhs == o.entries.end()) {
res = 1;
} else {
res = -1;
}
if (res < 0) {
// Something is missing in new ramdisk, backup!
backup = true;
fprintf(stderr, "Backup missing entry: ");
} else if (res == 0) {
if (lhs->second->filesize != rhs->second->filesize ||
memcmp(lhs->second->data, rhs->second->data, lhs->second->filesize) != 0) {
// Not the same!
backup = true;
fprintf(stderr, "Backup mismatch entry: ");
}
} else {
// Something new in ramdisk
remv += rhs->first;
remv += (char) '\0';
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->first.data());
}
if (backup) {
string back_name(".backup/");
back_name += lhs->first;
fprintf(stderr, "[%s] -> [%s]\n", lhs->first.data(), back_name.data());
auto ex = static_cast<cpio_entry*>(lhs->second.release());
ex->filename = back_name;
bkup_entries[ex->filename].reset(ex);
}
if (res < 0) {
// Something is missing in new ramdisk, backup!
backup = true;
fprintf(stderr, "Backup missing entry: ");
} else if (res == 0) {
if (lhs->second->filesize != rhs->second->filesize ||
memcmp(lhs->second->data, rhs->second->data, lhs->second->filesize) != 0) {
// Not the same!
backup = true;
fprintf(stderr, "Backup mismatch entry: ");
}
} else {
// Something new in ramdisk
remv += rhs->first;
remv += (char) '\0';
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->first.data());
}
if (backup) {
string back_name(".backup/");
back_name += lhs->first;
fprintf(stderr, "[%s] -> [%s]\n", lhs->first.data(), back_name.data());
auto ex = static_cast<cpio_entry*>(lhs->second.release());
ex->filename = back_name;
bkup_entries[ex->filename].reset(ex);
}
// Increment positions
if (res < 0) {
++lhs;
} else if (res == 0) {
++lhs; ++rhs;
} else {
++rhs;
}
}
// Increment positions
if (res < 0) {
++lhs;
} else if (res == 0) {
++lhs; ++rhs;
} else {
++rhs;
}
}
if (!remv.empty()) {
auto rmlist = new cpio_entry(".backup/.rmlist", S_IFREG);
rmlist->filesize = remv.length();
rmlist->data = xmalloc(remv.length());
memcpy(rmlist->data, remv.data(), remv.length());
bkup_entries[rmlist->filename].reset(rmlist);
}
if (!remv.empty()) {
auto rmlist = new cpio_entry(".backup/.rmlist", S_IFREG);
rmlist->filesize = remv.length();
rmlist->data = xmalloc(remv.length());
memcpy(rmlist->data, remv.data(), remv.length());
bkup_entries[rmlist->filename].reset(rmlist);
}
if (bkup_entries.size() > 1)
entries.merge(bkup_entries);
if (bkup_entries.size() > 1)
entries.merge(bkup_entries);
}
void magisk_cpio::compress() {
if (exists(RAMDISK_XZ))
return;
fprintf(stderr, "Compressing cpio -> [%s]\n", RAMDISK_XZ);
auto init = entries.extract("init");
if (exists(RAMDISK_XZ))
return;
fprintf(stderr, "Compressing cpio -> [%s]\n", RAMDISK_XZ);
auto init = entries.extract("init");
uint8_t *data;
size_t len;
auto strm = make_stream_fp(get_encoder(XZ, make_unique<byte_stream>(data, len)));
dump(strm.release());
uint8_t *data;
size_t len;
auto strm = make_stream_fp(get_encoder(XZ, make_unique<byte_stream>(data, len)));
dump(strm.release());
entries.clear();
entries.insert(std::move(init));
auto xz = new cpio_entry(RAMDISK_XZ, S_IFREG);
xz->data = data;
xz->filesize = len;
insert(xz);
entries.clear();
entries.insert(std::move(init));
auto xz = new cpio_entry(RAMDISK_XZ, S_IFREG);
xz->data = data;
xz->filesize = len;
insert(xz);
}
void magisk_cpio::decompress() {
auto it = entries.find(RAMDISK_XZ);
if (it == entries.end())
return;
fprintf(stderr, "Decompressing cpio [%s]\n", RAMDISK_XZ);
auto it = entries.find(RAMDISK_XZ);
if (it == entries.end())
return;
fprintf(stderr, "Decompressing cpio [%s]\n", RAMDISK_XZ);
char *data;
size_t len;
{
auto strm = get_decoder(XZ, make_unique<byte_stream>(data, len));
strm->write(it->second->data, it->second->filesize);
}
char *data;
size_t len;
{
auto strm = get_decoder(XZ, make_unique<byte_stream>(data, len));
strm->write(it->second->data, it->second->filesize);
}
entries.erase(it);
load_cpio(data, len);
free(data);
entries.erase(it);
load_cpio(data, len);
free(data);
}
int cpio_commands(int argc, char *argv[]) {
char *incpio = argv[0];
++argv;
--argc;
char *incpio = argv[0];
++argv;
--argc;
magisk_cpio cpio;
if (access(incpio, R_OK) == 0)
cpio.load_cpio(incpio);
magisk_cpio cpio;
if (access(incpio, R_OK) == 0)
cpio.load_cpio(incpio);
int cmdc;
char *cmdv[6];
int cmdc;
char *cmdv[6];
while (argc) {
// Clean up
cmdc = 0;
memset(cmdv, NULL, sizeof(cmdv));
while (argc) {
// Clean up
cmdc = 0;
memset(cmdv, NULL, sizeof(cmdv));
// Split the commands
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(nullptr, " "))
cmdv[cmdc++] = tok;
// Split the commands
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(nullptr, " "))
cmdv[cmdc++] = tok;
if (cmdc == 0)
continue;
if (cmdc == 0)
continue;
if (strcmp(cmdv[0], "test") == 0) {
exit(cpio.test());
} else if (strcmp(cmdv[0], "restore") == 0) {
cpio.restore();
} else if (strcmp(cmdv[0], "sha1") == 0) {
char *sha1 = cpio.sha1();
if (sha1) printf("%s\n", sha1);
return 0;
} else if (strcmp(cmdv[0], "compress") == 0){
cpio.compress();
} else if (strcmp(cmdv[0], "decompress") == 0){
cpio.decompress();
} else if (strcmp(cmdv[0], "patch") == 0) {
cpio.patch();
} else if (cmdc == 2 && strcmp(cmdv[0], "exists") == 0) {
exit(!cpio.exists(cmdv[1]));
} else if (cmdc == 2 && strcmp(cmdv[0], "backup") == 0) {
cpio.backup(cmdv[1]);
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
bool r = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
cpio.rm(cmdv[1 + r], r);
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
cpio.mv(cmdv[1], cmdv[2]);
} else if (strcmp(cmdv[0], "extract") == 0) {
if (cmdc == 3) {
return !cpio.extract(cmdv[1], cmdv[2]);
} else {
cpio.extract();
return 0;
}
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
cpio.mkdir(strtoul(cmdv[1], nullptr, 8), cmdv[2]);
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
cpio.ln(cmdv[1], cmdv[2]);
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
cpio.add(strtoul(cmdv[1], nullptr, 8), cmdv[2], cmdv[3]);
} else {
return 1;
}
if (strcmp(cmdv[0], "test") == 0) {
exit(cpio.test());
} else if (strcmp(cmdv[0], "restore") == 0) {
cpio.restore();
} else if (strcmp(cmdv[0], "sha1") == 0) {
char *sha1 = cpio.sha1();
if (sha1) printf("%s\n", sha1);
return 0;
} else if (strcmp(cmdv[0], "compress") == 0){
cpio.compress();
} else if (strcmp(cmdv[0], "decompress") == 0){
cpio.decompress();
} else if (strcmp(cmdv[0], "patch") == 0) {
cpio.patch();
} else if (cmdc == 2 && strcmp(cmdv[0], "exists") == 0) {
exit(!cpio.exists(cmdv[1]));
} else if (cmdc == 2 && strcmp(cmdv[0], "backup") == 0) {
cpio.backup(cmdv[1]);
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
bool r = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
cpio.rm(cmdv[1 + r], r);
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
cpio.mv(cmdv[1], cmdv[2]);
} else if (strcmp(cmdv[0], "extract") == 0) {
if (cmdc == 3) {
return !cpio.extract(cmdv[1], cmdv[2]);
} else {
cpio.extract();
return 0;
}
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
cpio.mkdir(strtoul(cmdv[1], nullptr, 8), cmdv[2]);
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
cpio.ln(cmdv[1], cmdv[2]);
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
cpio.add(strtoul(cmdv[1], nullptr, 8), cmdv[2], cmdv[3]);
} else {
return 1;
}
--argc;
++argv;
}
--argc;
++argv;
}
cpio.dump(incpio);
return 0;
cpio.dump(incpio);
return 0;
}