diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 959286c9c..4f7dfa396 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -9,6 +9,14 @@ LIBLZMA := $(EXT_PATH)/xz/src/liblzma/api LIBLZ4 := $(EXT_PATH)/lz4/lib LIBBZ2 := $(EXT_PATH)/bzip2 LIBFDT := $(EXT_PATH)/dtc/libfdt +UTIL_SRC := utils/cpio.c \ + utils/file.c \ + utils/img.c \ + utils/list.c \ + utils/misc.c \ + utils/pattern.c \ + utils/vector.c \ + utils/xwrap.c ######################## # Binaries @@ -32,12 +40,6 @@ LOCAL_SRC_FILES := \ core/log_monitor.c \ core/bootstages.c \ core/socket.c \ - utils/misc.c \ - utils/vector.c \ - utils/xwrap.c \ - utils/list.c \ - utils/img.c \ - utils/file.c \ magiskhide/magiskhide.c \ magiskhide/proc_monitor.c \ magiskhide/hide_utils.c \ @@ -48,7 +50,8 @@ LOCAL_SRC_FILES := \ su/db.c \ su/pts.c \ su/su_daemon.c \ - su/su_socket.c + su/su_socket.c \ + $(UTIL_SRC) LOCAL_CFLAGS := -DIS_DAEMON -DSELINUX LOCAL_LDLIBS := -llog @@ -72,15 +75,11 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ core/magiskinit.c \ core/socket.c \ - utils/misc.c \ - utils/vector.c \ - utils/file.c \ - utils/xwrap.c \ - utils/cpio.c \ magiskpolicy/api.c \ magiskpolicy/magiskpolicy.c \ magiskpolicy/rules.c \ - magiskpolicy/sepolicy.c + magiskpolicy/sepolicy.c \ + $(UTIL_SRC) LOCAL_LDFLAGS := -static include $(BUILD_EXECUTABLE) @@ -106,10 +105,7 @@ LOCAL_SRC_FILES := \ magiskboot/types.c \ magiskboot/dtb.c \ magiskboot/ramdisk.c \ - utils/xwrap.c \ - utils/file.c \ - utils/cpio.c \ - utils/vector.c + $(UTIL_SRC) LOCAL_CFLAGS := -DXWRAP_EXIT LOCAL_LDLIBS := -lz diff --git a/core/jni/core/magiskinit.c b/core/jni/core/magiskinit.c index 90d636b33..2da559fff 100644 --- a/core/jni/core/magiskinit.c +++ b/core/jni/core/magiskinit.c @@ -72,7 +72,6 @@ static void parse_cmdline(struct cmdline *cmd) { cmd->skip_initramfs = 0; cmd->slot[0] = '\0'; - char *tok; char cmdline[4096]; mkdir("/proc", 0555); mount("proc", "/proc", "proc", 0, NULL); @@ -80,8 +79,7 @@ static void parse_cmdline(struct cmdline *cmd) { cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0'; close(fd); umount("/proc"); - tok = strtok(cmdline, " "); - while (tok != NULL) { + for (char *tok = strtok(cmdline, " "); tok; tok = strtok(NULL, " ")) { if (strncmp(tok, "androidboot.slot_suffix", 23) == 0) { sscanf(tok, "androidboot.slot_suffix=%s", cmd->slot); } else if (strncmp(tok, "androidboot.slot", 16) == 0) { @@ -90,7 +88,6 @@ static void parse_cmdline(struct cmdline *cmd) { } else if (strcmp(tok, "skip_initramfs") == 0) { cmd->skip_initramfs = 1; } - tok = strtok(NULL, " "); } } @@ -146,34 +143,6 @@ static int setup_block(struct device *dev, const char *partname) { return 0; } -static void *patch_init_rc(char *data, uint32_t *size) { - int injected = 0; - char *new_data = malloc(*size + 23); - char *old_data = data; - uint32_t pos = 0; - - for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) { - if (!injected && strncmp(tok, "import", 6) == 0) { - if (strstr(tok, "init.magisk.rc")) { - injected = 1; - } else { - strcpy(new_data + pos, "import /init.magisk.rc\n"); - pos += 23; - injected = 1; - } - } else if (strstr(tok, "selinux.reload_policy")) { - continue; - } - // Copy the line - strcpy(new_data + pos, tok); - pos += strlen(tok); - new_data[pos++] = '\n'; - } - - *size = pos; - return new_data; -} - static void patch_ramdisk() { void *addr; size_t size; @@ -186,15 +155,12 @@ static void patch_ramdisk() { } munmap(addr, size); - mmap_rw("/init.rc", &addr, &size); - uint32_t new_size = size; - void *init_rc = patch_init_rc(addr, &new_size); - munmap(addr, size); - - int fd = open("/init.rc", O_WRONLY | O_TRUNC | O_CLOEXEC); - write(fd, init_rc, new_size); + full_read("/init.rc", &addr, &size); + patch_init_rc(&addr, &size); + int fd = creat("/init.rc", 0750); + write(fd, addr, size); close(fd); - free(init_rc); + free(addr); } static int strend(const char *s1, const char *s2) { diff --git a/core/jni/include/cpio.h b/core/jni/include/cpio.h index 30c9da773..214271561 100644 --- a/core/jni/include/cpio.h +++ b/core/jni/include/cpio.h @@ -42,8 +42,10 @@ typedef struct cpio_newc_header { } cpio_newc_header; // Basic cpio functions +int cpio_cmp(const void *a, const void *b); void parse_cpio(struct vector *v, const char *filename); void dump_cpio(struct vector *v, const char *filename); +void cpio_vec_insert(struct vector *v, cpio_entry *n); void cpio_vec_destroy(struct vector *v); void cpio_rm(struct vector *v, int recursive, const char *entry); void cpio_mkdir(struct vector *v, mode_t mode, const char *entry); @@ -53,10 +55,4 @@ int cpio_mv(struct vector *v, const char *from, const char *to); int cpio_extract(struct vector *v, const char *entry, const char *filename); void cpio_extract_all(struct vector *v); -// Magisk specific -int cpio_test(struct vector *v); -struct vector *cpio_backup(struct vector *v, const char *orig, const char *sha1); -void cpio_restore(struct vector *v); -char *cpio_stocksha1(struct vector *v); - #endif diff --git a/core/jni/include/logging.h b/core/jni/include/logging.h index dbc0cc74e..e9434a704 100644 --- a/core/jni/include/logging.h +++ b/core/jni/include/logging.h @@ -15,7 +15,9 @@ * No logging * **************/ +#define LOGD(...) #define LOGI(...) +#define LOGW(...) #define LOGE(...) #define PLOGE(...) @@ -26,6 +28,7 @@ #ifdef IS_DAEMON #undef LOGI +#undef LOGW #undef LOGE #undef PLOGE @@ -35,14 +38,12 @@ #define LOG_TAG "Magisk" #ifdef MAGISK_DEBUG +#undef LOGD #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#else -#define LOGD(...) #endif #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) enum { @@ -65,13 +66,11 @@ void start_debug_log(); #ifdef XWRAP_EXIT -#undef LOGI #undef LOGE #undef PLOGE #include -#define LOGI(...) #define LOGE(...) { fprintf(stderr, __VA_ARGS__); exit(1); } #define PLOGE(fmt, args...) { fprintf(stderr, fmt " failed with %d: %s\n\n", ##args, errno, strerror(errno)); exit(1); } diff --git a/core/jni/include/utils.h b/core/jni/include/utils.h index 15333df57..b0bcf4fff 100644 --- a/core/jni/include/utils.h +++ b/core/jni/include/utils.h @@ -70,7 +70,7 @@ pid_t xfork(); // misc.c -extern int quit_signals[]; +#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 }) unsigned get_shell_uid(); unsigned get_system_uid(); @@ -119,7 +119,8 @@ 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 full_read(int fd, void **buf, size_t *size); +void full_read(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); void file_align(int fd, size_t align, int out); @@ -138,4 +139,10 @@ void umount_image(const char *target, const char *device); int merge_img(const char *source, const char *target); 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); + #endif diff --git a/core/jni/magiskboot/compress.c b/core/jni/magiskboot/compress.c index 0832dd005..f57772741 100644 --- a/core/jni/magiskboot/compress.c +++ b/core/jni/magiskboot/compress.c @@ -392,7 +392,7 @@ void decomp_file(char *from, const char *to) { void *file; size_t size = 0; if (strcmp(from, "-") == 0) - full_read(STDIN_FILENO, &file, &size); + stream_full_read(STDIN_FILENO, &file, &size); else mmap_ro(from, &file, &size); file_t type = check_type(file); @@ -483,7 +483,7 @@ void comp_file(const char *method, const char *from, const char *to) { void *file; size_t size; if (strcmp(from, "-") == 0) - full_read(STDIN_FILENO, &file, &size); + stream_full_read(STDIN_FILENO, &file, &size); else mmap_ro(from, &file, &size); if (to == NULL) { diff --git a/core/jni/magiskboot/dtb.c b/core/jni/magiskboot/dtb.c index 68bd8c14f..3fcec46f6 100644 --- a/core/jni/magiskboot/dtb.c +++ b/core/jni/magiskboot/dtb.c @@ -5,8 +5,6 @@ #include "magiskboot.h" #include "utils.h" -extern int check_verity_pattern(const char *s); - static void print_props(const void *fdt, int node, int depth) { int prop; fdt_for_each_property_offset(prop, fdt, node) { @@ -79,21 +77,9 @@ static void dtb_patch(const char *file, int patch) { int block; fdt_for_each_subnode(block, fdt, fstab) { fprintf(stderr, "Found block [%s] in fstab\n", fdt_get_name(fdt, block, NULL)); - int skip, value_size; + uint32_t value_size; char *value = (char *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size); - for (int i = 0; i < value_size; ++i) { - if ((skip = check_verity_pattern(value + i)) > 0) { - if (patch) { - fprintf(stderr, "Remove pattern [%.*s] in [fsmgr_flags]\n", skip, value + i); - memcpy(value + i, value + i + skip, value_size - i - skip); - memset(value + value_size - skip, '\0', skip); - } else { - fprintf(stderr, "Found pattern [%.*s] in [fsmgr_flags]\n", skip, value + i); - i += skip - 1; - } - found = 1; - } - } + found |= patch_verity(&value, &value_size, patch); } } } diff --git a/core/jni/magiskboot/main.c b/core/jni/magiskboot/main.c index 9b343ca39..02a047743 100644 --- a/core/jni/magiskboot/main.c +++ b/core/jni/magiskboot/main.c @@ -18,13 +18,13 @@ static void usage(char *arg0) { "\n" "Supported actions:\n" " --parse \n" - " Parse only, do not unpack. Return value: \n" + " Parse only, do not unpack. Return values: \n" " 0:OK 1:error 2:insufficient boot partition size\n" " 3:chromeos 4:ELF32 5:ELF64\n" "\n" " --unpack \n" " Unpack to kernel, ramdisk.cpio, (second), (dtb), (extra) into\n" - " the current directory. Return value is the same as parse command\n" + " the current directory. Return value is the same as --parse\n" "\n" " --repack [outbootimg]\n" " Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n" @@ -54,10 +54,11 @@ static void usage(char *arg0) { " -test\n" " Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n" " -patch \n" - " Patch cpio for Magisk. KEEP**** are boolean values\n" - " -backup [SHA1]\n" + " Ramdisk patches. KEEP**** are boolean values\n" + " This command is no longer used in Magisk installations\n" + " -backup [SHA1]\n" " Create ramdisk backups into from \n" - " HIGH_COMP is a boolean value, toggles high compression mode\n" + " HIGHCOMP, KEEP**** are boolean values\n" " SHA1 of stock boot image is optional\n" " -restore\n" " Restore ramdisk from ramdisk backup within \n" diff --git a/core/jni/magiskboot/ramdisk.c b/core/jni/magiskboot/ramdisk.c index a12663d30..a3f51b6e7 100644 --- a/core/jni/magiskboot/ramdisk.c +++ b/core/jni/magiskboot/ramdisk.c @@ -8,47 +8,12 @@ #include "magiskboot.h" #include "cpio.h" -int check_verity_pattern(const char *s) { - int pos = 0; - if (s[0] == ',') ++pos; - if (strncmp(s + pos, "verify", 6) == 0) - pos += 6; - else if (strncmp(s + pos, "avb", 3) == 0) - pos += 3; - else - return -1; - - if (s[pos] == '=') { - while (s[pos] != '\0' && s[pos] != ' ' && s[pos] != '\n' && s[pos] != ',') ++pos; - } - return pos; -} - -int check_encryption_pattern(const char *s) { - const char *encrypt_list[] = { "forceencrypt", "forcefdeorfbe", NULL }; - for (int i = 0 ; encrypt_list[i]; ++i) { - int len = strlen(encrypt_list[i]); - if (strncmp(s, encrypt_list[i], len) == 0) - return len; - } - return -1; -} - -void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) { +static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) { cpio_entry *f; - int skip, write; vec_for_each(v, f) { if (!keepverity) { if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) { - write = 0; - for (int read = 0; read < f->filesize; ++write, ++read) { - if ((skip = check_verity_pattern(f->data + read)) > 0) { - fprintf(stderr, "Remove pattern [%.*s] in [%s]\n", skip, f->data + read, f->filename); - read += skip; - } - f->data[write] = f->data[read]; - } - f->filesize = write; + patch_verity(&f->data, &f->filesize, 1); } else if (strcmp(f->filename, "verity_key") == 0) { fprintf(stderr, "Remove [verity_key]\n"); f->remove = 1; @@ -56,35 +21,207 @@ void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) { } if (!keepforceencrypt) { if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) { - write = 0; - for (int read = 0; read < f->filesize; ++write, ++read) { - if ((skip = check_encryption_pattern(f->data + read)) > 0) { - // assert(skip > 11)! - fprintf(stderr, "Replace pattern [%.*s] with [encryptable] in [%s]\n", skip, f->data + read, f->filename); - memcpy(f->data + write, "encryptable", 11); - write += 11; - read += skip; - } - f->data[write] = f->data[read]; - } - f->filesize = write; + patch_encryption(&f->data, &f->filesize); } } } } +#define STOCK_BOOT 0x0 +#define MAGISK_PATCH 0x1 +#define OTHER_PATCH 0x2 + +static int cpio_test(struct vector *v) { + int ret = STOCK_BOOT; + cpio_entry *f; + const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL }; + const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL }; + vec_for_each(v, f) { + for (int i = 0; OTHER_LIST[i]; ++i) { + if (strcmp(f->filename, OTHER_LIST[i]) == 0) { + // Already find other files, abort + return OTHER_PATCH; + } + } + for (int i = 0; MAGISK_LIST[i]; ++i) { + if (strcmp(f->filename, MAGISK_LIST[i]) == 0) + ret = MAGISK_PATCH; + } + } + cpio_vec_destroy(v); + return ret; +} + +static char *cpio_stocksha1(struct vector *v) { + cpio_entry *f; + char sha1[41]; + 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) { + if (memcmp(pos, "# STOCKSHA1=", 12) == 0) { + pos += 12; + memcpy(sha1, pos, 40); + sha1[40] = '\0'; + return strdup(sha1); + } + } + } else if (strcmp(f->filename, ".backup/.sha1") == 0) { + return f->data; + } + } + return NULL; +} + +static struct vector *cpio_backup(struct vector *v, const char *orig, const char *keepverity, + const char *keepforceencrypt, const char *sha1) { + struct vector o_body, *o = &o_body, *ret; + cpio_entry *m, *n, *rem, *cksm; + char buf[PATH_MAX]; + int res, backup; + + ret = xcalloc(sizeof(*ret), 1); + + vec_init(o); + vec_init(ret); + + m = xcalloc(sizeof(*m), 1); + m->filename = strdup(".backup"); + m->mode = S_IFDIR; + vec_push_back(ret, m); + + m = xcalloc(sizeof(*m), 1); + m->filename = strdup(".backup/.magisk"); + m->mode = S_IFREG; + m->data = xmalloc(50); + snprintf(m->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", keepverity, keepforceencrypt); + m->filesize = strlen(m->data) + 1; + vec_push_back(ret, m); + + rem = xcalloc(sizeof(*rem), 1); + rem->filename = strdup(".backup/.rmlist"); + rem->mode = S_IFREG; + vec_push_back(ret, rem); + + if (sha1) { + fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1); + cksm = xcalloc(sizeof(*cksm), 1); + vec_push_back(ret, cksm); + cksm->filename = strdup(".backup/.sha1"); + cksm->mode = S_IFREG; + cksm->data = strdup(sha1); + cksm->filesize = strlen(sha1) + 1; + } + + parse_cpio(o, orig); + // Remove possible backups in original ramdisk + cpio_rm(o, 1, ".backup"); + cpio_rm(v, 1, ".backup"); + + // Sort both vectors before comparing + vec_sort(v, cpio_cmp); + vec_sort(o, cpio_cmp); + + // Start comparing + size_t i = 0, j = 0; + while(i != vec_size(o) || j != vec_size(v)) { + backup = 0; + if (i != vec_size(o) && j != vec_size(v)) { + m = vec_entry(o)[i]; + n = vec_entry(v)[j]; + res = strcmp(m->filename, n->filename); + } else if (i == vec_size(o)) { + n = vec_entry(v)[j]; + res = 1; + } else if (j == vec_size(v)) { + m = vec_entry(o)[i]; + res = -1; + } + + if (res < 0) { + // Something is missing in new ramdisk, backup! + ++i; + backup = 1; + fprintf(stderr, "Backup missing entry: "); + } else if (res == 0) { + ++i; ++j; + if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0) + continue; + // Not the same! + backup = 1; + fprintf(stderr, "Backup mismatch entry: "); + } else { + // Someting new in ramdisk, record in rem + ++j; + if (n->remove) continue; + rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1); + memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1); + rem->filesize += strlen(n->filename) + 1; + fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename); + } + if (backup) { + sprintf(buf, ".backup/%s", m->filename); + free(m->filename); + m->filename = strdup(buf); + fprintf(stderr, "[%s] -> [%s]\n", buf, m->filename); + vec_push_back(ret, m); + // NULL the original entry, so it won't be freed + vec_entry(o)[i - 1] = NULL; + } + } + + if (rem->filesize == 0) + rem->remove = 1; + + // Cleanup + cpio_vec_destroy(o); + + return ret; +} + +static void cpio_restore(struct vector *v) { + cpio_entry *f, *n; + vec_for_each(v, f) { + if (strncmp(f->filename, ".backup", 7) == 0) { + f->remove = 1; + if (f->filename[7] == '\0') continue; + if (f->filename[8] == '.') { + if (strcmp(f->filename, ".backup/.rmlist") == 0) { + for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1) + cpio_rm(v, 0, f->data + pos); + } + continue; + } else { + n = xcalloc(sizeof(*n), 1); + memcpy(n, f, sizeof(*f)); + n->filename = strdup(f->filename + 8); + n->data = f->data; + f->data = NULL; + n->remove = 0; + fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename); + cpio_vec_insert(v, n); + } + } + if (strncmp(f->filename, "overlay", 7) == 0) + f->remove = 1; + } + // Some known stuff we can remove + cpio_rm(v, 0, "sbin/magic_mask.sh"); + cpio_rm(v, 0, "init.magisk.rc"); + cpio_rm(v, 0, "magisk"); + cpio_rm(v, 0, "ramdisk-recovery.xz"); +} + static void restore_high_compress(struct vector *v, const char *incpio) { // Check if the ramdisk is in high compression mode if (cpio_extract(v, "ramdisk.cpio.xz", incpio) == 0) { - void *addr, *xz; + void *xz; size_t size; - mmap_ro(incpio, &addr, &size); - xz = xmalloc(size); - memcpy(xz, addr, size); - munmap(addr, size); + full_read(incpio, &xz, &size); int fd = creat(incpio, 0644); lzma(0, fd, xz, size); close(fd); + free(xz); cpio_rm(v, 0, "ramdisk.cpio.xz"); cpio_rm(v, 0, "init"); struct vector vv; @@ -120,15 +257,13 @@ static void enable_high_compress(struct vector *v, struct vector *b, const char dump_cpio(v, incpio); cpio_vec_destroy(v); - void *addr, *cpio; + void *cpio; size_t size; - mmap_ro(incpio, &addr, &size); - cpio = xmalloc(size); - memcpy(cpio, addr, size); - munmap(addr, size); + full_read(incpio, &cpio, &size); int fd = creat(incpio, 0644); lzma(1, fd, cpio, size); close(fd); + free(cpio); vec_init(v); vec_push_back(v, magiskinit); cpio_add(v, 0, "ramdisk.cpio.xz", incpio); @@ -150,10 +285,10 @@ int cpio_commands(const char *command, int argc, char *argv[]) { } else if (strcmp(command, "stocksha1") == 0) { printf("%s\n", cpio_stocksha1(&v)); return 0; - } else if (argc >= 2 && strcmp(command, "backup") == 0) { + } else if (argc >= 4 && strcmp(command, "backup") == 0) { struct vector *back; cpio_entry *e; - back = cpio_backup(&v, argv[0], argc > 2 ? argv[2] : NULL); + back = cpio_backup(&v, argv[0], argv[2], argv[3], argc > 4 ? argv[4] : NULL); // Enable high compression mode if (strcmp(argv[1], "true") == 0) diff --git a/core/jni/utils/cpio.c b/core/jni/utils/cpio.c index 8a3b967a1..020a9e4c4 100644 --- a/core/jni/utils/cpio.c +++ b/core/jni/utils/cpio.c @@ -30,7 +30,11 @@ static void cpio_free(cpio_entry *f) { } } -static void cpio_vec_insert(struct vector *v, cpio_entry *n) { +int cpio_cmp(const void *a, const void *b) { + return strcmp((*(cpio_entry **) a)->filename, (*(cpio_entry **) b)->filename); +} + +void cpio_vec_insert(struct vector *v, cpio_entry *n) { cpio_entry *f; vec_for_each(v, f) { if (strcmp(f->filename, n->filename) == 0) { @@ -43,10 +47,6 @@ static void cpio_vec_insert(struct vector *v, cpio_entry *n) { vec_push_back(v, n); } -static int cpio_cmp(const void *a, const void *b) { - return strcmp((*(cpio_entry **) a)->filename, (*(cpio_entry **) b)->filename); -} - // Parse cpio file to a vector of cpio_entry void parse_cpio(struct vector *v, const char *filename) { fprintf(stderr, "Loading cpio: [%s]\n\n", filename); @@ -251,183 +251,3 @@ void cpio_extract_all(struct vector *v) { } } } - -int cpio_test(struct vector *v) { - #define STOCK_BOOT 0x0 - #define MAGISK_PATCH 0x1 - #define OTHER_PATCH 0x2 - int ret = STOCK_BOOT; - cpio_entry *f; - const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL }; - const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL }; - vec_for_each(v, f) { - for (int i = 0; OTHER_LIST[i]; ++i) { - if (strcmp(f->filename, OTHER_LIST[i]) == 0) { - // Already find other files, abort - return OTHER_PATCH; - } - } - for (int i = 0; MAGISK_LIST[i]; ++i) { - if (strcmp(f->filename, MAGISK_LIST[i]) == 0) - ret = MAGISK_PATCH; - } - } - cpio_vec_destroy(v); - return ret; -} - -struct vector * cpio_backup(struct vector *v, const char *orig, const char *sha1) { - struct vector o_body, *o = &o_body, *ret; - cpio_entry *m, *n, *rem, *cksm; - char buf[PATH_MAX]; - int res, backup; - - ret = xcalloc(sizeof(*ret), 1); - - vec_init(o); - vec_init(ret); - - m = xcalloc(sizeof(*m), 1); - m->filename = strdup(".backup"); - m->mode = S_IFDIR; - vec_push_back(ret, m); - - m = xcalloc(sizeof(*m), 1); - m->filename = strdup(".backup/.magisk"); - m->mode = S_IFREG; - vec_push_back(ret, m); - - rem = xcalloc(sizeof(*rem), 1); - rem->filename = strdup(".backup/.rmlist"); - rem->mode = S_IFREG; - vec_push_back(ret, rem); - - if (sha1) { - fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1); - cksm = xcalloc(sizeof(*cksm), 1); - vec_push_back(ret, cksm); - cksm->filename = strdup(".backup/.sha1"); - cksm->mode = S_IFREG; - cksm->data = strdup(sha1); - cksm->filesize = strlen(sha1) + 1; - } - - parse_cpio(o, orig); - // Remove possible backups in original ramdisk - cpio_rm(o, 1, ".backup"); - cpio_rm(v, 1, ".backup"); - - // Sort both vectors before comparing - vec_sort(v, cpio_cmp); - vec_sort(o, cpio_cmp); - - // Start comparing - size_t i = 0, j = 0; - while(i != vec_size(o) || j != vec_size(v)) { - backup = 0; - if (i != vec_size(o) && j != vec_size(v)) { - m = vec_entry(o)[i]; - n = vec_entry(v)[j]; - res = strcmp(m->filename, n->filename); - } else if (i == vec_size(o)) { - n = vec_entry(v)[j]; - res = 1; - } else if (j == vec_size(v)) { - m = vec_entry(o)[i]; - res = -1; - } - - if (res < 0) { - // Something is missing in new ramdisk, backup! - ++i; - backup = 1; - fprintf(stderr, "Backup missing entry: "); - } else if (res == 0) { - ++i; ++j; - if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0) - continue; - // Not the same! - backup = 1; - fprintf(stderr, "Backup mismatch entry: "); - } else { - // Someting new in ramdisk, record in rem - ++j; - if (n->remove) continue; - rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1); - memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1); - rem->filesize += strlen(n->filename) + 1; - fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename); - } - if (backup) { - sprintf(buf, ".backup/%s", m->filename); - free(m->filename); - m->filename = strdup(buf); - fprintf(stderr, "[%s] -> [%s]\n", buf, m->filename); - vec_push_back(ret, m); - // NULL the original entry, so it won't be freed - vec_entry(o)[i - 1] = NULL; - } - } - - if (rem->filesize == 0) - rem->remove = 1; - - // Cleanup - cpio_vec_destroy(o); - - return ret; -} - -void cpio_restore(struct vector *v) { - cpio_entry *f, *n; - vec_for_each(v, f) { - if (strncmp(f->filename, ".backup", 7) == 0) { - f->remove = 1; - if (f->filename[7] == '\0') continue; - if (f->filename[8] == '.') { - if (strcmp(f->filename, ".backup/.rmlist") == 0) { - for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1) - cpio_rm(v, 0, f->data + pos); - } - continue; - } else { - n = xcalloc(sizeof(*n), 1); - memcpy(n, f, sizeof(*f)); - n->filename = strdup(f->filename + 8); - n->data = f->data; - f->data = NULL; - n->remove = 0; - fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename); - cpio_vec_insert(v, n); - } - } - if (strncmp(f->filename, "overlay", 7) == 0) - f->remove = 1; - } - // Some known stuff we can remove - cpio_rm(v, 0, "sbin/magic_mask.sh"); - cpio_rm(v, 0, "init.magisk.rc"); - cpio_rm(v, 0, "magisk"); - cpio_rm(v, 0, "ramdisk-recovery.xz"); -} - -char *cpio_stocksha1(struct vector *v) { - cpio_entry *f; - char sha1[41]; - 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) { - if (memcmp(pos, "# STOCKSHA1=", 12) == 0) { - pos += 12; - memcpy(sha1, pos, 40); - sha1[40] = '\0'; - return strdup(sha1); - } - } - } else if (strcmp(f->filename, ".backup/.sha1") == 0) { - return f->data; - } - } - return NULL; -} diff --git a/core/jni/utils/file.c b/core/jni/utils/file.c index 6e06a908f..2beaeaf2f 100644 --- a/core/jni/utils/file.c +++ b/core/jni/utils/file.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #ifdef SELINUX @@ -218,23 +217,6 @@ void clone_dir(int src, int dest) { } } -void wait_till_exists(const char *target) { - if (access(target, F_OK) == 0) - return; - int fd = inotify_init(); - char *dir = dirname(target); - char crap[PATH_MAX]; - inotify_add_watch(fd, dir, IN_CREATE); - while (1) { - struct inotify_event event; - read(fd, &event, sizeof(event)); - read(fd, crap, event.len); - if (access(target, F_OK) == 0) - break; - } - close(fd); -} - int getattr(const char *path, struct file_attr *a) { if (xlstat(path, &a->st) == -1) return -1; @@ -378,7 +360,21 @@ int mmap_rw(const char *filename, void **buf, size_t *size) { return _mmap(1, filename, buf, size); } -void full_read(int fd, void **buf, size_t *size) { +void full_read(const char *filename, void **buf, size_t *size) { + int fd = xopen(filename, O_RDONLY); + if (fd < 0) { + *buf = NULL; + *size = 0; + return; + } + *size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + *buf = xmalloc(*size); + xxread(fd, *buf, *size); + close(fd); +} + +void stream_full_read(int fd, void **buf, size_t *size) { size_t cap = 1 << 20; uint8_t tmp[1 << 20]; *buf = xmalloc(cap); diff --git a/core/jni/utils/misc.c b/core/jni/utils/misc.c index a943d2dd7..7306fff40 100644 --- a/core/jni/utils/misc.c +++ b/core/jni/utils/misc.c @@ -11,16 +11,16 @@ #include #include #include +#include #include #include #include #include +#include #include "logging.h" #include "utils.h" -int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 }; - unsigned get_shell_uid() { struct passwd* ppwd = getpwnam("shell"); if (NULL == ppwd) @@ -314,3 +314,20 @@ int fork_dont_care() { } return 0; } + +void wait_till_exists(const char *target) { + if (access(target, F_OK) == 0) + return; + int fd = inotify_init(); + char *dir = dirname(target); + char crap[PATH_MAX]; + inotify_add_watch(fd, dir, IN_CREATE); + while (1) { + struct inotify_event event; + read(fd, &event, sizeof(event)); + read(fd, crap, event.len); + if (access(target, F_OK) == 0) + break; + } + close(fd); +} diff --git a/core/jni/utils/pattern.c b/core/jni/utils/pattern.c new file mode 100644 index 000000000..8b4efa229 --- /dev/null +++ b/core/jni/utils/pattern.c @@ -0,0 +1,92 @@ +#include +#include + +#include "utils.h" + +static int check_verity_pattern(const char *s) { + int pos = 0; + if (s[0] == ',') ++pos; + if (strncmp(s + pos, "verify", 6) == 0) + pos += 6; + else if (strncmp(s + pos, "avb", 3) == 0) + pos += 3; + else + return -1; + + if (s[pos] == '=') { + while (s[pos] != '\0' && s[pos] != ' ' && s[pos] != '\n' && s[pos] != ',') ++pos; + } + return pos; +} + +static int check_encryption_pattern(const char *s) { + const char *encrypt_list[] = { "forceencrypt", "forcefdeorfbe", NULL }; + for (int i = 0 ; encrypt_list[i]; ++i) { + int len = strlen(encrypt_list[i]); + if (strncmp(s, encrypt_list[i], len) == 0) + return len; + } + return -1; +} + +void patch_init_rc(void **buf, size_t *size) { + int injected = 0; + char *new_data = malloc(*size + 23); + char *old_data = *buf; + size_t pos = 0; + + for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) { + if (!injected && strncmp(tok, "import", 6) == 0) { + if (strstr(tok, "init.magisk.rc")) { + injected = 1; + } else { + strcpy(new_data + pos, "import /init.magisk.rc\n"); + pos += 23; + injected = 1; + } + } else if (strstr(tok, "selinux.reload_policy")) { + continue; + } + // Copy the line + strcpy(new_data + pos, tok); + pos += strlen(tok); + new_data[pos++] = '\n'; + } + + free(*buf); + *size = pos; + *buf = new_data; +} + +int patch_verity(char **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); + if (patch) { + memcpy(*buf + pos, *buf + pos + skip, *size - pos - skip); + memset(*buf + *size - skip, '\0', skip); + *size -= skip; + } else { + pos += skip - 1; + } + } + } + return found; +} + +void patch_encryption(char **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); + memcpy(*buf + pos, "encryptable", 11); + memcpy(*buf + pos + 11, *buf + pos + skip, *size - pos - skip); + memset(*buf + *size - skip + 11, '\0', skip - 11); + *size -= (skip - 11); + } + } +} + +