From e645c6e465f35f9dd4ad2f593c17126454c2beca Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 10 Oct 2017 02:04:50 +0800 Subject: [PATCH] Refactor resetprop --- jni/include/resetprop.h | 6 +- jni/magiskhide/hide_utils.c | 4 +- jni/magiskhide/magiskhide.c | 4 +- jni/resetprop/resetprop.cpp | 471 ++++++++++++++++++++++-------------- 4 files changed, 295 insertions(+), 190 deletions(-) diff --git a/jni/include/resetprop.h b/jni/include/resetprop.h index be69f1395..689abbeb7 100644 --- a/jni/include/resetprop.h +++ b/jni/include/resetprop.h @@ -12,9 +12,11 @@ int prop_exist(const char *name); int setprop(const char *name, const char *value); int setprop2(const char *name, const char *value, const int trigger); char *getprop(const char *name); -int deleteprop(const char *name, const int trigger); +char *getprop2(const char *name, int persist); +int deleteprop(const char *name); +int deleteprop2(const char *name, const int persist); int read_prop_file(const char* filename, const int trigger); -void getprop_all(void (*cbk)(const char *name)); +void getprop_all(void (*callback)(const char*, const char*)); #ifdef __cplusplus } diff --git a/jni/magiskhide/hide_utils.c b/jni/magiskhide/hide_utils.c index 175aa2540..b34d5621c 100644 --- a/jni/magiskhide/hide_utils.c +++ b/jni/magiskhide/hide_utils.c @@ -58,9 +58,9 @@ void hide_sensitive_props() { } } -static void rm_magisk_prop(const char *name) { +static void rm_magisk_prop(const char *name, const char *value) { if (strstr(name, "magisk")) { - deleteprop(name, 0); + deleteprop2(name, 0); } } diff --git a/jni/magiskhide/magiskhide.c b/jni/magiskhide/magiskhide.c index 272e4daec..d899465b6 100644 --- a/jni/magiskhide/magiskhide.c +++ b/jni/magiskhide/magiskhide.c @@ -55,7 +55,7 @@ void launch_magiskhide(int client) { hideEnabled = 1; LOGI("* Starting MagiskHide\n"); - deleteprop(MAGISKHIDE_PROP, 1); + deleteprop2(MAGISKHIDE_PROP, 1); hide_sensitive_props(); @@ -102,7 +102,7 @@ void stop_magiskhide(int client) { hideEnabled = 0; setprop(MAGISKHIDE_PROP, "0"); // Remove without actually removing persist props - deleteprop(MAGISKHIDE_PROP, 0); + deleteprop2(MAGISKHIDE_PROP, 0); pthread_kill(proc_monitor_thread, SIGUSR1); write_int(client, DAEMON_SUCCESS); diff --git a/jni/resetprop/resetprop.cpp b/jni/resetprop/resetprop.cpp index 83c2d2f52..00d02e991 100644 --- a/jni/resetprop/resetprop.cpp +++ b/jni/resetprop/resetprop.cpp @@ -56,249 +56,352 @@ #include #include #include +#include #include #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include "_system_properties.h" #include "system_properties.h" + #include "magisk.h" #include "resetprop.h" +extern "C" { +#include "vector.h" +} -#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) printf(__VA_ARGS__); } +#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) fprintf(stderr, __VA_ARGS__); } #define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); } #define PERSISTENT_PROPERTY_DIR "/data/property" static int verbose = 0; -static bool is_legal_property_name(const char *name, size_t namelen) { +static int check_legal_property_name(const char *name) { + int namelen = strlen(name); - if (namelen < 1) return false; - if (name[0] == '.') return false; - if (name[namelen - 1] == '.') return false; + if (namelen < 1) goto illegal; + if (name[0] == '.') goto illegal; + if (name[namelen - 1] == '.') goto illegal; - /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ - /* Don't allow ".." to appear in a property name */ - for (size_t i = 0; i < namelen; i++) { - if (name[i] == '.') { - // i=0 is guaranteed to never have a dot. See above. - if (name[i-1] == '.') return false; - continue; - } - if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue; - if (name[i] >= 'a' && name[i] <= 'z') continue; - if (name[i] >= 'A' && name[i] <= 'Z') continue; - if (name[i] >= '0' && name[i] <= '9') continue; - return false; - } + /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ + /* Don't allow ".." to appear in a property name */ + for (size_t i = 0; i < namelen; i++) { + if (name[i] == '.') { + // i=0 is guaranteed to never have a dot. See above. + if (name[i-1] == '.') goto illegal; + continue; + } + if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue; + if (name[i] >= 'a' && name[i] <= 'z') continue; + if (name[i] >= 'A' && name[i] <= 'Z') continue; + if (name[i] >= '0' && name[i] <= '9') continue; + goto illegal; + } - return true; + return 0; + +illegal: + PRINT_E("Illegal property name: [%s]\n", name); + return 1; } static int usage(char* arg0) { - fprintf(stderr, - "resetprop v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu & nkk71) - System Props Modification Tool\n\n" - "Usage: %s [options] [args...]\n" - "\n" - "Options:\n" - " -v show verbose output\n" - " -n only modify property in memory\n" - "\n" - "%s NAME VALUE set property entry NAME with VALUE\n" - "%s --file FILE load props from FILE\n" - "%s --delete NAME remove prop entry NAME\n" - "\n" + fprintf(stderr, + "resetprop v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu & nkk71) - System Props Modification Tool\n\n" + "Usage: %s [flags] [options...]\n" + "\n" + "Options:\n" + " -h, --help show this message\n" + " (no arguments) print all properties\n" + " NAME get property\n" + " NAME VALUE set property entry NAME with VALUE\n" + " --file FILE load props from FILE\n" + " --delete NAME delete property\n" + "\n" + "Flags:\n" + " -v print verbose output to stderr\n" + " -n set properties without init triggers\n" + " only affects setprop\n" + " -p access actual persist storage\n" + " only affects getprop and deleteprop\n" + "\n" - , arg0, arg0, arg0, arg0); - return 1; + , arg0); + return 1; } static int init_resetprop() { - if (__system_properties_init2()) { - PRINT_E("resetprop: Initialize error\n"); - return -1; - } - return 0; + if (__system_properties_init2()) { + PRINT_E("resetprop: Initialize error\n"); + return -1; + } + return 0; } int prop_exist(const char *name) { - if (init_resetprop()) return 0; - return __system_property_find2(name) != NULL; + if (init_resetprop()) return 0; + return __system_property_find2(name) != NULL; } static void read_prop_info(void* cookie, const char *name, const char *value, uint32_t serial) { - strcpy((char *) cookie, value); + strcpy((char *) cookie, value); +} + + +char *getprop(const char *name) { + return getprop2(name, 0); } // Get prop by name, return string (should free manually!) -char *getprop(const char *name) { - if (init_resetprop()) return NULL; - const prop_info *pi = __system_property_find2(name); - if (pi == NULL) { - PRINT_D("resetprop: prop [%s] does not exist\n", name); - return NULL; - } - char value[PROP_VALUE_MAX]; - __system_property_read_callback2(pi, read_prop_info, value); - PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value); - return strdup(value); +char *getprop2(const char *name, int persist) { + if (check_legal_property_name(name)) + return NULL; + char value[PROP_VALUE_MAX]; + if (init_resetprop()) return NULL; + const prop_info *pi = __system_property_find2(name); + if (pi == NULL) { + if (persist && strncmp(name, "persist.", 8) == 0) { + // Try to read from file + char path[PATH_MAX]; + snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name); + int fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) goto no_prop; + PRINT_D("resetprop: read prop from [%s]\n", path); + size_t len = read(fd, value, sizeof(value)); + value[len] = '\0'; // Null terminate the read value + } else { +no_prop: + PRINT_D("resetprop: prop [%s] does not exist\n", name); + return NULL; + } + } else { + __system_property_read_callback2(pi, read_prop_info, value); + } + PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value); + return strdup(value); } -static void (*cb)(const char *); +struct wrapper { + void (*func)(const char *, const char *); +}; -static void run_actual_cb(void* cookie, const char *name, const char *value, uint32_t serial) { - cb(name); +static void cb_wrapper(void* cookie, const char *name, const char *value, uint32_t serial) { + ((wrapper *) cookie)->func(name, value); } static void prop_foreach_cb(const prop_info* pi, void* cookie) { - __system_property_read_callback2(pi, run_actual_cb, NULL); + __system_property_read_callback2(pi, cb_wrapper, cookie); } -void getprop_all(void (*cbk)(const char *name)) { - if (init_resetprop()) return; - cb = cbk; - __system_property_foreach2(prop_foreach_cb, NULL); +class property { +public: + property(const char *n, const char *v) { + name = strdup(n); + value = strdup(v); + } + ~property() { + free((void *)name); + free((void *)value); + } + const char *name; + const char *value; +}; + +vector prop_list; + +static int prop_cmp(const void *p1, const void *p2) { + return strcmp((*((property **) p1))->name, (*((property **) p2))->name); +} + +static void print_all_props_cb(const char *name, const char *value) { + vec_push_back(&prop_list, new property(name, value)); +} + +static void print_all_props(int persist) { + void *p; + vec_init(&prop_list); + getprop_all(print_all_props_cb); + if (persist) { + // Check all persist props in data + DIR *dir = opendir(PERSISTENT_PROPERTY_DIR); + struct dirent *entry; + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 ) + continue; + int found = 0; + vec_for_each(&prop_list, p) { + if (strcmp(((property *) p)->name, entry->d_name) == 0) { + found = 1; + break; + } + } + if (!found) + vec_push_back(&prop_list, new property(entry->d_name, getprop2(entry->d_name, 1))); + } + } + vec_sort(&prop_list, prop_cmp); + vec_for_each(&prop_list, p) { + printf("[%s]: [%s]\n", ((property *) p)->name, ((property *) p)->value); + delete((property *) p); + } + vec_destroy(&prop_list); +} + +void getprop_all(void (*callback)(const char*, const char*)) { + if (init_resetprop()) return; + struct wrapper wrap = { + .func = callback + }; + __system_property_foreach2(prop_foreach_cb, &wrap); } int setprop(const char *name, const char *value) { - return setprop2(name, value, 1); + return setprop2(name, value, 1); } int setprop2(const char *name, const char *value, const int trigger) { - if (init_resetprop()) return -1; - int ret; + if (check_legal_property_name(name)) + return 1; + if (init_resetprop()) return -1; + int ret; - prop_info *pi = (prop_info*) __system_property_find2(name); - if (pi != NULL) { - if (trigger) { - if (!strncmp(name, "ro.", 3)) deleteprop(name, trigger); - ret = __system_property_set2(name, value); - } else { - ret = __system_property_update2(pi, value, strlen(value)); - } - } else { - PRINT_D("resetprop: New prop [%s]\n", name); - if (trigger) { - ret = __system_property_set2(name, value); - } else { - ret = __system_property_add2(name, strlen(name), value, strlen(value)); - } - } + prop_info *pi = (prop_info*) __system_property_find2(name); + if (pi != NULL) { + if (trigger) { + if (strncmp(name, "ro.", 3) == 0) deleteprop(name); + ret = __system_property_set2(name, value); + } else { + ret = __system_property_update2(pi, value, strlen(value)); + } + } else { + PRINT_D("resetprop: New prop [%s]\n", name); + if (trigger) { + ret = __system_property_set2(name, value); + } else { + ret = __system_property_add2(name, strlen(name), value, strlen(value)); + } + } - PRINT_D("resetprop: setprop [%s]: [%s] by %s\n", name, value, - trigger ? "property_service" : "modifing prop data structure"); + PRINT_D("resetprop: setprop [%s]: [%s] by %s\n", name, value, + trigger ? "property_service" : "modifing prop data structure"); - if (ret) - PRINT_E("resetprop: setprop error\n"); + if (ret) + PRINT_E("resetprop: setprop error\n"); - return ret; + return ret; } -int deleteprop(const char *name, const int trigger) { - if (init_resetprop()) return -1; - PRINT_D("resetprop: deleteprop [%s]\n", name); - if (trigger && strstr(name, "persist.")) { - char buffer[PATH_MAX]; - snprintf(buffer, sizeof(buffer), "%s/%s", PERSISTENT_PROPERTY_DIR, name); - unlink(buffer); - } - return __system_property_del(name); +int deleteprop(const char *name) { + return deleteprop2(name, 1); +} + +int deleteprop2(const char *name, const int persist) { + if (check_legal_property_name(name)) + return 1; + if (init_resetprop()) return -1; + char path[PATH_MAX]; + path[0] = '\0'; + PRINT_D("resetprop: deleteprop [%s]\n", name); + if (persist && strncmp(name, "persist.", 8) == 0) + snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name); + return __system_property_del(name) && unlink(path); } int read_prop_file(const char* filename, const int trigger) { - if (init_resetprop()) return -1; - PRINT_D("resetprop: Load prop file [%s]\n", filename); - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - PRINT_E("Cannot open [%s]\n", filename); - return 1; - } - char *line = NULL, *pch; - size_t len; - ssize_t read; - int comment = 0, i; - while ((read = getline(&line, &len, fp)) != -1) { - // Remove the trailing newline - if (line[read - 1] == '\n') { - line[read - 1] = '\0'; - --read; - } - comment = 0; - for (i = 0; i < read; ++i) { - // Ignore starting spaces - if (line[i] == ' ') continue; - else { - // A line starting with # is ignored - if (line[i] == '#') comment = 1; - break; - } - } - if (comment) continue; - pch = strchr(line, '='); - // Ignore ivalid formats - if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue; - // Separate the string - *pch = '\0'; - setprop2(line + i, pch + 1, trigger); - } - free(line); - fclose(fp); - return 0; + if (init_resetprop()) return -1; + PRINT_D("resetprop: Load prop file [%s]\n", filename); + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + PRINT_E("Cannot open [%s]\n", filename); + return 1; + } + char *line = NULL, *pch; + size_t len; + ssize_t read; + int comment = 0, i; + while ((read = getline(&line, &len, fp)) != -1) { + // Remove the trailing newline + if (line[read - 1] == '\n') { + line[read - 1] = '\0'; + --read; + } + comment = 0; + for (i = 0; i < read; ++i) { + // Ignore starting spaces + if (line[i] == ' ') continue; + else { + // A line starting with # is ignored + if (line[i] == '#') comment = 1; + break; + } + } + if (comment) continue; + pch = strchr(line, '='); + // Ignore ivalid formats + if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue; + // Separate the string + *pch = '\0'; + setprop2(line + i, pch + 1, trigger); + } + free(line); + fclose(fp); + return 0; } int resetprop_main(int argc, char *argv[]) { + int trigger = 1, persist = 0; + char *argv0 = argv[0], *prop; - int del = 0, file = 0, trigger = 1; + --argc; + ++argv; - int exp_arg = 2; - char *name, *value, *filename; + // Parse flags and -- options + while (argc && argv[0][0] == '-') { + for (int idx = 1; 1; ++idx) { + switch (argv[0][idx]) { + case '-': + if (strcmp(argv[0], "--file") == 0 && argc == 2) { + return read_prop_file(argv[1], trigger); + } else if (strcmp(argv[0], "--delete") == 0 && argc == 2) { + return deleteprop2(argv[1], persist); + } else if (strcmp(argv[0], "--help") == 0) { + goto usage; + } + case 'v': + verbose = 1; + continue; + case 'p': + persist = 1; + continue; + case 'n': + trigger = 0; + continue; + case '\0': + break; + case 'h': + default: + usage: + return usage(argv0); + } + break; + } + --argc; + ++argv; + } - if (argc < 3) { - return usage(argv[0]); - } - - for (int i = 1; i < argc; ++i) { - if (!strcmp("-v", argv[i])) { - verbose = 1; - } else if (!strcmp("-n", argv[i])) { - trigger = 0; - } else if (!strcmp("--file", argv[i])) { - file = 1; - exp_arg = 1; - } else if (!strcmp("--delete", argv[i])) { - del = 1; - exp_arg = 1; - } else { - if (i + exp_arg > argc) { - return usage(argv[0]); - } - if (file) { - filename = argv[i]; - break; - } else { - if(!is_legal_property_name(argv[i], strlen(argv[i]))) { - PRINT_E("Illegal property name: [%s]\n", argv[i]); - return 1; - } - name = argv[i]; - if (exp_arg > 1) { - if (strlen(argv[i + 1]) >= PROP_VALUE_MAX) { - PRINT_E("Value too long: [%s]\n", argv[i + 1]); - return 1; - } - value = argv[i + 1]; - } - break; - } - } - } - - if (file) { - return read_prop_file(filename, trigger); - } else if (del) { - return deleteprop(name, trigger); - } else { - return setprop2(name, value, trigger); - } - - return 0; + switch (argc) { + case 0: + print_all_props(persist); + return 0; + case 1: + prop = getprop2(argv[0], persist); + if (prop == NULL) return 1; + printf("%s\n", prop); + free(prop); + return 0; + case 2: + return setprop2(argv[0], argv[1], trigger); + default: + usage(argv0); + return 1; + } }