From baff9256c5ba9145b3c5ef20c663e2d66cce3f60 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 7 Dec 2017 03:21:13 +0800 Subject: [PATCH] Dynamic patch verity and forceencrypt flag --- core/jni/core/magiskinit.c | 62 ++++++++++++++++++++----- core/jni/include/cpio.h | 2 +- core/jni/include/utils.h | 7 ++- core/jni/magiskboot/dtb.c | 2 +- core/jni/magiskboot/ramdisk.c | 2 +- core/jni/utils/file.c | 85 ++++++++++++++++++++++------------- core/jni/utils/pattern.c | 8 ++-- scripts/boot_patch.sh | 9 ++-- 8 files changed, 121 insertions(+), 56 deletions(-) diff --git a/core/jni/core/magiskinit.c b/core/jni/core/magiskinit.c index 2da559fff..e228d5c17 100644 --- a/core/jni/core/magiskinit.c +++ b/core/jni/core/magiskinit.c @@ -47,10 +47,15 @@ #include "cpio.h" #include "magisk.h" -// #define VLOG(fmt, ...) printf(fmt, __VA_ARGS__) /* Enable to debug */ +#ifdef MAGISK_DEBUG +#define VLOG(fmt, ...) printf(fmt, __VA_ARGS__) +#else #define VLOG(fmt, ...) +#endif +extern policydb_t *policydb; int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, NULL }; +static int keepverity = 0, keepencrypt = 0; struct cmdline { int skip_initramfs; @@ -65,8 +70,6 @@ struct device { char path[64]; }; -extern policydb_t *policydb; - static void parse_cmdline(struct cmdline *cmd) { // cleanup cmd->skip_initramfs = 0; @@ -143,7 +146,24 @@ static int setup_block(struct device *dev, const char *partname) { return 0; } -static void patch_ramdisk() { +static void fstab_patch_cb(int dirfd, struct dirent *entry) { + if (entry->d_type == DT_REG && strstr(entry->d_name, "fstab")) { + void *buf; + size_t _size; + uint32_t size; + full_read_at(dirfd, entry->d_name, &buf, &_size); + size = _size; /* Type conversion */ + if (!keepverity) + patch_verity(&buf, &size, 1); + if (!keepencrypt) + patch_encryption(&buf, &size); + int fstab = xopenat(dirfd, entry->d_name, O_WRONLY | O_CLOEXEC); + write(fstab, buf, size); + close(fstab); + } +} + +static void patch_ramdisk(int root) { void *addr; size_t size; mmap_rw("/init", &addr, &size); @@ -161,6 +181,23 @@ static void patch_ramdisk() { write(fd, addr, size); close(fd); free(addr); + + char *key, *value; + full_read("/.backup/.magisk", &addr, &size); + for (char *tok = strtok(addr, "\n"); tok; tok = strtok(NULL, "\n")) { + key = tok; + value = strchr(tok, '=') + 1; + value[-1] = '\0'; + if (strcmp(key, "KEEPVERITY") == 0) + keepverity = strcmp(value, "true") == 0; + else if (strcmp(key, "KEEPFORCEENCRYPT") == 0) + keepencrypt = strcmp(value, "true") == 0; + } + + excl_list = (char *[]) { "system_root", "system", "vendor", NULL }; + in_order_walk(root, fstab_patch_cb); + if (!keepverity) + unlink("/verity_key"); } static int strend(const char *s1, const char *s2) { @@ -456,17 +493,13 @@ int main(int argc, char *argv[]) { } } - // Only patch initramfs if not intended to run in recovery (legacy devices) + int overlay = open("/overlay", O_RDONLY | O_CLOEXEC); + + // Only patch rootfs if not intended to run in recovery if (access("/etc/recovery.fstab", F_OK) != 0) { - int overlay = open("/overlay", O_RDONLY | O_CLOEXEC); mv_dir(overlay, root); - // Clean up - rmdir("/overlay"); - close(overlay); - close(root); - - patch_ramdisk(); + patch_ramdisk(root); patch_sepolicy(); if (fork_dont_care() == 0) { @@ -475,7 +508,12 @@ int main(int argc, char *argv[]) { } } + // Clean up + close(overlay); + close(root); umount("/vendor"); + rmdir("/overlay"); + // Finally, give control back! execv("/init", argv); } diff --git a/core/jni/include/cpio.h b/core/jni/include/cpio.h index 214271561..81a8342a9 100644 --- a/core/jni/include/cpio.h +++ b/core/jni/include/cpio.h @@ -20,7 +20,7 @@ typedef struct cpio_entry { // uint32_t namesize; // uint32_t check; char *filename; - char *data; + void *data; int remove; } cpio_entry; diff --git a/core/jni/include/utils.h b/core/jni/include/utils.h index b0bcf4fff..0d3ff00cc 100644 --- a/core/jni/include/utils.h +++ b/core/jni/include/utils.h @@ -102,6 +102,7 @@ struct file_attr { int fd_getpath(int fd, char *path, size_t size); int mkdir_p(const char *pathname, mode_t mode); +void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)); void rm_rf(const char *path); void frm_rf(int dirfd); void mv_f(const char *source, const char *destination); @@ -119,7 +120,9 @@ void clone_attr(const char *source, const char *target); void restorecon(int dirfd, int force); int mmap_ro(const char *filename, void **buf, size_t *size); int mmap_rw(const char *filename, void **buf, size_t *size); +void fd_full_read(int fd, void **buf, size_t *size); void full_read(const char *filename, void **buf, size_t *size); +void full_read_at(int dirfd, const char *filename, void **buf, size_t *size); void stream_full_read(int fd, void **buf, size_t *size); void write_zero(int fd, size_t size); void mem_align(size_t *pos, size_t align); @@ -142,7 +145,7 @@ void trim_img(const char *img); // pattern.c void patch_init_rc(void **buf, size_t *size); -int patch_verity(char **buf, uint32_t *size, int patch); -void patch_encryption(char **buf, uint32_t *size); +int patch_verity(void **buf, uint32_t *size, int patch); +void patch_encryption(void **buf, uint32_t *size); #endif diff --git a/core/jni/magiskboot/dtb.c b/core/jni/magiskboot/dtb.c index 3fcec46f6..0bd57cac8 100644 --- a/core/jni/magiskboot/dtb.c +++ b/core/jni/magiskboot/dtb.c @@ -78,7 +78,7 @@ static void dtb_patch(const char *file, int patch) { fdt_for_each_subnode(block, fdt, fstab) { fprintf(stderr, "Found block [%s] in fstab\n", fdt_get_name(fdt, block, NULL)); uint32_t value_size; - char *value = (char *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size); + void *value = (char *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size); found |= patch_verity(&value, &value_size, patch); } } diff --git a/core/jni/magiskboot/ramdisk.c b/core/jni/magiskboot/ramdisk.c index a3f51b6e7..b565f1f95 100644 --- a/core/jni/magiskboot/ramdisk.c +++ b/core/jni/magiskboot/ramdisk.c @@ -58,7 +58,7 @@ static char *cpio_stocksha1(struct vector *v) { vec_for_each(v, f) { if (strcmp(f->filename, "init.magisk.rc") == 0 || strcmp(f->filename, "overlay/init.magisk.rc") == 0) { - for (char *pos = f->data; pos < f->data + f->filesize; pos = strchr(pos + 1, '\n') + 1) { + for (void *pos = f->data; pos < f->data + f->filesize; pos = strchr(pos + 1, '\n') + 1) { if (memcmp(pos, "# STOCKSHA1=", 12) == 0) { pos += 12; memcpy(sha1, pos, 40); diff --git a/core/jni/utils/file.c b/core/jni/utils/file.c index 2beaeaf2f..8e6630fbc 100644 --- a/core/jni/utils/file.c +++ b/core/jni/utils/file.c @@ -17,13 +17,13 @@ #include "utils.h" -char **excl_list = (char *[]) { NULL }; +char **excl_list = NULL; static int is_excl(const char *name) { - for (int i = 0; excl_list[i]; ++i) { - if (strcmp(name, excl_list[i]) == 0) - return 1; - } + if (excl_list) + for (int i = 0; excl_list[i]; ++i) + if (strcmp(name, excl_list[i]) == 0) + return 1; return 0; } @@ -55,6 +55,36 @@ int mkdir_p(const char *pathname, mode_t mode) { return 0; } +void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)) { + struct dirent *entry; + int newfd; + DIR *dir = xfdopendir(dirfd); + + while ((entry = xreaddir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + if (is_excl(entry->d_name)) + continue; + if (entry->d_type == DT_DIR) { + newfd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); + in_order_walk(newfd, callback); + close(newfd); + } + callback(dirfd, entry); + } +} + +static void rm_cb(int dirfd, struct dirent *entry) { + switch (entry->d_type) { + case DT_DIR: + unlinkat(dirfd, entry->d_name, AT_REMOVEDIR); + break; + default: + unlinkat(dirfd, entry->d_name, 0); + break; + } +} + void rm_rf(const char *path) { int fd = xopen(path, O_RDONLY | O_CLOEXEC); if (fd < 0) @@ -65,27 +95,7 @@ void rm_rf(const char *path) { } void frm_rf(int dirfd) { - struct dirent *entry; - int newfd; - DIR *dir = xfdopendir(dirfd); - - while ((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - if (is_excl(entry->d_name)) - continue; - switch (entry->d_type) { - case DT_DIR: - newfd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); - frm_rf(newfd); - close(newfd); - unlinkat(dirfd, entry->d_name, AT_REMOVEDIR); - break; - default: - unlinkat(dirfd, entry->d_name, 0); - break; - } - } + in_order_walk(dirfd, rm_cb); } /* This will only on the same file system */ @@ -360,6 +370,13 @@ int mmap_rw(const char *filename, void **buf, size_t *size) { return _mmap(1, filename, buf, size); } +void fd_full_read(int fd, void **buf, size_t *size) { + *size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + *buf = xmalloc(*size); + xxread(fd, *buf, *size); +} + void full_read(const char *filename, void **buf, size_t *size) { int fd = xopen(filename, O_RDONLY); if (fd < 0) { @@ -367,10 +384,18 @@ void full_read(const char *filename, void **buf, size_t *size) { *size = 0; return; } - *size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - *buf = xmalloc(*size); - xxread(fd, *buf, *size); + fd_full_read(fd, buf, size); + close(fd); +} + +void full_read_at(int dirfd, const char *filename, void **buf, size_t *size) { + int fd = xopenat(dirfd, filename, O_RDONLY); + if (fd < 0) { + *buf = NULL; + *size = 0; + return; + } + fd_full_read(fd, buf, size); close(fd); } diff --git a/core/jni/utils/pattern.c b/core/jni/utils/pattern.c index 8b4efa229..36d62dc64 100644 --- a/core/jni/utils/pattern.c +++ b/core/jni/utils/pattern.c @@ -58,12 +58,12 @@ void patch_init_rc(void **buf, size_t *size) { *buf = new_data; } -int patch_verity(char **buf, uint32_t *size, int patch) { +int patch_verity(void **buf, uint32_t *size, int patch) { int skip, found = 0; for (int pos = 0; pos < *size; ++pos) { if ((skip = check_verity_pattern(*buf + pos)) > 0) { found = 1; - fprintf(stderr, "%s pattern [%.*s]\n", patch ? "Remove" : "Found", skip, *buf + pos); + fprintf(stderr, "%s pattern [%.*s]\n", patch ? "Remove" : "Found", skip, (char *) *buf + pos); if (patch) { memcpy(*buf + pos, *buf + pos + skip, *size - pos - skip); memset(*buf + *size - skip, '\0', skip); @@ -76,11 +76,11 @@ int patch_verity(char **buf, uint32_t *size, int patch) { return found; } -void patch_encryption(char **buf, uint32_t *size) { +void patch_encryption(void **buf, uint32_t *size) { int skip; for (int pos = 0; pos < *size; ++pos) { if ((skip = check_encryption_pattern(*buf + pos)) > 0) { - fprintf(stderr, "Replace pattern [%.*s] with [encryptable]\n", skip, *buf + pos); + fprintf(stderr, "Replace pattern [%.*s] with [encryptable]\n", skip, (char *) *buf + pos); memcpy(*buf + pos, "encryptable", 11); memcpy(*buf + pos + 11, *buf + pos + skip, *size - pos - skip); memset(*buf + *size - skip + 11, '\0', skip - 11); diff --git a/scripts/boot_patch.sh b/scripts/boot_patch.sh index d35d1fef0..b012c5417 100644 --- a/scripts/boot_patch.sh +++ b/scripts/boot_patch.sh @@ -64,7 +64,7 @@ BOOTIMAGE="$1" # Presets [ -z $KEEPVERITY ] && KEEPVERITY=false [ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false -[ -z $HIGH_COMP ] && HIGH_COMP=false +[ -z $HIGHCOMP ] && HIGHCOMP=false chmod -R 755 . @@ -89,7 +89,7 @@ case $? in 2 ) ui_print "! Insufficient boot partition size detected" ui_print "- Enable high compression mode" - HIGH_COMP=true + HIGHCOMP=true ;; 3 ) ui_print "- ChromeOS boot image detected" @@ -139,11 +139,10 @@ esac ui_print "- Patching ramdisk" -[ -f /sdcard/ramdisk-recovery.img ] && HIGH_COMP=true +[ -f /sdcard/ramdisk-recovery.img ] && HIGHCOMP=true -./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT ./magiskboot --cpio-add ramdisk.cpio 750 init magiskinit -./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig $HIGH_COMP $SHA1 +./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig $HIGHCOMP $KEEPVERITY $KEEPFORCEENCRYPT $SHA1 rm -f ramdisk.cpio.orig