add: Magisk variant status; improve: KSU detection

This commit adds the Magisk variant to module description, and also improves KernelSU detection by requiring the userspace part of it to be installed, AKA "ksud".
This commit is contained in:
ThePedroo
2024-10-24 16:51:23 -03:00
parent 380ef011a1
commit 135ebbb9ba
12 changed files with 245 additions and 222 deletions

View File

@@ -14,7 +14,11 @@
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]);
#ifdef __LP64__
LOGI("Welcome to ReZygisk %s Zygiskd64!\n", ZKSU_VERSION);
#else
LOGI("Welcome to ReZygisk %s Zygiskd32!\n", ZKSU_VERSION);
#endif
if (argc > 1) {
if (strcmp(argv[1], "companion") == 0) {
@@ -38,37 +42,14 @@ int main(int argc, char *argv[]) {
else if (strcmp(argv[1], "root") == 0) {
root_impls_setup();
enum RootImpl impl = get_impl();
switch (impl) {
case None: {
LOGI("No root implementation found.\n");
struct root_impl impl;
get_impl(&impl);
return 1;
}
char impl_name[LONGEST_ROOT_IMPL_NAME];
stringify_root_impl_name(impl, impl_name);
case Multiple: {
LOGI("Multiple root implementations found.\n");
return 1;
}
case KernelSU: {
LOGI("KernelSU root implementation found.\n");
return 0;
}
case APatch: {
LOGI("APatch root implementation found.\n");
return 0;
}
case Magisk: {
LOGI("Magisk root implementation found.\n");
return 0;
}
}
LOGI("Root implementation: %s\n", impl_name);
return 0;
}

View File

@@ -6,10 +6,11 @@
#include "../constants.h"
#include "../utils.h"
#include "common.h"
#include "apatch.h"
enum RootImplState apatch_get_existence(void) {
void apatch_get_existence(struct root_impl_state *state) {
struct stat s;
if (stat("/data/adb/apd", &s) != 0) {
if (errno != ENOENT) {
@@ -17,7 +18,9 @@ enum RootImplState apatch_get_existence(void) {
}
errno = 0;
return Inexistent;
state->state = Inexistent;
return;
}
char *PATH = getenv("PATH");
@@ -25,13 +28,17 @@ enum RootImplState apatch_get_existence(void) {
LOGE("Failed to get PATH environment variable: %s\n", strerror(errno));
errno = 0;
return Inexistent;
state->state = Inexistent;
return;
}
if (strstr(PATH, "/data/adb/ap/bin") == NULL) {
LOGE("APatch's APD binary is not in PATH\n");
return Inexistent;
state->state = Inexistent;
return;
}
char apatch_version[32];
@@ -41,16 +48,17 @@ enum RootImplState apatch_get_existence(void) {
LOGE("Failed to execute apd binary: %s\n", strerror(errno));
errno = 0;
return Inexistent;
state->state = Inexistent;
return;
}
int version = atoi(apatch_version + strlen("apd "));
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;
if (version == 0) state->state = Abnormal;
else if (version >= MIN_APATCH_VERSION && version <= 999999) state->state = Supported;
else if (version >= 1 && version <= MIN_APATCH_VERSION - 1) state->state = TooOld;
else state->state = Abnormal;
}
struct package_config {

View File

@@ -3,7 +3,7 @@
#include "../constants.h"
enum RootImplState apatch_get_existence(void);
void apatch_get_existence(struct root_impl_state *state);
bool apatch_uid_granted_root(uid_t uid);

View File

@@ -9,15 +9,34 @@
#include "common.h"
static enum RootImpl ROOT_IMPL = None;
static struct root_impl impl;
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;
struct root_impl_state state_ksu;
ksu_get_existence(&state_ksu);
switch (ROOT_IMPL) {
struct root_impl_state state_apatch;
apatch_get_existence(&state_apatch);
struct root_impl_state state_magisk;
magisk_get_existence(&state_magisk);
/* INFO: Check if it's only one supported, if not, it's multile and that's bad.
Remember that true here is equal to the integer 1. */
if ((state_ksu.state == Supported ? 1 : 0) + (state_apatch.state == Supported ? 1 : 0) + (state_magisk.state == Supported ? 1 : 0) >= 2) {
impl.impl = Multiple;
} else if (state_ksu.state == Supported) {
impl.impl = KernelSU;
} else if (state_apatch.state == Supported) {
impl.impl = APatch;
} else if (state_magisk.state == Supported) {
impl.impl = Magisk;
impl.variant = state_magisk.variant;
} else {
impl.impl = None;
}
switch (impl.impl) {
case None: {
LOGI("No root implementation found.\n");
@@ -39,19 +58,24 @@ void root_impls_setup(void) {
break;
}
case Magisk: {
LOGI("Magisk root implementation found.\n");
if (state_magisk.variant == 0) {
LOGI("Magisk Official root implementation found.\n");
} else {
LOGI("Magisk Kitsune root implementation found.\n");
}
break;
}
}
}
enum RootImpl get_impl(void) {
return ROOT_IMPL;
void get_impl(struct root_impl *uimpl) {
uimpl->impl = impl.impl;
uimpl->variant = impl.variant;
}
bool uid_granted_root(uid_t uid) {
switch (get_impl()) {
switch (impl.impl) {
case KernelSU: {
return ksu_uid_granted_root(uid);
}
@@ -68,7 +92,7 @@ bool uid_granted_root(uid_t uid) {
}
bool uid_should_umount(uid_t uid) {
switch (get_impl()) {
switch (impl.impl) {
case KernelSU: {
return ksu_uid_should_umount(uid);
}
@@ -85,7 +109,7 @@ bool uid_should_umount(uid_t uid) {
}
bool uid_is_manager(uid_t uid) {
switch (get_impl()) {
switch (impl.impl) {
case KernelSU: {
return ksu_uid_is_manager(uid);
}

View File

@@ -1,9 +1,11 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h>
#include "../constants.h"
enum RootImpl {
enum root_impls {
None,
Multiple,
KernelSU,
@@ -11,9 +13,21 @@ enum RootImpl {
Magisk
};
struct root_impl_state {
enum RootImplState state;
uint8_t variant;
};
struct root_impl {
enum root_impls impl;
uint8_t variant;
};
#define LONGEST_ROOT_IMPL_NAME sizeof("Magisk Kitsune")
void root_impls_setup(void);
enum RootImpl get_impl(void);
void get_impl(struct root_impl *uimpl);
bool uid_granted_root(uid_t uid);

View File

@@ -6,6 +6,7 @@
#include "../constants.h"
#include "../utils.h"
#include "common.h"
#include "kernelsu.h"
@@ -19,15 +20,31 @@
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
enum RootImplState ksu_get_existence(void) {
void ksu_get_existence(struct root_impl_state *state) {
int version = 0;
prctl((signed int)KERNEL_SU_OPTION, CMD_GET_VERSION, &version, 0, 0);
if (version == 0) return Inexistent;
if (version >= MIN_KSU_VERSION && version <= MAX_KSU_VERSION) return Supported;
if (version >= 1 && version <= MIN_KSU_VERSION - 1) return TooOld;
if (version == 0) state->state = Abnormal;
else if (version >= MIN_KSU_VERSION && version <= MAX_KSU_VERSION) {
/* INFO: Some custom kernels for custom ROMs have pre-installed KernelSU.
Some users don't want to use KernelSU, but, for example, Magisk.
This if allows this to happen, as it checks if "ksud" exists,
which in case it doesn't, it won't be considered as supported. */
struct stat s;
if (stat("/data/adb/ksud", &s) == -1) {
if (errno != ENOENT) {
LOGE("Failed to stat KSU daemon: %s\n", strerror(errno));
}
errno = 0;
state->state = Abnormal;
return Abnormal;
return;
}
state->state = Supported;
}
else if (version >= 1 && version <= MIN_KSU_VERSION - 1) state->state = TooOld;
else state->state = Abnormal;
}
bool ksu_uid_granted_root(uid_t uid) {

View File

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

View File

@@ -10,6 +10,7 @@
#include "../constants.h"
#include "../utils.h"
#include "common.h"
#include "magisk.h"
@@ -30,7 +31,7 @@ enum magisk_variants variant = Official;
/* INFO: Longest path */
static char path_to_magisk[sizeof(DEBUG_RAMDISK_MAGISK)];
enum RootImplState magisk_get_existence(void) {
void magisk_get_existence(struct root_impl_state *state) {
struct stat s;
if (stat(SBIN_MAGISK, &s) != 0) {
if (errno != ENOENT) {
@@ -50,7 +51,9 @@ enum RootImplState magisk_get_existence(void) {
}
errno = 0;
return Inexistent;
state->state = Inexistent;
return;
}
/* INFO: /debug_ramdisk/magisk64 (or 32) doesn't exist but /debug_ramdisk/magisk does */
@@ -71,11 +74,20 @@ enum RootImplState magisk_get_existence(void) {
LOGE("Failed to execute magisk binary: %s\n", strerror(errno));
errno = 0;
return Abnormal;
state->state = Abnormal;
return;
}
state->variant = (uint8_t)Official;
for (unsigned long i = 0; i < sizeof(supported_variants) / sizeof(supported_variants[0]); i++) {
if (strstr(magisk_info, supported_variants[i])) variant = (enum magisk_variants)(i + 1);
if (strstr(magisk_info, supported_variants[i])) {
variant = (enum magisk_variants)(i + 1);
state->variant = (uint8_t)variant;
break;
}
}
argv[1] = "-V";
@@ -85,11 +97,13 @@ enum RootImplState magisk_get_existence(void) {
LOGE("Failed to execute magisk binary: %s\n", strerror(errno));
errno = 0;
return Abnormal;
state->state = Abnormal;
return;
}
if (atoi(magisk_version) >= MIN_MAGISK_VERSION) return Supported;
else return TooOld;
if (atoi(magisk_version) >= MIN_MAGISK_VERSION) state->state = Supported;
else state->state = TooOld;
}
bool magisk_uid_granted_root(uid_t uid) {

View File

@@ -8,7 +8,7 @@ enum magisk_variants {
Kitsune
};
enum RootImplState magisk_get_existence(void);
void magisk_get_existence(struct root_impl_state *state);
bool magisk_uid_granted_root(uid_t uid);

View File

@@ -17,6 +17,7 @@
#include <android/log.h>
#include "utils.h"
#include "root_impl/common.h"
bool switch_mount_namespace(pid_t pid) {
char path[PATH_MAX];
@@ -411,3 +412,37 @@ int non_blocking_execv(const char *restrict file, char *const argv[]) {
return -1;
}
void stringify_root_impl_name(struct root_impl impl, char *restrict output) {
switch (impl.impl) {
case None: {
strcpy(output, "None");
break;
}
case Multiple: {
strcpy(output, "Multiple");
break;
}
case KernelSU: {
strcpy(output, "KernelSU");
break;
}
case APatch: {
strcpy(output, "APatch");
break;
}
case Magisk: {
if (impl.variant == 0) {
strcpy(output, "Magisk Official");
} else {
strcpy(output, "Magisk Kitsune");
}
break;
}
}
}

View File

@@ -4,6 +4,7 @@
#include <sys/types.h>
#include "constants.h"
#include "root_impl/common.h"
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
@@ -101,4 +102,6 @@ bool check_unix_socket(int fd, bool block);
int non_blocking_execv(const char *restrict file, char *const argv[]);
void stringify_root_impl_name(struct root_impl impl, char *restrict output);
#endif /* UTILS_H */

View File

@@ -316,175 +316,92 @@ struct __attribute__((__packed__)) MsgHead {
/* WARNING: Dynamic memory based */
void zygiskd_start(char *restrict argv[]) {
LOGI("Welcome to ReZygisk %s Zygiskd!\n", ZKSU_VERSION);
/* INFO: When implementation is None or Multiple, it won't set the values
for the context, causing it to have garbage values. In response
to that, "= { 0 }" is used to ensure that the values are clean. */
struct Context context = { 0 };
enum RootImpl impl = get_impl();
if (impl == None) {
struct MsgHead *msg = malloc(sizeof(struct MsgHead) + sizeof("No root implementation found."));
if (msg == NULL) {
LOGE("Failed allocating memory for message.\n");
return;
}
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."));
if (msg == NULL) {
LOGE("Failed allocating memory for message.\n");
return;
}
struct root_impl impl;
get_impl(&impl);
if (impl.impl == None || impl.impl == Multiple) {
struct MsgHead *msg = NULL;
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);
if (impl.impl == None) {
msg = malloc(sizeof(struct MsgHead) + strlen("Unsupported environment: Unknown root implementation") + 1);
} else {
msg = malloc(sizeof(struct MsgHead) + strlen("Unsupported environment: Multiple root implementations found") + 1);
}
if (msg == NULL) {
LOGE("Failed allocating memory for message.\n");
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead) + msg->length);
return;
}
msg->cmd = DAEMON_SET_ERROR_INFO;
if (impl.impl == None) {
msg->length = sprintf(msg->data, "Unsupported environment: Unknown root implementation");
} else {
msg->length = sprintf(msg->data, "Unsupported environment: Multiple root implementations found");
}
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, sizeof(struct MsgHead) + msg->length);
free(msg);
}
} else {
enum Architecture arch = get_arch();
load_modules(arch, &context);
enum Architecture arch = get_arch();
char *module_list = NULL;
size_t module_list_len = 0;
if (context.len == 0) {
module_list = strdup("None");
module_list_len = strlen("None");
} else {
for (int i = 0; i < context.len; i++) {
if (i != context.len - 1) {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + strlen(", ") + 1);
if (module_list == NULL) {
LOGE("Failed reallocating memory for module list.\n");
struct Context context;
load_modules(arch, &context);
return;
}
struct MsgHead *msg = NULL;
strcpy(module_list + module_list_len, context.modules[i].name);
switch (impl) {
case None: { break; }
case Multiple: { break; }
case KernelSU:
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");
module_list_len += strlen(context.modules[i].name);
break;
}
case APatch: {
root_impl_len = strlen("APatch");
strcpy(module_list + module_list_len, ", ");
break;
}
case Magisk: {
root_impl_len = strlen("Magisk");
module_list_len += strlen(", ");
} else {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + 1);
if (module_list == NULL) {
LOGE("Failed reallocating memory for module list.\n");
break;
return;
}
strcpy(module_list + module_list_len, context.modules[i].name);
module_list_len += strlen(context.modules[i].name);
}
}
if (context.len == 0) {
msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: None") + root_impl_len + 1);
if (msg == NULL) {
LOGE("Failed allocating memory for message.\n");
return;
}
msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: , Modules: None") + root_impl_len + 1;
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;
}
case Magisk: {
memcpy(msg->data, "Root: Magisk, Modules: None", strlen("Root: Magisk, Modules: None"));
break;
}
}
} else {
char *module_list = malloc(1);
if (module_list == NULL) {
LOGE("Failed allocating memory for module list.\n");
return;
}
size_t module_list_len = 0;
for (int i = 0; i < context.len; i++) {
if (i != context.len - 1) {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + strlen(", ") + 1);
memcpy(module_list + module_list_len, context.modules[i].name, strlen(context.modules[i].name));
module_list_len += strlen(context.modules[i].name);
memcpy(module_list + module_list_len, ", ", strlen(", "));
module_list_len += strlen(", ");
} else {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + 1);
memcpy(module_list + module_list_len, context.modules[i].name, strlen(context.modules[i].name));
module_list_len += strlen(context.modules[i].name);
}
}
msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: ") + root_impl_len + module_list_len + 1);
if (msg == NULL) {
LOGE("Failed allocating memory for message.\n");
return;
}
msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: , Modules: ") + root_impl_len + module_list_len + 1;
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;
}
case Magisk: {
memcpy(msg->data, "Root: Magisk, Modules: ", strlen("Root: Magisk, Modules: "));
break;
}
}
memcpy(msg->data + strlen("Root: , Modules: ") + root_impl_len, module_list, module_list_len);
free(module_list);
}
break;
}
char impl_name[LONGEST_ROOT_IMPL_NAME];
stringify_root_impl_name(impl, impl_name);
struct MsgHead *msg = NULL;
msg = malloc(sizeof(struct MsgHead) + strlen("Root: , Modules: ") + strlen(impl_name) + module_list_len + 1);
msg->length = sprintf(msg->data, "Root: %s, Modules: %s", impl_name, module_list);
msg->cmd = DAEMON_SET_INFO;
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, sizeof(struct MsgHead) + msg->length);
free(msg);
free(module_list);
}
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, sizeof(struct MsgHead) + msg->length);
free(msg);
int socket_fd = create_daemon_socket();
if (socket_fd == -1) {
LOGE("Failed creating daemon socket\n");
@@ -535,6 +452,16 @@ void zygiskd_start(char *restrict argv[]) {
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
if (impl.impl == None || impl.impl == Multiple) {
LOGI("Unsupported environment detected. Exiting.\n");
close(client_fd);
close(socket_fd);
free_modules(&context);
exit(1);
}
break;
}
case RequestLogcatFd: {
@@ -586,7 +513,7 @@ void zygiskd_start(char *restrict argv[]) {
}
}
switch (get_impl()) {
switch (impl.impl) {
case None: { break; }
case Multiple: { break; }
case KernelSU: {
@@ -614,7 +541,7 @@ void zygiskd_start(char *restrict argv[]) {
case GetInfo: {
uint32_t flags = 0;
switch (get_impl()) {
switch (impl.impl) {
case None: { break; }
case Multiple: { break; }
case KernelSU: {