diff --git a/zygiskd/build.gradle.kts b/zygiskd/build.gradle.kts index 62a0f64..e7bd970 100644 --- a/zygiskd/build.gradle.kts +++ b/zygiskd/build.gradle.kts @@ -53,6 +53,7 @@ val Files = arrayOf( "root_impl/apatch.c", "root_impl/common.c", "root_impl/kernelsu.c", + "root_impl/magisk.c", "companion.c", "dl.c", "main.c", diff --git a/zygiskd/src/companion.c b/zygiskd/src/companion.c index c12337b..b45b3b6 100644 --- a/zygiskd/src/companion.c +++ b/zygiskd/src/companion.c @@ -30,7 +30,7 @@ zygisk_companion_entry_func load_module(int fd) { return (zygisk_companion_entry_func)entry; } -void *call_entry(void *arg) { +void *call_entry(void *restrict arg) { int fd = *((int *)arg); struct stat st0; @@ -92,7 +92,7 @@ void entry(int fd) { if (entry == NULL) { LOGI("No companion entry for: %s\n", name); - uint8_t response[1] = { 0 }; + uint8_t response = 0; write(fd, &response, sizeof(response)); exit(0); @@ -102,7 +102,7 @@ void entry(int fd) { LOGI("Companion process created for: %s\n", name); - uint8_t response[1] = { 1 }; + uint8_t response = 1; write(fd, &response, sizeof(response)); while (1) { @@ -114,21 +114,17 @@ void entry(int fd) { break; } - int client_fd; - recv_fd(fd, &client_fd); + int *client_fd = malloc(sizeof(int)); + recv_fd(fd, client_fd); - LOGI("New companion request from module \"%s\" with fd \"%d\"\n", name, client_fd); + LOGI("New companion request from module \"%s\" with fd \"%d\"\n", name, *client_fd); write(fd, &response, sizeof(response)); - - /* TODO: Do we really need to allocate this..? */ - int *client_fd_ptr = malloc(sizeof(int)); - *client_fd_ptr = client_fd; LOGI("Creating new thread for companion request\n"); pthread_t thread; - pthread_create(&thread, NULL, call_entry, (void *)client_fd_ptr); + pthread_create(&thread, NULL, call_entry, (void *)client_fd); pthread_detach(thread); } } diff --git a/zygiskd/src/dl.c b/zygiskd/src/dl.c index eddcf1f..b7cba7b 100644 --- a/zygiskd/src/dl.c +++ b/zygiskd/src/dl.c @@ -23,7 +23,7 @@ struct AndroidDlextinfo { void *android_dlopen_ext(const char *filename, int flags, const struct AndroidDlextinfo *extinfo); -void *android_dlopen(char *path, u_int32_t flags) { +void *android_dlopen(char *restrict path, uint32_t flags) { char *dir = dirname(path); struct AndroidDlextinfo info = { .flags = 0, diff --git a/zygiskd/src/dl.h b/zygiskd/src/dl.h index 32cd248..2c32160 100644 --- a/zygiskd/src/dl.h +++ b/zygiskd/src/dl.h @@ -1,6 +1,6 @@ #ifndef DL_H #define DL_H -void *android_dlopen(char *path, u_int32_t flags); +void *android_dlopen(char *restrict path, u_int32_t flags); #endif /* DL_H */ diff --git a/zygiskd/src/main.c b/zygiskd/src/main.c index b7b9d86..f6f9073 100644 --- a/zygiskd/src/main.c +++ b/zygiskd/src/main.c @@ -11,7 +11,7 @@ #include "utils.h" -int __android_log_print(int prio, const char *tag, const char *fmt, ...); +int __android_log_print(int prio, const char *tag, const char *fmt, ...); int main(int argc, char *argv[]) { LOGI("Initializing zygiskd: %s\n", argv[0]); @@ -61,6 +61,11 @@ int main(int argc, char *argv[]) { case APatch: { LOGI("APatch root implementation found.\n"); + return 0; + } + case Magisk: { + LOGI("Magisk root implementation found.\n"); + return 0; } } diff --git a/zygiskd/src/root_impl/apatch.c b/zygiskd/src/root_impl/apatch.c index e43ca4f..ce597d4 100644 --- a/zygiskd/src/root_impl/apatch.c +++ b/zygiskd/src/root_impl/apatch.c @@ -12,7 +12,8 @@ enum RootImplState apatch_get_existence(void) { struct stat s; if (stat("/data/adb/apd", &s) != 0) { - LOGE("APATCH | Failed to stat /data/adb/apd: %s\n", strerror(errno)); + if (errno != ENOENT) LOGE("Failed to stat APatch apd binary: %s\n", strerror(errno)); + errno = 0; return Inexistent; } @@ -20,18 +21,16 @@ enum RootImplState apatch_get_existence(void) { char apatch_version[32]; char *const argv[] = { "apd", "-V", NULL }; - LOGI("APATCH | Checking for apd existence\n"); if (!exec_command(apatch_version, sizeof(apatch_version), "/data/adb/apd", argv)) { - LOGE("APATCH | Failed to execute apd binary: %s\n", strerror(errno)); + LOGE("Failed to execute apd binary: %s\n", strerror(errno)); errno = 0; return Inexistent; } int version = atoi(apatch_version + strlen("apd ")); - LOGI("APATCH | apd version: %d\n", version); - if (version == 0) return Abnormal; + if (version == 0) return Abnormal; if (version >= MIN_APATCH_VERSION && version <= 999999) return Supported; if (version >= 1 && version <= MIN_APATCH_VERSION - 1) return TooOld; @@ -49,38 +48,54 @@ struct packages_config { size_t size; }; -bool _apatch_get_package_config(struct packages_config *config) { +/* WARNING: Dynamic memory based */ +bool _apatch_get_package_config(struct packages_config *restrict config) { FILE *fp = fopen("/data/adb/ap/package_config", "r"); if (fp == NULL) { - LOGE("APATCH | Failed to open package_config: %s\n", strerror(errno)); + LOGE("Failed to open APatch's package_config: %s\n", strerror(errno)); return false; } - char line[256]; + char line[1024]; /* INFO: Skip the CSV header */ fgets(line, sizeof(line), fp); + LOGI("meow meow: %s\n", line); + + config->size = 0; while (fgets(line, sizeof(line), fp) != NULL) { - config->configs = realloc(config, (config->size + 1) * sizeof(struct package_config)); + LOGI("meow meow\n"); + + config->configs = realloc(config->configs, (config->size + 1) * sizeof(struct package_config)); if (config->configs == NULL) { - LOGE("APATCH | Failed to realloc package config: %s\n", strerror(errno)); + LOGE("Failed to realloc APatch config struct: %s\n", strerror(errno)); fclose(fp); return false; } + LOGI("meow meow (1): %s\n", line); + strtok(line, ","); + LOGI("meow meow (2)\n"); + char *exclude_str = strtok(NULL, ","); if (exclude_str == NULL) continue; + LOGI("meow meow: %s\n", exclude_str); + char *allow_str = strtok(NULL, ","); if (allow_str == NULL) continue; + LOGI("meow meow: %s\n", allow_str); + char *uid_str = strtok(NULL, ","); - if (uid_str == NULL) continue; + if (uid_str == NULL) continue; + + LOGI("meow meow: %s\n", uid_str); config->configs[config->size].uid = atoi(uid_str); config->configs[config->size].root_granted = strcmp(allow_str, "1") == 0; @@ -138,7 +153,12 @@ bool apatch_uid_should_umount(uid_t uid) { bool apatch_uid_is_manager(uid_t uid) { struct stat s; - if (stat("/data/user_de/0/me.bmax.apatch", &s) == -1) return false; + if (stat("/data/user_de/0/me.bmax.apatch", &s) == -1) { + if (errno != ENOENT) LOGE("Failed to stat APatch manager data directory: %s\n", strerror(errno)); + errno = 0; + + return false; + } return s.st_uid == uid; } diff --git a/zygiskd/src/root_impl/common.c b/zygiskd/src/root_impl/common.c index d319430..92eb18e 100644 --- a/zygiskd/src/root_impl/common.c +++ b/zygiskd/src/root_impl/common.c @@ -1,7 +1,11 @@ +#include + #include +#include "../utils.h" #include "kernelsu.h" #include "apatch.h" +#include "magisk.h" #include "common.h" @@ -10,7 +14,36 @@ static enum RootImpl ROOT_IMPL = None; void root_impls_setup(void) { if (ksu_get_existence() == Supported) ROOT_IMPL = KernelSU; else if (apatch_get_existence() == Supported) ROOT_IMPL = APatch; + else if (magisk_get_existence() == Supported) ROOT_IMPL = Magisk; else ROOT_IMPL = None; + + switch (ROOT_IMPL) { + case None: { + LOGI("No root implementation found.\n"); + + break; + } + case Multiple: { + LOGI("Multiple root implementations found.\n"); + + break; + } + case KernelSU: { + LOGI("KernelSU root implementation found.\n"); + + break; + } + case APatch: { + LOGI("APatch root implementation found.\n"); + + break; + } + case Magisk: { + LOGI("Magisk root implementation found.\n"); + + break; + } + } } enum RootImpl get_impl(void) { @@ -18,43 +51,52 @@ enum RootImpl get_impl(void) { } bool uid_granted_root(uid_t uid) { - // switch (get_impl()) { - // case KernelSU: { + switch (get_impl()) { + case KernelSU: { return ksu_uid_granted_root(uid); - // } - // case APatch: { - // return apatch_uid_granted_root(uid); - // } - // default: { - // return false; - // } - // } + } + case APatch: { + return apatch_uid_granted_root(uid); + } + case Magisk: { + return magisk_uid_granted_root(uid); + } + default: { + return false; + } + } } bool uid_should_umount(uid_t uid) { - // switch (get_impl()) { - // case KernelSU: { + switch (get_impl()) { + case KernelSU: { return ksu_uid_should_umount(uid); - // } - // case APatch: { - // return apatch_uid_should_umount(uid); - // } - // default: { - // return false; - // } - // } + } + case APatch: { + return apatch_uid_should_umount(uid); + } + case Magisk: { + return magisk_uid_should_umount(uid); + } + default: { + return false; + } + } } bool uid_is_manager(uid_t uid) { - // switch (get_impl()) { - // case KernelSU: { + switch (get_impl()) { + case KernelSU: { return ksu_uid_is_manager(uid); - // } - // case APatch: { - // return apatch_uid_is_manager(uid); - // } - // default: { - // return false; - // } - // } + } + case APatch: { + return apatch_uid_is_manager(uid); + } + case Magisk: { + return magisk_uid_is_manager(uid); + } + default: { + return false; + } + } } diff --git a/zygiskd/src/root_impl/common.h b/zygiskd/src/root_impl/common.h index 79964f1..13bef4e 100644 --- a/zygiskd/src/root_impl/common.h +++ b/zygiskd/src/root_impl/common.h @@ -7,7 +7,8 @@ enum RootImpl { None, Multiple, KernelSU, - APatch + APatch, + Magisk }; void root_impls_setup(void); diff --git a/zygiskd/src/root_impl/kernelsu.c b/zygiskd/src/root_impl/kernelsu.c index 853b494..f7f9ceb 100644 --- a/zygiskd/src/root_impl/kernelsu.c +++ b/zygiskd/src/root_impl/kernelsu.c @@ -48,7 +48,12 @@ bool ksu_uid_should_umount(uid_t uid) { bool ksu_uid_is_manager(uid_t uid) { struct stat s; - if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == -1) return false; + if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == -1) { + if (errno != ENOENT) LOGE("Failed to stat KSU manager data directory: %s\n", strerror(errno)); + errno = 0; + + return false; + } return s.st_uid == uid; } diff --git a/zygiskd/src/root_impl/magisk.c b/zygiskd/src/root_impl/magisk.c new file mode 100644 index 0000000..76570e2 --- /dev/null +++ b/zygiskd/src/root_impl/magisk.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../constants.h" +#include "../utils.h" + +#include "magisk.h" + +char *supported_variants[] = { + "kitsune" +}; + +char *magisk_managers[] = { + "com.topjohnwu.magisk", + "io.github.huskydg.magisk" +}; + +enum magisk_variants variant = Official; + +enum RootImplState magisk_get_existence(void) { + char *argv[] = { "magisk", "-v", NULL }; + + char magisk_info[32]; + if (!exec_command(magisk_info, sizeof(magisk_info), "/sbin/magisk", argv)) { + LOGE("Failed to execute magisk binary: %s\n", strerror(errno)); + errno = 0; + + return Inexistent; + } + + for (unsigned long i = 0; i < sizeof(supported_variants) / sizeof(char *); i++) { + if (strstr(magisk_info, supported_variants[i])) variant = (enum magisk_variants)(i + 1); + } + + argv[1] = "-V"; + + char magisk_version[32]; + if (!exec_command(magisk_version, sizeof(magisk_version), "/sbin/magisk", argv)) { + LOGE("Failed to execute magisk binary: %s\n", strerror(errno)); + errno = 0; + + return Abnormal; + } + + if (atoi(magisk_version) >= MIN_MAGISK_VERSION) return Supported; + else return TooOld; +} + +bool magisk_uid_granted_root(uid_t uid) { + char sqlite_cmd[256]; + snprintf(sqlite_cmd, sizeof(sqlite_cmd), "select 1 from policies where uid=%d and policy=2 limit 1", uid); + + char *const argv[] = { "magisk", "--sqlite", sqlite_cmd, NULL }; + + char result[32]; + if (!exec_command(result, sizeof(result), "/sbin/magisk", argv)) { + LOGE("Failed to execute magisk binary: %s\n", strerror(errno)); + errno = 0; + + return false; + } + + return result[0] != '\0'; +} + +bool magisk_uid_should_umount(uid_t uid) { + struct dirent *entry; + DIR *proc = opendir("/proc"); + if (!proc) { + LOGE("Failed to open /proc: %s\n", strerror(errno)); + errno = 0; + + return false; + } + + while ((entry = readdir(proc))) { + if (entry->d_type != DT_DIR) continue; + + if (atoi(entry->d_name) == 0) continue; + + char stat_path[32]; + snprintf(stat_path, sizeof(stat_path), "/proc/%s/stat", entry->d_name); + + struct stat s; + if (stat(stat_path, &s) == -1) continue; + + if (s.st_uid != uid) continue; + + char package_name[255 + 1]; + + char cmdline_path[32]; + snprintf(cmdline_path, sizeof(cmdline_path), "/proc/%s/cmdline", entry->d_name); + + int cmdline = open(cmdline_path, O_RDONLY); + if (cmdline == -1) { + LOGE("Failed to open %s: %s\n", cmdline_path, strerror(errno)); + errno = 0; + + closedir(proc); + + continue; + } + + ssize_t read_bytes = read(cmdline, package_name, sizeof(package_name) - 1); + if (read_bytes == -1) { + LOGE("Failed to read from %s: %s\n", cmdline_path, strerror(errno)); + errno = 0; + + close(cmdline); + closedir(proc); + + continue; + } + + close(cmdline); + closedir(proc); + + package_name[read_bytes] = '\0'; + + char sqlite_cmd[256]; + snprintf(sqlite_cmd, sizeof(sqlite_cmd), "select 1 from denylist where package_name=\"%s\" limit 1", package_name); + + char *const argv[] = { "magisk", "--sqlite", sqlite_cmd, NULL }; + + char result[32]; + if (!exec_command(result, sizeof(result), "/sbin/magisk", argv)) { + LOGE("Failed to execute magisk binary: %s\n", strerror(errno)); + errno = 0; + + return false; + } + + return result[0] != '\0'; + } + + return false; +} + +bool magisk_uid_is_manager(uid_t uid) { + char sqlite_cmd[256]; + snprintf(sqlite_cmd, sizeof(sqlite_cmd), "select value from strings where key=\"requester\" limit 1"); + + char *const argv[] = { "magisk", "--sqlite", sqlite_cmd, NULL }; + + char output[32]; + if (!exec_command(output, sizeof(output), "/sbin/magisk", argv)) { + LOGE("Failed to execute magisk binary: %s\n", strerror(errno)); + errno = 0; + + return false; + } + + if (output[0] == '\0') { + char stat_path[PATH_MAX]; + snprintf(stat_path, sizeof(stat_path), "/data/user_de/0/%s", magisk_managers[(int)variant]); + + struct stat s; + if (stat(stat_path, &s) == -1) { + LOGE("Failed to stat %s: %s\n", stat_path, strerror(errno)); + errno = 0; + + return false; + } + + return s.st_uid == uid; + } else { + char stat_path[PATH_MAX]; + snprintf(stat_path, sizeof(stat_path), "/data/user_de/0/%s", output + strlen("value=")); + + LOGI("Checking |%s|\n", stat_path); + + struct stat s; + if (stat(stat_path, &s) == -1) { + LOGE("Failed to stat %s: %s\n", stat_path, strerror(errno)); + LOGE("???\n"); + errno = 0; + + return false; + } + + return s.st_uid == uid; + } +} diff --git a/zygiskd/src/root_impl/magisk.h b/zygiskd/src/root_impl/magisk.h new file mode 100644 index 0000000..0260d7a --- /dev/null +++ b/zygiskd/src/root_impl/magisk.h @@ -0,0 +1,19 @@ +#ifndef MAGISK_H +#define MAGISK_H + +#include "../constants.h" + +enum magisk_variants { + Official, + Kitsune +}; + +enum RootImplState magisk_get_existence(void); + +bool magisk_uid_granted_root(uid_t uid); + +bool magisk_uid_should_umount(uid_t uid); + +bool magisk_uid_is_manager(uid_t uid); + +#endif diff --git a/zygiskd/src/utils.c b/zygiskd/src/utils.c index 141c3f8..19d8e52 100644 --- a/zygiskd/src/utils.c +++ b/zygiskd/src/utils.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -43,31 +44,53 @@ bool switch_mount_namespace(pid_t pid) { int __system_property_get(const char *, char *); -void get_property(const char *name, char *output) { +void get_property(const char *restrict name, char *restrict output) { __system_property_get(name, output); } -void set_socket_create_context(const char *context) { +void set_socket_create_context(const char *restrict context) { char path[PATH_MAX]; snprintf(path, PATH_MAX, "/proc/thread-self/attr/sockcreate"); FILE *sockcreate = fopen(path, "w"); if (sockcreate == NULL) { - LOGE("Failed to open /proc/thread-self/attr/sockcreate: %s\n", strerror(errno)); + LOGE("Failed to open /proc/thread-self/attr/sockcreate: %s Now trying to via gettid().\n", strerror(errno)); - return; + goto fail; } if (fwrite(context, 1, strlen(context), sockcreate) != strlen(context)) { - LOGE("Failed to write to /proc/thread-self/attr/sockcreate: %s\n", strerror(errno)); + LOGE("Failed to write to /proc/thread-self/attr/sockcreate: %s Now trying to via gettid().\n", strerror(errno)); - return; + fclose(sockcreate); + + goto fail; } fclose(sockcreate); + + return; + + fail: + snprintf(path, PATH_MAX, "/proc/self/task/%d/attr/sockcreate", gettid()); + + sockcreate = fopen(path, "w"); + if (sockcreate == NULL) { + LOGE("Failed to open %s: %s\n", path, strerror(errno)); + + return; + } + + if (fwrite(context, 1, strlen(context), sockcreate) != strlen(context)) { + LOGE("Failed to write to %s: %s\n", path, strerror(errno)); + + return; + } + + fclose(sockcreate); } -static void get_current_attr(char *output) { +static void get_current_attr(char *restrict output, size_t size) { char path[PATH_MAX]; snprintf(path, PATH_MAX, "/proc/self/attr/current"); @@ -78,8 +101,8 @@ static void get_current_attr(char *output) { return; } - if (fgets(output, PATH_MAX, current) == NULL) { - LOGE("fgets: %s\n", strerror(errno)); + if (fread(output, 1, size, current) == 0) { + LOGE("fread: %s\n", strerror(errno)); return; } @@ -87,9 +110,9 @@ static void get_current_attr(char *output) { fclose(current); } -void unix_datagram_sendto(const char *path, void *buf, size_t len) { +void unix_datagram_sendto(const char *restrict path, void *restrict buf, size_t len) { char current_attr[PATH_MAX]; - get_current_attr(current_attr); + get_current_attr(current_attr, sizeof(current_attr)); set_socket_create_context(current_attr); @@ -122,14 +145,14 @@ void unix_datagram_sendto(const char *path, void *buf, size_t len) { close(socket_fd); } -int chcon(const char *path, const char *context) { +int chcon(const char *restrict path, const char *context) { char command[PATH_MAX]; snprintf(command, PATH_MAX, "chcon %s %s", context, path); return system(command); } -int unix_listener_from_path(char *path) { +int unix_listener_from_path(char *restrict path) { if (remove(path) == -1 && errno != ENOENT) { LOGE("remove: %s\n", strerror(errno)); @@ -143,10 +166,9 @@ int unix_listener_from_path(char *path) { return -1; } - struct sockaddr_un addr; - - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; + struct sockaddr_un addr = { + .sun_family = AF_UNIX + }; strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { @@ -204,7 +226,7 @@ ssize_t send_fd(int sockfd, int fd) { return sent_bytes; } -ssize_t recv_fd(int sockfd, int *fd) { +ssize_t recv_fd(int sockfd, int *restrict fd) { char control_buf[CMSG_SPACE(sizeof(int))]; memset(control_buf, 0, sizeof(control_buf)); @@ -234,7 +256,7 @@ ssize_t recv_fd(int sockfd, int *fd) { return received_bytes; } -ssize_t write_string(int fd, const char *str) { +ssize_t write_string(int fd, const char *restrict str) { size_t len = strlen(str); ssize_t written_bytes = write(fd, &len, sizeof(len)); @@ -254,7 +276,7 @@ ssize_t write_string(int fd, const char *str) { return written_bytes; } -ssize_t read_string(int fd, char *str, size_t len) { +ssize_t read_string(int fd, char *restrict str, size_t len) { size_t str_len_buf[1]; ssize_t read_bytes = read(fd, &str_len_buf, sizeof(str_len_buf)); @@ -282,7 +304,8 @@ ssize_t read_string(int fd, char *str, size_t len) { return read_bytes; } -bool exec_command(char *buf, size_t len, const char *file, char *const argv[]) { +/* INFO: Cannot use restrict here as execv does not have restrict */ +bool exec_command(char *restrict buf, size_t len, const char *restrict file, char *const argv[]) { int link[2]; pid_t pid; @@ -308,10 +331,55 @@ bool exec_command(char *buf, size_t len, const char *file, char *const argv[]) { close(link[1]); int nbytes = read(link[0], buf, len); - buf[nbytes] = '\0'; + buf[nbytes - 1] = '\0'; wait(NULL); } return true; } + +bool check_unix_socket(int fd, bool block) { + struct pollfd pfd = { + .fd = fd, + .events = POLLIN, + .revents = 0 + }; + + int timeout = block ? -1 : 0; + poll(&pfd, 1, timeout); + + return (pfd.revents & !POLLIN) != 0 ? false : true; +} + +/* INFO: Cannot use restrict here as execv does not have restrict */ +int non_blocking_execv(const char *restrict file, char *const argv[]) { + int link[2]; + pid_t pid; + + if (pipe(link) == -1) { + LOGE("pipe: %s\n", strerror(errno)); + + return -1; + } + + if ((pid = fork()) == -1) { + LOGE("fork: %s\n", strerror(errno)); + + return -1; + } + + if (pid == 0) { + dup2(link[1], STDOUT_FILENO); + close(link[0]); + close(link[1]); + + execv(file, argv); + } else { + close(link[1]); + + return link[0]; + } + + return -1; +} diff --git a/zygiskd/src/utils.h b/zygiskd/src/utils.h index 8d112ea..8e37bfe 100644 --- a/zygiskd/src/utils.h +++ b/zygiskd/src/utils.h @@ -8,38 +8,40 @@ #define CONCAT_(x,y) x##y #define CONCAT(x,y) CONCAT_(x,y) -#define LOGI(...) \ - __android_log_print(ANDROID_LOG_INFO, lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \ - printf(__VA_ARGS__); \ +#define LOGI(...) \ + __android_log_print(ANDROID_LOG_INFO, lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \ + printf(__VA_ARGS__); \ FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__)) #define LOGE(...) \ __android_log_print(ANDROID_LOG_INFO , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \ - printf(__VA_ARGS__); \ + printf(__VA_ARGS__); \ FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__)) bool switch_mount_namespace(pid_t pid); -void get_property(const char *name, char *output); +void get_property(const char *name, char *restrict output); -void set_socket_create_context(const char *context); +void set_socket_create_context(const char *restrict context); -void unix_datagram_sendto(const char *path, void *buf, size_t len); +void unix_datagram_sendto(const char *restrict path, void *restrict buf, size_t len); -int chcon(const char *path, const char *context); +int chcon(const char *path, const char *restrict context); int unix_listener_from_path(char *path); ssize_t send_fd(int sockfd, int fd); -ssize_t recv_fd(int sockfd, int *fd); +ssize_t recv_fd(int sockfd, int *restrict fd); -ssize_t write_string(int fd, const char *str); +ssize_t write_string(int fd, const char *restrict str); -ssize_t read_string(int fd, char *str, size_t len); +ssize_t read_string(int fd, char *restrict str, size_t len); -bool exec_command(char *buf, size_t len, const char *file, char *const argv[]); +bool exec_command(char *restrict buf, size_t len, const char *restrict file, char *const argv[]); bool check_unix_socket(int fd, bool block); +int non_blocking_execv(const char *restrict file, char *const argv[]); + #endif /* UTILS_H */ diff --git a/zygiskd/src/zygiskd.c b/zygiskd/src/zygiskd.c index 45f04b1..38e5525 100644 --- a/zygiskd/src/zygiskd.c +++ b/zygiskd/src/zygiskd.c @@ -12,6 +12,8 @@ #include #include +#include +#include #include @@ -97,8 +99,10 @@ static enum Architecture get_arch(void) { exit(1); } -int create_library_fd(const char *so_path) { - int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING); +int create_library_fd(const char *restrict so_path) { + /* INFO: This is required as older implementations of glibc may not + have the memfd_create function call, causing a crash. */ + int memfd = syscall(SYS_memfd_create, "jit-cache-zygisk", MFD_ALLOW_SEALING); if (memfd == -1) { LOGE("Failed creating memfd: %s\n", strerror(errno)); @@ -155,9 +159,8 @@ int create_library_fd(const char *so_path) { return memfd; } - /* WARNING: Dynamic memory based */ -static void load_modules(enum Architecture arch, struct Context *context) { +static void load_modules(enum Architecture arch, struct Context *restrict context) { context->len = 0; context->modules = malloc(1); @@ -213,11 +216,16 @@ static void load_modules(enum Architecture arch, struct Context *context) { char disabled[PATH_MAX]; snprintf(disabled, PATH_MAX, "/data/adb/modules/%s/disable", name); - if (stat(disabled, &st) != -1) { - errno = 0; + if (stat(disabled, &st) == -1) { + if (errno != ENOENT) { + LOGE("Failed checking if module `%s` is disabled: %s\n", name, strerror(errno)); + errno = 0; - continue; - } + continue; + } + + errno = 0; + } else continue; LOGI("Loading module `%s`...\n", name); int lib_fd = create_library_fd(so_path); @@ -237,7 +245,7 @@ static void load_modules(enum Architecture arch, struct Context *context) { } } -static void free_modules(struct Context *context) { +static void free_modules(struct Context *restrict context) { for (int i = 0; i < context->len; i++) { free(context->modules[i].name); if (context->modules[i].companion != -1) close(context->modules[i].companion); @@ -250,7 +258,7 @@ static int create_daemon_socket(void) { return unix_listener_from_path(PATH_CP_NAME); } -static int spawn_companion(char *name, int lib_fd) { +static int spawn_companion(char *restrict name, int lib_fd) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { LOGE("Failed creating socket pair.\n"); @@ -324,7 +332,7 @@ static int spawn_companion(char *name, int lib_fd) { } /* INFO: if pid == 0: */ } else { - LOGI("Companion started (%d)\n", pid); + LOGI("Companion started\n"); /* INFO: There is no case where this will fail with a valid fd. */ fcntl(companion_fd, F_SETFD, 0); } @@ -334,19 +342,20 @@ static int spawn_companion(char *name, int lib_fd) { LOGI("Executing companion...\n"); - char arg[sizeof(ZYGISKD_FILE) + sizeof(" companion ") + 32]; - snprintf(arg, sizeof(arg), "%s companion %d", ZYGISKD_FILE, companion_fd); - - if (system(arg) == -1) { + char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL }; + if (non_blocking_execv(ZYGISKD_PATH, argv) == -1) { LOGE("Failed executing companion: %s\n", strerror(errno)); + close(companion_fd); + exit(1); } + LOGI("Bye bye!\n"); + exit(0); } -/* TODO: Is packed attribute really necessary? */ struct __attribute__((__packed__)) MsgHead { unsigned int cmd; int length; @@ -354,7 +363,7 @@ struct __attribute__((__packed__)) MsgHead { }; void zygiskd_start(void) { - LOGI("Welcome to ReZygisk %s!", ZKSU_VERSION); + LOGI("Welcome to ReZygisk %s!\n", ZKSU_VERSION); enum RootImpl impl = get_impl(); if (impl == None) { @@ -388,8 +397,28 @@ void zygiskd_start(void) { case None: { break; } case Multiple: { break; } case KernelSU: - case APatch: { - size_t root_impl_len = strlen(impl == KernelSU ? "KernelSU" : "APatch"); + case APatch: + case Magisk: { + size_t root_impl_len = 0; + switch (impl) { + case None: { break; } + case Multiple: { break; } + case KernelSU: { + root_impl_len = strlen("KernelSU"); + + break; + } + case APatch: { + root_impl_len = strlen("APatch"); + + break; + } + case Magisk: { + root_impl_len = strlen("Magisk"); + + break; + } + } if (context.len == 0) { msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: None") + root_impl_len + 1); @@ -407,6 +436,11 @@ void zygiskd_start(void) { case APatch: { memcpy(msg->data, "Root: APatch, Modules: None", strlen("Root: APatch, Modules: None")); + break; + } + case Magisk: { + memcpy(msg->data, "Root: Magisk, Modules: None", strlen("Root: Magisk, Modules: None")); + break; } } @@ -447,6 +481,11 @@ void zygiskd_start(void) { case APatch: { memcpy(msg->data, "Root: APatch, Modules: ", strlen("Root: APatch, Modules: ")); + break; + } + case Magisk: { + memcpy(msg->data, "Root: Magisk, Modules: ", strlen("Root: Magisk, Modules: ")); + break; } } @@ -582,6 +621,11 @@ void zygiskd_start(void) { case APatch: { flags |= PROCESS_ROOT_IS_APATCH; + break; + } + case Magisk: { + flags |= PROCESS_ROOT_IS_MAGISK; + break; } } @@ -609,6 +653,11 @@ void zygiskd_start(void) { case APatch: { flags |= PROCESS_ROOT_IS_APATCH; + break; + } + case Magisk: { + flags |= PROCESS_ROOT_IS_MAGISK; + break; } } @@ -673,31 +722,28 @@ void zygiskd_start(void) { size_t index = index_buf[0]; struct Module *module = &context.modules[index]; - int companion_fd = module->companion; - if (companion_fd != -1) { + if (module->companion != -1) { LOGI("Companion for module `%s` already exists\n", module->name); - if (!check_unix_socket(companion_fd, false)) { + if (!check_unix_socket(module->companion, false)) { LOGE("Poll companion for module `%s` crashed\n", module->name); - close(companion_fd); + close(module->companion); module->companion = -1; } } - if (companion_fd == -1) { + if (module->companion == -1) { LOGI("Spawning companion for `%s`\n", module->name); - companion_fd = spawn_companion(module->name, module->lib_fd); + module->companion = spawn_companion(module->name, module->lib_fd); - if (companion_fd != -1) { + if (module->companion != -1) { LOGI("Spawned companion for `%s`\n", module->name); - module->companion = companion_fd; - /* INFO: Reversed params, may fix issues */ - if (send_fd(companion_fd, client_fd) == -1) { + if (send_fd(module->companion, client_fd) == -1) { LOGE("Failed sending companion fd\n"); uint8_t response = 0; @@ -705,7 +751,7 @@ void zygiskd_start(void) { ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response)); } } else { - if (companion_fd == -2) { + if (module->companion == -2) { LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name); } else { LOGI("Could not spawn companion for `%s` due to failures.\n", module->name); @@ -716,7 +762,7 @@ void zygiskd_start(void) { ret = write(client_fd, &response, sizeof(response)); ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response)); - LOGI("Companion fd: %d\n", companion_fd); + LOGI("Companion fd: %d\n", module->companion); } break; @@ -753,11 +799,10 @@ void zygiskd_start(void) { break; } - - /* INFO: Maybe we don't need to close? */ - close(client_fd); } + close(client_fd); + continue; }