add: zygiskd C99 APatch support

This commit adds support for zygiskd C99 to recognize APatch rooted devices.
This commit is contained in:
ThePedroo
2024-08-15 22:42:47 -03:00
parent 19d2a1758e
commit c1e45e9af6
13 changed files with 484 additions and 210 deletions

View File

@@ -14,7 +14,8 @@ fun getLatestNDKPath(): String {
throw Exception("NDK not found at $ndkPath") throw Exception("NDK not found at $ndkPath")
} }
val ndkVersion = ndkDir.toFile().listFiles().filter { it.isDirectory }.map { it.name }.sorted().last() // get 2nd latest version
val ndkVersion = ndkDir.toFile().listFiles().filter { it.isDirectory }.map { it.name }.sorted().reversed().getOrNull(1)
return ndkPath + "/" + ndkVersion return ndkPath + "/" + ndkVersion
} }
@@ -26,6 +27,14 @@ val verCode: Int by rootProject.extra
val verName: String by rootProject.extra val verName: String by rootProject.extra
val commitHash: String by rootProject.extra val commitHash: String by rootProject.extra
val CStandardFlags = arrayOf(
"-DMIN_APATCH_VERSION=$minAPatchVersion",
"-DMIN_KSU_VERSION=$minKsuVersion",
"-DMAX_KSU_VERSION=$maxKsuVersion",
"-DMIN_MAGISK_VERSION=$minMagiskVersion",
"-DZKSU_VERSION=\"$verName\""
)
val CFlagsRelease = arrayOf( val CFlagsRelease = arrayOf(
"-D_GNU_SOURCE", "-std=c99", "-Wpedantic", "-Wall", "-Wextra", "-Werror", "-D_GNU_SOURCE", "-std=c99", "-Wpedantic", "-Wall", "-Wextra", "-Werror",
"-Wformat", "-Wuninitialized", "-Wshadow", "-Wno-zero-length-array", "-Wformat", "-Wuninitialized", "-Wshadow", "-Wno-zero-length-array",
@@ -41,6 +50,7 @@ val CFlagsDebug = arrayOf(
) )
val Files = arrayOf( val Files = arrayOf(
"root_impl/apatch.c",
"root_impl/common.c", "root_impl/common.c",
"root_impl/kernelsu.c", "root_impl/kernelsu.c",
"companion.c", "companion.c",
@@ -94,7 +104,7 @@ task("buildAndStrip") {
x86OutputDir.mkdirs() x86OutputDir.mkdirs()
x86_64OutputDir.mkdirs() x86_64OutputDir.mkdirs()
val compileArgs = if (isDebug) CFlagsDebug else CFlagsRelease val compileArgs = (if (isDebug) CFlagsDebug else CFlagsRelease) + CStandardFlags
exec { exec {
commandLine(aarch64Compiler, "-o", Paths.get(aarch64OutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files) commandLine(aarch64Compiler, "-o", Paths.get(aarch64OutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files)

View File

@@ -17,9 +17,9 @@
#include "dl.h" #include "dl.h"
#include "utils.h" #include "utils.h"
typedef void (*ZygiskCompanionEntryFn)(int); typedef void (*zygisk_companion_entry_func)(int);
ZygiskCompanionEntryFn load_module(int fd) { zygisk_companion_entry_func load_module(int fd) {
char path[PATH_MAX]; char path[PATH_MAX];
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
@@ -27,10 +27,10 @@ ZygiskCompanionEntryFn load_module(int fd) {
void *entry = dlsym(handle, "zygisk_companion_entry"); void *entry = dlsym(handle, "zygisk_companion_entry");
if (entry == NULL) return NULL; if (entry == NULL) return NULL;
return (ZygiskCompanionEntryFn)entry; return (zygisk_companion_entry_func)entry;
} }
void *ExecuteNew(void *arg) { void *call_entry(void *arg) {
int fd = *((int *)arg); int fd = *((int *)arg);
struct stat st0; struct stat st0;
@@ -65,13 +65,10 @@ void *ExecuteNew(void *arg) {
return NULL; return NULL;
} }
void entry(int fd) { void entry(int fd) {
LOGI("companion entry fd: |%d|\n", fd); LOGI("companion entry fd: |%d|\n", fd);
char name[256 + 1]; char name[256 + 1];
/* INFO: Getting stuck here */
ssize_t ret = read_string(fd, name, sizeof(name) - 1); ssize_t ret = read_string(fd, name, sizeof(name) - 1);
if (ret == -1) return; if (ret == -1) return;
@@ -84,7 +81,7 @@ void entry(int fd) {
LOGI("Library fd: %d\n", library_fd); LOGI("Library fd: %d\n", library_fd);
ZygiskCompanionEntryFn entry = load_module(library_fd); zygisk_companion_entry_func entry = load_module(library_fd);
LOGI("Library loaded\n"); LOGI("Library loaded\n");
@@ -95,17 +92,28 @@ 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);
write(fd, (void *)0, 1); uint8_t response[1] = { 0 };
write(fd, &response, sizeof(response));
exit(0);
return; return;
} }
LOGI("Companion process created for: %s\n", name); LOGI("Companion process created for: %s\n", name);
uint8_t response = 1; uint8_t response[1] = { 1 };
write(fd, &response, sizeof(response)); write(fd, &response, sizeof(response));
while (1) { while (1) {
if (!check_unix_socket(fd, true)) {
LOGI("Something went wrong. Bye!\n");
exit(0);
break;
}
int client_fd; int client_fd;
recv_fd(fd, &client_fd); recv_fd(fd, &client_fd);
@@ -113,13 +121,14 @@ void entry(int 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)); int *client_fd_ptr = malloc(sizeof(int));
*client_fd_ptr = client_fd; *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, ExecuteNew, (void *)client_fd_ptr); pthread_create(&thread, NULL, call_entry, (void *)client_fd_ptr);
pthread_detach(thread); pthread_detach(thread);
} }
} }

View File

@@ -7,20 +7,6 @@
#define true 1 #define true 1
#define false 0 #define false 0
// #define MIN_APATCH_VERSION (atoi(getenv("MIN_APATCH_VERSION")))
// #define MIN_KSU_VERSION (atoi(getenv("MIN_KSU_VERSION")))
// #define MAX_KSU_VERSION (atoi(getenv("MAX_KSU_VERSION")))
// #define MIN_MAGISK_VERSION (atoi(getenv("MIN_MAGISK_VERSION")))
// #define ZKSU_VERSION (getenv("ZKSU_VERSION"))
#define MIN_APATCH_VERSION 0
// val minKsudVersion by extra(11425)
// val maxKsuVersion by extra(20000)
#define MIN_KSU_VERSION 11425
#define MAX_KSU_VERSION 20000
#define MIN_MAGISK_VERSION 0
#define ZKSU_VERSION "1.0.0"
#if DEBUG == false #if DEBUG == false
#define MAX_LOG_LEVEL ANDROID_LOG_VERBOSE #define MAX_LOG_LEVEL ANDROID_LOG_VERBOSE
#else #else
@@ -64,6 +50,7 @@ enum ProcessFlags: uint32_t {
enum RootImplState { enum RootImplState {
Supported, Supported,
TooOld, TooOld,
Inexistent,
Abnormal Abnormal
}; };

View File

@@ -14,14 +14,7 @@
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[]) {
errno = 0; LOGI("Initializing zygiskd: %s\n", argv[0]);
/* Initialize android logger */
LOGI("Initializing zygiskd\n");
LOGI("Argc: %d\n", argc);
for (int i = 0; i < argc; i++) {
LOGI("argv[%d] = %s\n", i, argv[i]);
}
if (argc > 1) { if (argc > 1) {
if (strcmp(argv[1], "companion") == 0) { if (strcmp(argv[1], "companion") == 0) {
@@ -65,8 +58,12 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
} case APatch: {
LOGI("APatch root implementation found.\n");
return 0;
}
}
return 0; return 0;
} }

View File

@@ -0,0 +1,144 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "../constants.h"
#include "../utils.h"
#include "apatch.h"
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));
return Inexistent;
}
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));
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 >= MIN_APATCH_VERSION && version <= 999999) return Supported;
if (version >= 1 && version <= MIN_APATCH_VERSION - 1) return TooOld;
return Inexistent;
}
struct package_config {
uid_t uid;
bool root_granted;
bool umount_needed;
};
struct packages_config {
struct package_config *configs;
size_t size;
};
bool _apatch_get_package_config(struct packages_config *config) {
FILE *fp = fopen("/data/adb/ap/package_config", "r");
if (fp == NULL) {
LOGE("APATCH | Failed to open package_config: %s\n", strerror(errno));
return false;
}
char line[256];
/* INFO: Skip the CSV header */
fgets(line, sizeof(line), fp);
while (fgets(line, sizeof(line), fp) != NULL) {
config->configs = realloc(config, (config->size + 1) * sizeof(struct package_config));
if (config->configs == NULL) {
LOGE("APATCH | Failed to realloc package config: %s\n", strerror(errno));
fclose(fp);
return false;
}
strtok(line, ",");
char *exclude_str = strtok(NULL, ",");
if (exclude_str == NULL) continue;
char *allow_str = strtok(NULL, ",");
if (allow_str == NULL) continue;
char *uid_str = strtok(NULL, ",");
if (uid_str == NULL) continue;
config->configs[config->size].uid = atoi(uid_str);
config->configs[config->size].root_granted = strcmp(allow_str, "1") == 0;
config->configs[config->size].umount_needed = strcmp(exclude_str, "1") == 0;
config->size++;
}
fclose(fp);
return true;
}
bool apatch_uid_granted_root(uid_t uid) {
struct packages_config *config = NULL;
if (!_apatch_get_package_config(config)) {
free(config);
return false;
}
for (size_t i = 0; i < config->size; i++) {
if (config->configs[i].uid == uid) {
free(config);
return config->configs[i].root_granted;
}
}
free(config);
return false;
}
bool apatch_uid_should_umount(uid_t uid) {
struct packages_config *config = NULL;
if (!_apatch_get_package_config(config)) {
free(config);
return false;
}
for (size_t i = 0; i < config->size; i++) {
if (config->configs[i].uid == uid) {
free(config);
return config->configs[i].umount_needed;
}
}
free(config);
return false;
}
bool apatch_uid_is_manager(uid_t uid) {
struct stat s;
if (stat("/data/user_de/0/me.bmax.apatch", &s) == -1) return false;
return s.st_uid == uid;
}

View File

@@ -0,0 +1,14 @@
#ifndef APATCH_H
#define APATCH_H
#include "../constants.h"
enum RootImplState apatch_get_existence(void);
bool apatch_uid_granted_root(uid_t uid);
bool apatch_uid_should_umount(uid_t uid);
bool apatch_uid_is_manager(uid_t uid);
#endif

View File

@@ -1,19 +1,16 @@
#include <sys/types.h> #include <sys/types.h>
#include "kernelsu.h" #include "kernelsu.h"
#include "apatch.h"
#include "common.h" #include "common.h"
static enum RootImpl ROOT_IMPL = None; static enum RootImpl ROOT_IMPL = None;
void root_impls_setup(void) { void root_impls_setup(void) {
enum RootImplState ksu_version = ksu_get_kernel_su(); if (ksu_get_existence() == Supported) ROOT_IMPL = KernelSU;
else if (apatch_get_existence() == Supported) ROOT_IMPL = APatch;
enum RootImpl impl = None; else ROOT_IMPL = None;
if (ksu_version == Supported) impl = KernelSU;
ROOT_IMPL = impl;
} }
enum RootImpl get_impl(void) { enum RootImpl get_impl(void) {
@@ -21,34 +18,43 @@ 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);
} // }
default: { // case APatch: {
return false; // return apatch_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);
} // }
default: { // case APatch: {
return false; // return apatch_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);
} // }
default: { // case APatch: {
return false; // return apatch_uid_is_manager(uid);
} // }
} // default: {
// return false;
// }
// }
} }

View File

@@ -5,8 +5,9 @@
enum RootImpl { enum RootImpl {
None, None,
Multiple, /* INFO: I know. */ Multiple,
KernelSU KernelSU,
APatch
}; };
void root_impls_setup(void); void root_impls_setup(void);

View File

@@ -1,4 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <errno.h> #include <errno.h>
@@ -14,16 +15,12 @@
#define CMD_UID_GRANTED_ROOT 12 #define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13 #define CMD_UID_SHOULD_UMOUNT 13
enum RootImplState ksu_get_kernel_su(void) { enum RootImplState ksu_get_existence(void) {
int version = 0; int version = 0;
prctl(KERNEL_SU_OPTION, CMD_GET_VERSION, &version, 0, 0); prctl(KERNEL_SU_OPTION, CMD_GET_VERSION, &version, 0, 0);
errno = 0; if (version == 0) return Inexistent;
if (version == 0) return Abnormal;
if (version >= MIN_KSU_VERSION && version <= MAX_KSU_VERSION) return Supported; if (version >= MIN_KSU_VERSION && version <= MAX_KSU_VERSION) return Supported;
if (version >= 1 && version <= MIN_KSU_VERSION - 1) return TooOld; if (version >= 1 && version <= MIN_KSU_VERSION - 1) return TooOld;
return Abnormal; return Abnormal;
@@ -34,8 +31,6 @@ bool ksu_uid_granted_root(uid_t uid) {
bool granted = false; bool granted = false;
prctl(KERNEL_SU_OPTION, CMD_UID_GRANTED_ROOT, uid, &granted, &result); prctl(KERNEL_SU_OPTION, CMD_UID_GRANTED_ROOT, uid, &granted, &result);
LOGI("ksu_uid_granted_root: %d", granted);
if (result != KERNEL_SU_OPTION) return false; if (result != KERNEL_SU_OPTION) return false;
return granted; return granted;
@@ -46,23 +41,14 @@ bool ksu_uid_should_umount(uid_t uid) {
bool umount = false; bool umount = false;
prctl(KERNEL_SU_OPTION, CMD_UID_SHOULD_UMOUNT, uid, &umount, &result); prctl(KERNEL_SU_OPTION, CMD_UID_SHOULD_UMOUNT, uid, &umount, &result);
LOGI("ksu_uid_should_umount: %d", umount);
if (result != KERNEL_SU_OPTION) return false; if (result != KERNEL_SU_OPTION) return false;
return umount; return umount;
} }
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) == 0) { if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == -1) return false;
LOGI("ksu_uid_is_manager: %d", uid);
return s.st_uid == uid; return s.st_uid == uid;
}
LOGI("ksu_uid_is_manager: false");
return false;
} }

View File

@@ -3,7 +3,7 @@
#include "../constants.h" #include "../constants.h"
enum RootImplState ksu_get_kernel_su(void); enum RootImplState ksu_get_existence(void);
bool ksu_uid_granted_root(uid_t uid); bool ksu_uid_granted_root(uid_t uid);

View File

@@ -4,6 +4,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h> #include <sys/un.h>
#include <errno.h> #include <errno.h>
@@ -280,3 +281,37 @@ 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[]) {
int link[2];
pid_t pid;
if (pipe(link) == -1) {
LOGE("pipe: %s\n", strerror(errno));
return false;
}
if ((pid = fork()) == -1) {
LOGE("fork: %s\n", strerror(errno));
return false;
}
if (pid == 0) {
dup2(link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execv(file, argv);
} else {
close(link[1]);
int nbytes = read(link[0], buf, len);
buf[nbytes] = '\0';
wait(NULL);
}
return true;
}

View File

@@ -5,13 +5,18 @@
#include "constants.h" #include "constants.h"
#define CONCAT_(x,y) 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__))
#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__))
bool switch_mount_namespace(pid_t pid); bool switch_mount_namespace(pid_t pid);
@@ -33,4 +38,8 @@ ssize_t write_string(int fd, const char *str);
ssize_t read_string(int fd, char *str, size_t len); ssize_t read_string(int fd, char *str, size_t len);
bool exec_command(char *buf, size_t len, const char *file, char *const argv[]);
bool check_unix_socket(int fd, bool block);
#endif /* UTILS_H */ #endif /* UTILS_H */

View File

@@ -41,7 +41,7 @@ enum Architecture {
#define TMP_PATH "/data/adb/rezygisk" #define TMP_PATH "/data/adb/rezygisk"
#define CONTROLLER_SOCKET TMP_PATH "/init_monitor" #define CONTROLLER_SOCKET TMP_PATH "/init_monitor"
#define PATH_CP_NAME TMP_PATH "/" lp_select("cp32.sock", "cp64.sock") #define PATH_CP_NAME TMP_PATH "/" lp_select("cp32.sock", "cp64.sock")
#define ZYGISKD_FILE "zygiskd" lp_select("32", "64") #define ZYGISKD_FILE PATH_MODULES_DIR "/zygisksu/bin/zygiskd" lp_select("32", "64")
#define ZYGISKD_PATH "/data/adb/modules/zygisksu/bin/zygiskd" lp_select("32", "64") #define ZYGISKD_PATH "/data/adb/modules/zygisksu/bin/zygiskd" lp_select("32", "64")
#define ASSURE_SIZE_WRITE(area_name, subarea_name, sent_size, expected_size) \ #define ASSURE_SIZE_WRITE(area_name, subarea_name, sent_size, expected_size) \
@@ -100,30 +100,42 @@ static enum Architecture get_arch(void) {
int create_library_fd(const char *so_path) { int create_library_fd(const char *so_path) {
int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING); int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING);
if (memfd == -1) { if (memfd == -1) {
perror("memfd_create"); LOGE("Failed creating memfd: %s\n", strerror(errno));
return -1; return -1;
} }
int so_fd = open(so_path, O_RDONLY); int so_fd = open(so_path, O_RDONLY);
if (so_fd == -1) { if (so_fd == -1) {
perror("open"); LOGE("Failed opening so file: %s\n", strerror(errno));
close(memfd); close(memfd);
return -1; return -1;
} }
struct stat st; off_t so_size = lseek(so_fd, 0, SEEK_END);
if (fstat(so_fd, &st) == -1) { if (so_size == -1) {
perror("fstat"); LOGE("Failed getting so file size: %s\n", strerror(errno));
close(so_fd); close(so_fd);
close(memfd); close(memfd);
return -1; return -1;
} }
if (sendfile(memfd, so_fd, NULL, st.st_size) == -1) { if (lseek(so_fd, 0, SEEK_SET) == -1) {
perror("sendfile"); LOGE("Failed seeking so file: %s\n", strerror(errno));
close(so_fd);
close(memfd);
return -1;
}
if (sendfile(memfd, so_fd, NULL, so_size) == -1) {
LOGE("Failed copying so file to memfd: %s\n", strerror(errno));
close(so_fd); close(so_fd);
close(memfd); close(memfd);
@@ -133,7 +145,8 @@ int create_library_fd(const char *so_path) {
close(so_fd); close(so_fd);
if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1) { if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1) {
perror("fcntl"); LOGE("Failed sealing memfd: %s\n", strerror(errno));
close(memfd); close(memfd);
return -1; return -1;
@@ -266,14 +279,21 @@ static int spawn_companion(char *name, int lib_fd) {
LOGI("Waiting for companion to start (%d)\n", pid); LOGI("Waiting for companion to start (%d)\n", pid);
int status = 0; int status = 0;
// waitpid(pid, &status, 0); waitpid(pid, &status, 0);
LOGI("Companion exited with status %d\n", status); LOGI("Companion exited with status %d\n", status);
// if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
if (write_string(daemon_fd, name) == -1) return -1; if (write_string(daemon_fd, name) == -1) {
LOGE("Failed sending module name\n");
if (send_fd(daemon_fd, lib_fd) == -1) return -1; return -1;
}
if (send_fd(daemon_fd, lib_fd) == -1) {
LOGE("Failed sending lib fd\n");
return -1;
}
LOGI("Sent module name and lib fd\n"); LOGI("Sent module name and lib fd\n");
@@ -281,20 +301,27 @@ static int spawn_companion(char *name, int lib_fd) {
ssize_t ret = read(daemon_fd, &response_buf, sizeof(response_buf)); ssize_t ret = read(daemon_fd, &response_buf, sizeof(response_buf));
ASSURE_SIZE_READ_WR("companion", "response", ret, sizeof(response_buf)); ASSURE_SIZE_READ_WR("companion", "response", ret, sizeof(response_buf));
uint8_t response = response_buf[0]; LOGI("Companion response: %hhu\n", response_buf[0]);
LOGI("Companion response: %hhu\n", response); if (response_buf[0] == 0) {
close(daemon_fd);
if (response == 0) return -2; return -1;
else if (response == 1) return daemon_fd; } else if (response_buf[0] == 1) return daemon_fd;
else return -2; else {
// } else { LOGE("Invalid response from companion: %hhu\n", response_buf[0]);
// LOGE("Exited with status %d\n", status);
// close(daemon_fd); close(daemon_fd);
// return -1; return -1;
// } }
} else {
LOGE("Exited with status %d\n", status);
close(daemon_fd);
return -1;
}
/* INFO: if pid == 0: */ /* INFO: if pid == 0: */
} else { } else {
LOGI("Companion started (%d)\n", pid); LOGI("Companion started (%d)\n", pid);
@@ -307,11 +334,11 @@ static int spawn_companion(char *name, int lib_fd) {
LOGI("Executing companion...\n"); LOGI("Executing companion...\n");
char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL }; char arg[sizeof(ZYGISKD_FILE) + sizeof(" companion ") + 32];
if (execv(ZYGISKD_PATH, argv) == -1) { snprintf(arg, sizeof(arg), "%s companion %d", ZYGISKD_FILE, companion_fd);
LOGE("Failed executing companion: %s\n", strerror(errno));
close(companion_fd); if (system(arg) == -1) {
LOGE("Failed executing companion: %s\n", strerror(errno));
exit(1); exit(1);
} }
@@ -329,34 +356,60 @@ struct __attribute__((__packed__)) MsgHead {
void zygiskd_start(void) { void zygiskd_start(void) {
LOGI("Welcome to ReZygisk %s!", ZKSU_VERSION); LOGI("Welcome to ReZygisk %s!", ZKSU_VERSION);
enum RootImpl impl = get_impl();
if (impl == None) {
struct MsgHead *msg = malloc(sizeof(struct MsgHead) + sizeof("No root implementation found."));
msg->cmd = DAEMON_SET_ERROR_INFO;
msg->length = sizeof("No root implementation found.");
memcpy(msg->data, "No root implementation found.", msg->length);
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead) + msg->length);
free(msg);
} else if (impl == Multiple) {
struct MsgHead *msg = malloc(sizeof(struct MsgHead) + sizeof("Multiple root implementations found. Not supported yet."));
msg->cmd = DAEMON_SET_ERROR_INFO;
msg->length = sizeof("Multiple root implementations found. Not supported yet.");
memcpy(msg->data, "Multiple root implementations found. Not supported yet.", msg->length);
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead) + msg->length);
free(msg);
}
enum Architecture arch = get_arch(); enum Architecture arch = get_arch();
struct Context context; struct Context context;
load_modules(arch, &context); load_modules(arch, &context);
struct MsgHead *msg = NULL; struct MsgHead *msg = NULL;
size_t msg_sz = 0;
switch (get_impl()) { switch (impl) {
case None: { case None: { break; }
/* INFO: Stop, compiler. */ case Multiple: { break; }
case KernelSU:
case APatch: {
size_t root_impl_len = strlen(impl == KernelSU ? "KernelSU" : "APatch");
break;
}
case Multiple: {
/* INFO: Stop, compiler. */
break;
}
case KernelSU: {
if (context.len == 0) { if (context.len == 0) {
msg_sz = sizeof(struct MsgHead) + strlen("Root: KernelSU, Modules: None") + 1; msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: None") + root_impl_len + 1);
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_INFO; msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: KernelSU, Modules: None") + 1; msg->length = strlen("Root: , Modules: None") + root_impl_len + 1;
memcpy(msg->data, "Root: KernelSU, Modules: None", strlen("Root: KernelSU, Modules: None"));
switch (impl) {
case None: { break; }
case Multiple: { break; }
case KernelSU: {
memcpy(msg->data, "Root: KernelSU, Modules: None", strlen("Root: KernelSU, Modules: None"));
break;
}
case APatch: {
memcpy(msg->data, "Root: APatch, Modules: None", strlen("Root: APatch, Modules: None"));
break;
}
}
} else { } else {
char *module_list = malloc(1); char *module_list = malloc(1);
size_t module_list_len = 0; size_t module_list_len = 0;
@@ -379,32 +432,34 @@ void zygiskd_start(void) {
} }
} }
msg_sz = sizeof(struct MsgHead) + strlen("Root: KernelSU, Modules: ") + module_list_len + 1; msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: ") + root_impl_len + module_list_len + 1);
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_INFO; msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: KernelSU, Modules: ") + module_list_len + 1; msg->length = strlen("Root: , Modules: ") + root_impl_len + module_list_len + 1;
memcpy(msg->data, "Root: KernelSU, Modules: ", strlen("Root: KernelSU, Modules: "));
memcpy(msg->data + strlen("Root: KernelSU, Modules: "), module_list, module_list_len); switch (impl) {
case None: { break; }
case Multiple: { break; }
case KernelSU: {
memcpy(msg->data, "Root: KernelSU, Modules: ", strlen("Root: KernelSU, Modules: "));
break;
}
case APatch: {
memcpy(msg->data, "Root: APatch, Modules: ", strlen("Root: APatch, Modules: "));
break;
}
}
memcpy(msg->data + strlen("Root: , Modules: ") + root_impl_len, module_list, module_list_len);
free(module_list); free(module_list);
} }
break;
}
default: {
msg_sz = sizeof(struct MsgHead) + strlen("Invalid root implementation") + 1;
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_ERROR_INFO;
msg->length = strlen("Invalid root implementation") + 1;
memcpy(msg->data, "Invalid root implementation", strlen("Invalid root implementation"));
break; break;
} }
} }
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, msg_sz); unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, sizeof(struct MsgHead) + msg->length);
free(msg); free(msg);
@@ -425,7 +480,7 @@ void zygiskd_start(void) {
LOGI("Accepted client: %d\n", client_fd); LOGI("Accepted client: %d\n", client_fd);
unsigned char buf[1]; uint8_t buf[1];
ssize_t len = read(client_fd, buf, sizeof(buf)); ssize_t len = read(client_fd, buf, sizeof(buf));
if (len == -1) { if (len == -1) {
LOGE("read: %s\n", strerror(errno)); LOGE("read: %s\n", strerror(errno));
@@ -437,7 +492,7 @@ void zygiskd_start(void) {
return; return;
} }
LOGI("Action: %hhu\n", (uint8_t)buf[0]); LOGI("Action: %hhu\n", buf[0]);
enum DaemonSocketAction action = (enum DaemonSocketAction)buf[0]; enum DaemonSocketAction action = (enum DaemonSocketAction)buf[0];
switch (action) { switch (action) {
@@ -448,8 +503,6 @@ void zygiskd_start(void) {
break; break;
} }
case ZygoteRestart: { case ZygoteRestart: {
LOGI("Zygote restart\n");
for (int i = 0; i < context.len; i++) { for (int i = 0; i < context.len; i++) {
if (context.modules[i].companion != -1) { if (context.modules[i].companion != -1) {
close(context.modules[i].companion); close(context.modules[i].companion);
@@ -465,22 +518,31 @@ void zygiskd_start(void) {
break; break;
} }
/* TODO: May need to move to another thread? :/ */
case RequestLogcatFd: { case RequestLogcatFd: {
char level_buf[1]; uint8_t level_buf[1];
ssize_t ret = read(client_fd, &level_buf, sizeof(level_buf)); ssize_t ret = read(client_fd, &level_buf, sizeof(level_buf));
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level_buf)); ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level_buf));
char level = level_buf[0]; uint8_t level = level_buf[0];
char tag[128 + 1]; char tag[128 + 1];
ret = read_string(client_fd, tag, sizeof(tag) - 1); ret = read_string(client_fd, tag, sizeof(tag) - 1);
if (ret == -1) break; if (ret == -1) {
LOGE("Failed reading tag\n");
break;
}
tag[ret] = '\0'; tag[ret] = '\0';
char message[1024]; char message[1024];
ret = read_string(client_fd, message, sizeof(message)); ret = read_string(client_fd, message, sizeof(message));
if (ret == -1) break; if (ret == -1) {
LOGE("Failed reading message\n");
break;
}
__android_log_print(level, tag, "%.*s", (int)ret, message); __android_log_print(level, tag, "%.*s", (int)ret, message);
@@ -489,13 +551,11 @@ void zygiskd_start(void) {
case GetProcessFlags: { case GetProcessFlags: {
LOGI("Getting process flags\n"); LOGI("Getting process flags\n");
uid_t uid_buf[1]; uint32_t uid_buf[1];
ssize_t ret = read(client_fd, &uid_buf, sizeof(uid_buf)); ssize_t ret = read(client_fd, &uid_buf, sizeof(uid_buf));
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid_buf)); ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid_buf));
uid_t uid = uid_buf[0]; uint32_t uid = uid_buf[0];
LOGI("Checking flags for uid: %d\n", uid);
uint32_t flags = 0; uint32_t flags = 0;
if (uid_is_manager(uid)) { if (uid_is_manager(uid)) {
@@ -512,23 +572,22 @@ void zygiskd_start(void) {
LOGI("Flags for uid %d: %d\n", uid, flags); LOGI("Flags for uid %d: %d\n", uid, flags);
switch (get_impl()) { switch (get_impl()) {
case None: { case None: { break; }
break; case Multiple: { break; }
}
case Multiple: {
break;
}
case KernelSU: { case KernelSU: {
flags |= PROCESS_ROOT_IS_KSU; flags |= PROCESS_ROOT_IS_KSU;
break;
}
case APatch: {
flags |= PROCESS_ROOT_IS_APATCH;
break;
} }
} }
// LOGI("Flags for uid %d: %d\n", uid, flags);
LOGI("Sending flags\n");
ret = write(client_fd, &flags, sizeof(flags)); ret = write(client_fd, &flags, sizeof(flags));
// ASSURE_SIZE_WRITE_BREAK("GetProcessFlags", "flags", ret, sizeof(flags)); ASSURE_SIZE_WRITE_BREAK("GetProcessFlags", "flags", ret, sizeof(flags));
LOGI("Sent flags\n"); LOGI("Sent flags\n");
@@ -540,14 +599,17 @@ void zygiskd_start(void) {
LOGI("Getting info\n"); LOGI("Getting info\n");
switch (get_impl()) { switch (get_impl()) {
case None: { case None: { break; }
break; case Multiple: { break; }
}
case Multiple: {
break;
}
case KernelSU: { case KernelSU: {
flags |= PROCESS_ROOT_IS_KSU; flags |= PROCESS_ROOT_IS_KSU;
break;
}
case APatch: {
flags |= PROCESS_ROOT_IS_APATCH;
break;
} }
} }
@@ -556,7 +618,7 @@ void zygiskd_start(void) {
ssize_t ret = write(client_fd, &flags, sizeof(flags)); ssize_t ret = write(client_fd, &flags, sizeof(flags));
ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags)); ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags));
pid_t pid = getpid(); uint32_t pid = getpid();
LOGI("Getting pid: %d\n", pid); LOGI("Getting pid: %d\n", pid);
@@ -565,6 +627,13 @@ void zygiskd_start(void) {
LOGI("Sent pid\n"); LOGI("Sent pid\n");
size_t modules_len = context.len;
ret = write(client_fd, &modules_len, sizeof(modules_len));
for (size_t i = 0; i < modules_len; i++) {
write_string(client_fd, context.modules[i].name);
}
break; break;
} }
case ReadModules: { case ReadModules: {
@@ -574,23 +643,20 @@ void zygiskd_start(void) {
ssize_t ret = write(client_fd, &clen, sizeof(clen)); ssize_t ret = write(client_fd, &clen, sizeof(clen));
ASSURE_SIZE_WRITE_BREAK("ReadModules", "len", ret, sizeof(clen)); ASSURE_SIZE_WRITE_BREAK("ReadModules", "len", ret, sizeof(clen));
for (int i = 0; i < (int)clen; i++) { for (size_t i = 0; i < clen; i++) {
LOGI("Hey, we're talking about: %d\n", i); LOGI("Hey, we're talking about: %zu, with name and lib_fd: %s, %d\n", i, context.modules[i].name, context.modules[i].lib_fd);
LOGI("Writing module `%s` to stream\n", context.modules[i].name);
LOGI("Lib fd: %d\n", context.modules[i].lib_fd);
size_t name_len = strlen(context.modules[i].name); if (write_string(client_fd, context.modules[i].name) == -1) {
LOGE("Failed writing module name\n");
LOGI("Name length: %zu\n", name_len); break;
ret = write(client_fd, &name_len, sizeof(name_len)); }
ASSURE_SIZE_WRITE_BREAK("ReadModules", "name length", ret, sizeof(name_len));
LOGI("Writing name: %s\n", context.modules[i].name); if (send_fd(client_fd, context.modules[i].lib_fd) == -1) {
ret = write(client_fd, context.modules[i].name, name_len); LOGE("Failed sending lib fd\n");
ASSURE_SIZE_WRITE_BREAK("ReadModules", "name", ret, name_len);
LOGI("Writing lib fd: %d\n", context.modules[i].lib_fd); break;
if (send_fd(client_fd, context.modules[i].lib_fd) == -1) break; }
} }
LOGI("Finished reading modules to stream\n"); LOGI("Finished reading modules to stream\n");
@@ -612,10 +678,10 @@ void zygiskd_start(void) {
if (companion_fd != -1) { if (companion_fd != -1) {
LOGI("Companion for module `%s` already exists\n", module->name); LOGI("Companion for module `%s` already exists\n", module->name);
if (fcntl(companion_fd, F_GETFD) == -1) { if (!check_unix_socket(companion_fd, 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(companion_fd);
module->companion = -1; module->companion = -1;
} }
} }
@@ -630,22 +696,26 @@ void zygiskd_start(void) {
module->companion = companion_fd; module->companion = companion_fd;
if (send_fd(client_fd, companion_fd) == -1) break; /* INFO: Reversed params, may fix issues */
} else if (companion_fd == -2) { if (send_fd(companion_fd, client_fd) == -1) {
LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name); LOGE("Failed sending companion fd\n");
/* TODO: Avoid duplicated code -- Merge this and the one below. */ uint8_t response = 0;
uint8_t response = 0; 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)); }
} else { } else {
LOGE("Failed to spawn companion for `%s`\n", module->name); if (companion_fd == -2) {
LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name);
uint8_t response = 0; } else {
ret = write(client_fd, &response, sizeof(response)); LOGI("Could not spawn companion for `%s` due to failures.\n", module->name);
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response)); }
} }
uint8_t response = 0;
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", companion_fd);
} }
@@ -666,19 +736,25 @@ void zygiskd_start(void) {
snprintf(dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name); snprintf(dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name);
LOGI("Module directory: %s\n", dir); LOGI("Module directory: %s\n", dir);
/* INFO: Maybe not read only? */
int dir_fd = open(dir, O_RDONLY); int dir_fd = open(dir, O_RDONLY);
LOGI("Module directory fd: %d\n", dir_fd); LOGI("Module directory fd: %d\n", dir_fd);
if (send_fd(client_fd, dir_fd) == -1) break; if (send_fd(client_fd, dir_fd) == -1) {
LOGE("Failed sending module directory fd\n");
close(dir_fd);
break;
}
LOGI("Sent module directory fd\n"); LOGI("Sent module directory fd\n");
break; break;
} }
/* INFO: Maybe we don't need to close? */
close(client_fd); close(client_fd);
} }