add: Magisk support; fix: (some) zygiskd code issues

This commit adds Magisk support to Zygiskd C99, and also fixes some code issues of it.
This commit is contained in:
ThePedroo
2024-08-20 19:16:12 -03:00
parent c1e45e9af6
commit a549f0e5ae
14 changed files with 520 additions and 126 deletions

View File

@@ -53,6 +53,7 @@ val Files = arrayOf(
"root_impl/apatch.c", "root_impl/apatch.c",
"root_impl/common.c", "root_impl/common.c",
"root_impl/kernelsu.c", "root_impl/kernelsu.c",
"root_impl/magisk.c",
"companion.c", "companion.c",
"dl.c", "dl.c",
"main.c", "main.c",

View File

@@ -30,7 +30,7 @@ zygisk_companion_entry_func load_module(int fd) {
return (zygisk_companion_entry_func)entry; return (zygisk_companion_entry_func)entry;
} }
void *call_entry(void *arg) { void *call_entry(void *restrict arg) {
int fd = *((int *)arg); int fd = *((int *)arg);
struct stat st0; struct stat st0;
@@ -92,7 +92,7 @@ void entry(int fd) {
if (entry == NULL) { if (entry == NULL) {
LOGI("No companion entry for: %s\n", name); LOGI("No companion entry for: %s\n", name);
uint8_t response[1] = { 0 }; uint8_t response = 0;
write(fd, &response, sizeof(response)); write(fd, &response, sizeof(response));
exit(0); exit(0);
@@ -102,7 +102,7 @@ void entry(int fd) {
LOGI("Companion process created for: %s\n", name); LOGI("Companion process created for: %s\n", name);
uint8_t response[1] = { 1 }; uint8_t response = 1;
write(fd, &response, sizeof(response)); write(fd, &response, sizeof(response));
while (1) { while (1) {
@@ -114,21 +114,17 @@ void entry(int fd) {
break; break;
} }
int client_fd; int *client_fd = malloc(sizeof(int));
recv_fd(fd, &client_fd); 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)); 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"); LOGI("Creating new thread for companion request\n");
pthread_t thread; 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); pthread_detach(thread);
} }
} }

View File

@@ -23,7 +23,7 @@ struct AndroidDlextinfo {
void *android_dlopen_ext(const char *filename, int flags, const struct AndroidDlextinfo *extinfo); 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); char *dir = dirname(path);
struct AndroidDlextinfo info = { struct AndroidDlextinfo info = {
.flags = 0, .flags = 0,

View File

@@ -1,6 +1,6 @@
#ifndef DL_H #ifndef DL_H
#define 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 */ #endif /* DL_H */

View File

@@ -11,7 +11,7 @@
#include "utils.h" #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[]) { int main(int argc, char *argv[]) {
LOGI("Initializing zygiskd: %s\n", argv[0]); LOGI("Initializing zygiskd: %s\n", argv[0]);
@@ -61,6 +61,11 @@ int main(int argc, char *argv[]) {
case APatch: { case APatch: {
LOGI("APatch root implementation found.\n"); LOGI("APatch root implementation found.\n");
return 0;
}
case Magisk: {
LOGI("Magisk root implementation found.\n");
return 0; return 0;
} }
} }

View File

@@ -12,7 +12,8 @@
enum RootImplState apatch_get_existence(void) { enum RootImplState apatch_get_existence(void) {
struct stat s; struct stat s;
if (stat("/data/adb/apd", &s) != 0) { 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; return Inexistent;
} }
@@ -20,18 +21,16 @@ enum RootImplState apatch_get_existence(void) {
char apatch_version[32]; char apatch_version[32];
char *const argv[] = { "apd", "-V", NULL }; 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)) { 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; errno = 0;
return Inexistent; return Inexistent;
} }
int version = atoi(apatch_version + strlen("apd ")); 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 >= MIN_APATCH_VERSION && version <= 999999) return Supported;
if (version >= 1 && version <= MIN_APATCH_VERSION - 1) return TooOld; if (version >= 1 && version <= MIN_APATCH_VERSION - 1) return TooOld;
@@ -49,38 +48,54 @@ struct packages_config {
size_t size; 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"); FILE *fp = fopen("/data/adb/ap/package_config", "r");
if (fp == NULL) { 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; return false;
} }
char line[256]; char line[1024];
/* INFO: Skip the CSV header */ /* INFO: Skip the CSV header */
fgets(line, sizeof(line), fp); fgets(line, sizeof(line), fp);
LOGI("meow meow: %s\n", line);
config->size = 0;
while (fgets(line, sizeof(line), fp) != NULL) { 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) { 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); fclose(fp);
return false; return false;
} }
LOGI("meow meow (1): %s\n", line);
strtok(line, ","); strtok(line, ",");
LOGI("meow meow (2)\n");
char *exclude_str = strtok(NULL, ","); char *exclude_str = strtok(NULL, ",");
if (exclude_str == NULL) continue; if (exclude_str == NULL) continue;
LOGI("meow meow: %s\n", exclude_str);
char *allow_str = strtok(NULL, ","); char *allow_str = strtok(NULL, ",");
if (allow_str == NULL) continue; if (allow_str == NULL) continue;
LOGI("meow meow: %s\n", allow_str);
char *uid_str = strtok(NULL, ","); 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].uid = atoi(uid_str);
config->configs[config->size].root_granted = strcmp(allow_str, "1") == 0; 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) { bool apatch_uid_is_manager(uid_t uid) {
struct stat s; 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; return s.st_uid == uid;
} }

View File

@@ -1,7 +1,11 @@
#include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include "../utils.h"
#include "kernelsu.h" #include "kernelsu.h"
#include "apatch.h" #include "apatch.h"
#include "magisk.h"
#include "common.h" #include "common.h"
@@ -10,7 +14,36 @@ static enum RootImpl ROOT_IMPL = None;
void root_impls_setup(void) { void root_impls_setup(void) {
if (ksu_get_existence() == Supported) ROOT_IMPL = KernelSU; if (ksu_get_existence() == Supported) ROOT_IMPL = KernelSU;
else if (apatch_get_existence() == Supported) ROOT_IMPL = APatch; else if (apatch_get_existence() == Supported) ROOT_IMPL = APatch;
else if (magisk_get_existence() == Supported) ROOT_IMPL = Magisk;
else ROOT_IMPL = None; 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) { enum RootImpl get_impl(void) {
@@ -18,43 +51,52 @@ enum RootImpl get_impl(void) {
} }
bool uid_granted_root(uid_t uid) { bool uid_granted_root(uid_t uid) {
// switch (get_impl()) { switch (get_impl()) {
// case KernelSU: { case KernelSU: {
return ksu_uid_granted_root(uid); return ksu_uid_granted_root(uid);
// } }
// case APatch: { case APatch: {
// return apatch_uid_granted_root(uid); return apatch_uid_granted_root(uid);
// } }
// default: { case Magisk: {
// return false; return magisk_uid_granted_root(uid);
// } }
// } default: {
return false;
}
}
} }
bool uid_should_umount(uid_t uid) { bool uid_should_umount(uid_t uid) {
// switch (get_impl()) { switch (get_impl()) {
// case KernelSU: { case KernelSU: {
return ksu_uid_should_umount(uid); return ksu_uid_should_umount(uid);
// } }
// case APatch: { case APatch: {
// return apatch_uid_should_umount(uid); return apatch_uid_should_umount(uid);
// } }
// default: { case Magisk: {
// return false; return magisk_uid_should_umount(uid);
// } }
// } default: {
return false;
}
}
} }
bool uid_is_manager(uid_t uid) { bool uid_is_manager(uid_t uid) {
// switch (get_impl()) { switch (get_impl()) {
// case KernelSU: { case KernelSU: {
return ksu_uid_is_manager(uid); return ksu_uid_is_manager(uid);
// } }
// case APatch: { case APatch: {
// return apatch_uid_is_manager(uid); return apatch_uid_is_manager(uid);
// } }
// default: { case Magisk: {
// return false; return magisk_uid_is_manager(uid);
// } }
// } default: {
return false;
}
}
} }

View File

@@ -7,7 +7,8 @@ enum RootImpl {
None, None,
Multiple, Multiple,
KernelSU, KernelSU,
APatch APatch,
Magisk
}; };
void root_impls_setup(void); void root_impls_setup(void);

View File

@@ -48,7 +48,12 @@ bool ksu_uid_should_umount(uid_t uid) {
bool ksu_uid_is_manager(uid_t uid) { bool ksu_uid_is_manager(uid_t uid) {
struct stat s; 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; return s.st_uid == uid;
} }

View File

@@ -0,0 +1,190 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <errno.h>
#include <unistd.h>
#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;
}
}

View File

@@ -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

View File

@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -43,31 +44,53 @@ bool switch_mount_namespace(pid_t pid) {
int __system_property_get(const char *, char *); 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); __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]; char path[PATH_MAX];
snprintf(path, PATH_MAX, "/proc/thread-self/attr/sockcreate"); snprintf(path, PATH_MAX, "/proc/thread-self/attr/sockcreate");
FILE *sockcreate = fopen(path, "w"); FILE *sockcreate = fopen(path, "w");
if (sockcreate == NULL) { 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)) { 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); 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]; char path[PATH_MAX];
snprintf(path, PATH_MAX, "/proc/self/attr/current"); snprintf(path, PATH_MAX, "/proc/self/attr/current");
@@ -78,8 +101,8 @@ static void get_current_attr(char *output) {
return; return;
} }
if (fgets(output, PATH_MAX, current) == NULL) { if (fread(output, 1, size, current) == 0) {
LOGE("fgets: %s\n", strerror(errno)); LOGE("fread: %s\n", strerror(errno));
return; return;
} }
@@ -87,9 +110,9 @@ static void get_current_attr(char *output) {
fclose(current); 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]; char current_attr[PATH_MAX];
get_current_attr(current_attr); get_current_attr(current_attr, sizeof(current_attr));
set_socket_create_context(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); close(socket_fd);
} }
int chcon(const char *path, const char *context) { int chcon(const char *restrict path, const char *context) {
char command[PATH_MAX]; char command[PATH_MAX];
snprintf(command, PATH_MAX, "chcon %s %s", context, path); snprintf(command, PATH_MAX, "chcon %s %s", context, path);
return system(command); return system(command);
} }
int unix_listener_from_path(char *path) { int unix_listener_from_path(char *restrict path) {
if (remove(path) == -1 && errno != ENOENT) { if (remove(path) == -1 && errno != ENOENT) {
LOGE("remove: %s\n", strerror(errno)); LOGE("remove: %s\n", strerror(errno));
@@ -143,10 +166,9 @@ int unix_listener_from_path(char *path) {
return -1; return -1;
} }
struct sockaddr_un addr; struct sockaddr_un addr = {
.sun_family = AF_UNIX
memset(&addr, 0, sizeof(struct sockaddr_un)); };
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -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; 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))]; char control_buf[CMSG_SPACE(sizeof(int))];
memset(control_buf, 0, sizeof(control_buf)); memset(control_buf, 0, sizeof(control_buf));
@@ -234,7 +256,7 @@ ssize_t recv_fd(int sockfd, int *fd) {
return received_bytes; 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); size_t len = strlen(str);
ssize_t written_bytes = write(fd, &len, sizeof(len)); 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; 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]; size_t str_len_buf[1];
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(str_len_buf)); 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; 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]; int link[2];
pid_t pid; pid_t pid;
@@ -308,10 +331,55 @@ bool exec_command(char *buf, size_t len, const char *file, char *const argv[]) {
close(link[1]); close(link[1]);
int nbytes = read(link[0], buf, len); int nbytes = read(link[0], buf, len);
buf[nbytes] = '\0'; buf[nbytes - 1] = '\0';
wait(NULL); wait(NULL);
} }
return true; 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;
}

View File

@@ -8,38 +8,40 @@
#define CONCAT_(x,y) x##y #define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y) #define CONCAT(x,y) CONCAT_(x,y)
#define LOGI(...) \ #define LOGI(...) \
__android_log_print(ANDROID_LOG_INFO, lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \ __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__)) FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__))
#define LOGE(...) \ #define LOGE(...) \
__android_log_print(ANDROID_LOG_INFO , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \ __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__)) 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); 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); int unix_listener_from_path(char *path);
ssize_t send_fd(int sockfd, int fd); 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); bool check_unix_socket(int fd, bool block);
int non_blocking_execv(const char *restrict file, char *const argv[]);
#endif /* UTILS_H */ #endif /* UTILS_H */

View File

@@ -12,6 +12,8 @@
#include <unistd.h> #include <unistd.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
#include <pthread.h> #include <pthread.h>
@@ -97,8 +99,10 @@ static enum Architecture get_arch(void) {
exit(1); exit(1);
} }
int create_library_fd(const char *so_path) { int create_library_fd(const char *restrict so_path) {
int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING); /* 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) { if (memfd == -1) {
LOGE("Failed creating memfd: %s\n", strerror(errno)); LOGE("Failed creating memfd: %s\n", strerror(errno));
@@ -155,9 +159,8 @@ int create_library_fd(const char *so_path) {
return memfd; return memfd;
} }
/* WARNING: Dynamic memory based */ /* 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->len = 0;
context->modules = malloc(1); context->modules = malloc(1);
@@ -213,11 +216,16 @@ static void load_modules(enum Architecture arch, struct Context *context) {
char disabled[PATH_MAX]; char disabled[PATH_MAX];
snprintf(disabled, PATH_MAX, "/data/adb/modules/%s/disable", name); snprintf(disabled, PATH_MAX, "/data/adb/modules/%s/disable", name);
if (stat(disabled, &st) != -1) { if (stat(disabled, &st) == -1) {
errno = 0; 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); LOGI("Loading module `%s`...\n", name);
int lib_fd = create_library_fd(so_path); 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++) { for (int i = 0; i < context->len; i++) {
free(context->modules[i].name); free(context->modules[i].name);
if (context->modules[i].companion != -1) close(context->modules[i].companion); 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); 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]; int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
LOGE("Failed creating socket pair.\n"); LOGE("Failed creating socket pair.\n");
@@ -324,7 +332,7 @@ static int spawn_companion(char *name, int lib_fd) {
} }
/* INFO: if pid == 0: */ /* INFO: if pid == 0: */
} else { } else {
LOGI("Companion started (%d)\n", pid); LOGI("Companion started\n");
/* INFO: There is no case where this will fail with a valid fd. */ /* INFO: There is no case where this will fail with a valid fd. */
fcntl(companion_fd, F_SETFD, 0); fcntl(companion_fd, F_SETFD, 0);
} }
@@ -334,19 +342,20 @@ static int spawn_companion(char *name, int lib_fd) {
LOGI("Executing companion...\n"); LOGI("Executing companion...\n");
char arg[sizeof(ZYGISKD_FILE) + sizeof(" companion ") + 32]; char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL };
snprintf(arg, sizeof(arg), "%s companion %d", ZYGISKD_FILE, companion_fd); if (non_blocking_execv(ZYGISKD_PATH, argv) == -1) {
if (system(arg) == -1) {
LOGE("Failed executing companion: %s\n", strerror(errno)); LOGE("Failed executing companion: %s\n", strerror(errno));
close(companion_fd);
exit(1); exit(1);
} }
LOGI("Bye bye!\n");
exit(0); exit(0);
} }
/* TODO: Is packed attribute really necessary? */
struct __attribute__((__packed__)) MsgHead { struct __attribute__((__packed__)) MsgHead {
unsigned int cmd; unsigned int cmd;
int length; int length;
@@ -354,7 +363,7 @@ struct __attribute__((__packed__)) MsgHead {
}; };
void zygiskd_start(void) { void zygiskd_start(void) {
LOGI("Welcome to ReZygisk %s!", ZKSU_VERSION); LOGI("Welcome to ReZygisk %s!\n", ZKSU_VERSION);
enum RootImpl impl = get_impl(); enum RootImpl impl = get_impl();
if (impl == None) { if (impl == None) {
@@ -388,8 +397,28 @@ void zygiskd_start(void) {
case None: { break; } case None: { break; }
case Multiple: { break; } case Multiple: { break; }
case KernelSU: case KernelSU:
case APatch: { case APatch:
size_t root_impl_len = strlen(impl == KernelSU ? "KernelSU" : "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) { if (context.len == 0) {
msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: None") + root_impl_len + 1); msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: None") + root_impl_len + 1);
@@ -407,6 +436,11 @@ void zygiskd_start(void) {
case APatch: { case APatch: {
memcpy(msg->data, "Root: APatch, Modules: None", strlen("Root: APatch, Modules: None")); 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; break;
} }
} }
@@ -447,6 +481,11 @@ void zygiskd_start(void) {
case APatch: { case APatch: {
memcpy(msg->data, "Root: APatch, Modules: ", strlen("Root: APatch, Modules: ")); memcpy(msg->data, "Root: APatch, Modules: ", strlen("Root: APatch, Modules: "));
break;
}
case Magisk: {
memcpy(msg->data, "Root: Magisk, Modules: ", strlen("Root: Magisk, Modules: "));
break; break;
} }
} }
@@ -582,6 +621,11 @@ void zygiskd_start(void) {
case APatch: { case APatch: {
flags |= PROCESS_ROOT_IS_APATCH; flags |= PROCESS_ROOT_IS_APATCH;
break;
}
case Magisk: {
flags |= PROCESS_ROOT_IS_MAGISK;
break; break;
} }
} }
@@ -609,6 +653,11 @@ void zygiskd_start(void) {
case APatch: { case APatch: {
flags |= PROCESS_ROOT_IS_APATCH; flags |= PROCESS_ROOT_IS_APATCH;
break;
}
case Magisk: {
flags |= PROCESS_ROOT_IS_MAGISK;
break; break;
} }
} }
@@ -673,31 +722,28 @@ void zygiskd_start(void) {
size_t index = index_buf[0]; size_t index = index_buf[0];
struct Module *module = &context.modules[index]; 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); 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); LOGE("Poll companion for module `%s` crashed\n", module->name);
close(companion_fd); close(module->companion);
module->companion = -1; module->companion = -1;
} }
} }
if (companion_fd == -1) { if (module->companion == -1) {
LOGI("Spawning companion for `%s`\n", module->name); 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); LOGI("Spawned companion for `%s`\n", module->name);
module->companion = companion_fd;
/* INFO: Reversed params, may fix issues */ /* 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"); LOGE("Failed sending companion fd\n");
uint8_t response = 0; uint8_t response = 0;
@@ -705,7 +751,7 @@ void zygiskd_start(void) {
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response)); ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response));
} }
} else { } else {
if (companion_fd == -2) { if (module->companion == -2) {
LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name); LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name);
} else { } else {
LOGI("Could not spawn companion for `%s` due to failures.\n", module->name); 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)); ret = write(client_fd, &response, sizeof(response));
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, 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; break;
@@ -753,11 +799,10 @@ void zygiskd_start(void) {
break; break;
} }
/* INFO: Maybe we don't need to close? */
close(client_fd);
} }
close(client_fd);
continue; continue;
} }