From 7051b2253645f425b170ab590d8a04b9d43a9e2e Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Mon, 3 Nov 2025 14:32:16 +0800 Subject: [PATCH] manager: Provide backward compatibility for legacy kernels --- manager/app/src/main/cpp/CMakeLists.txt | 1 + manager/app/src/main/cpp/ksu.c | 170 +++++++++++++----------- manager/app/src/main/cpp/ksu.h | 54 +++----- manager/app/src/main/cpp/legacy.c | 163 +++++++++++++++++++++++ 4 files changed, 276 insertions(+), 112 deletions(-) create mode 100644 manager/app/src/main/cpp/legacy.c diff --git a/manager/app/src/main/cpp/CMakeLists.txt b/manager/app/src/main/cpp/CMakeLists.txt index 2babafed..7fc4fdc6 100644 --- a/manager/app/src/main/cpp/CMakeLists.txt +++ b/manager/app/src/main/cpp/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(kernelsu SHARED jni.c ksu.c + legacy.c ) find_library(log-lib log) diff --git a/manager/app/src/main/cpp/ksu.c b/manager/app/src/main/cpp/ksu.c index ec7df527..03cb3fa6 100644 --- a/manager/app/src/main/cpp/ksu.c +++ b/manager/app/src/main/cpp/ksu.c @@ -90,22 +90,30 @@ uint32_t get_version() { return info.version; } -struct ksu_version_info legacy_get_info() -{ - int32_t version = -1; - int32_t flags = 0; - ksuctl_prctl(CMD_GET_VERSION, &version, &flags); - return (struct ksu_version_info){version, flags}; -} - bool get_allow_list(struct ksu_get_allow_list_cmd *cmd) { - return ksuctl(KSU_IOCTL_GET_ALLOW_LIST, cmd) == 0; + if (ksuctl(KSU_IOCTL_GET_ALLOW_LIST, cmd) == 0) { + return true; + } + + // fallback to legacy + int size = 0; + int uids[1024]; + if (legacy_get_allow_list(uids, &size)) { + cmd->count = size; + memcpy(cmd->uids, uids, sizeof(int) * size); + return true; + } + + return false; } bool is_safe_mode() { - struct ksu_check_safemode_cmd cmd = {}; - ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &cmd); - return cmd.in_safe_mode; + struct ksu_check_safemode_cmd cmd = {}; + if (ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &cmd) == 0) { + return cmd.in_safe_mode; + } + // fallback + return legacy_is_safe_mode(); } bool is_lkm_mode() { @@ -113,6 +121,7 @@ bool is_lkm_mode() { if (info.version > 0) { return (info.flags & 0x1) != 0; } + // Legacy Compatible return (legacy_get_info().flags & 0x1) != 0; } @@ -121,46 +130,55 @@ bool is_manager() { if (info.version > 0) { return (info.flags & 0x2) != 0; } + // Legacy Compatible return legacy_get_info().version; } bool uid_should_umount(int uid) { - struct ksu_uid_should_umount_cmd cmd = {}; - cmd.uid = uid; - ksuctl(KSU_IOCTL_UID_SHOULD_UMOUNT, &cmd); - return cmd.should_umount; + struct ksu_uid_should_umount_cmd cmd = {}; + cmd.uid = uid; + if (ksuctl(KSU_IOCTL_UID_SHOULD_UMOUNT, &cmd) == 0) { + return cmd.should_umount; + } + return legacy_uid_should_umount(uid); } bool set_app_profile(const struct app_profile *profile) { - struct ksu_set_app_profile_cmd cmd = {}; - cmd.profile = *profile; - return ksuctl(KSU_IOCTL_SET_APP_PROFILE, &cmd) == 0; + struct ksu_set_app_profile_cmd cmd = {}; + cmd.profile = *profile; + if (ksuctl(KSU_IOCTL_SET_APP_PROFILE, &cmd) == 0) { + return true; + } + return legacy_set_app_profile(profile); } int get_app_profile(struct app_profile *profile) { - struct ksu_get_app_profile_cmd cmd = {.profile = *profile}; - int ret = ksuctl(KSU_IOCTL_GET_APP_PROFILE, &cmd); - *profile = cmd.profile; - return ret; + struct ksu_get_app_profile_cmd cmd = {.profile = *profile}; + int ret = ksuctl(KSU_IOCTL_GET_APP_PROFILE, &cmd); + if (ret == 0) { + *profile = cmd.profile; + return 0; + } + return legacy_get_app_profile(profile->key, profile) ? 0 : -1; } bool set_su_enabled(bool enabled) { struct ksu_set_feature_cmd cmd = {}; cmd.feature_id = KSU_FEATURE_SU_COMPAT; cmd.value = enabled ? 1 : 0; - return ksuctl(KSU_IOCTL_SET_FEATURE, &cmd) == 0; + if (ksuctl(KSU_IOCTL_SET_FEATURE, &cmd) == 0) { + return true; + } + return legacy_set_su_enabled(enabled); } bool is_su_enabled() { struct ksu_get_feature_cmd cmd = {}; cmd.feature_id = KSU_FEATURE_SU_COMPAT; - if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) != 0) { - return false; + if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) == 0 && cmd.supported) { + return cmd.value != 0; } - if (!cmd.supported) { - return false; - } - return cmd.value != 0; + return legacy_is_su_enabled(); } static inline bool get_feature(uint32_t feature_id, uint64_t *out_value, bool *out_supported) { @@ -196,7 +214,7 @@ bool is_kernel_umount_enabled() { } return value != 0; } - +// 1. 获取完整版本名称 void get_full_version(char* buff) { struct ksu_get_full_version_cmd cmd = {0}; if (ksuctl(KSU_IOCTL_GET_FULL_VERSION, &cmd) == 0) { @@ -207,25 +225,24 @@ void get_full_version(char* buff) { } } -void legacy_get_full_version(char* buff) { - ksuctl_prctl(CMD_GET_VERSION_FULL, buff, NULL); +// 2. 获取KPM启用状态 +bool is_KPM_enable(void) { + struct ksu_enable_kpm_cmd cmd = {}; + if (ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled) { + return true; + } + return legacy_is_KPM_enable(); } -bool is_KPM_enable(void) -{ - struct ksu_enable_kpm_cmd cmd = {}; - return ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled; -} - -void get_hook_type(char *buff) -{ - struct ksu_hook_type_cmd cmd = {0}; - if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) { - strncpy(buff, cmd.hook_type, 32 - 1); - buff[32 - 1] = '\0'; - } else { - strcpy(buff, "Unknown"); - } +// 3. 获取钩子类型 +void get_hook_type(char *buff) { + struct ksu_hook_type_cmd cmd = {0}; + if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) { + strncpy(buff, cmd.hook_type, 32 - 1); + buff[32 - 1] = '\0'; + } else { + legacy_get_hook_type(buff, 32); + } } bool set_dynamic_manager(unsigned int size, const char *hash) @@ -272,6 +289,34 @@ bool get_managers_list(struct manager_list_info *info) return true; } +bool is_uid_scanner_enabled(void) +{ + bool status = false; + + struct ksu_enable_uid_scanner_cmd cmd = { + .operation = UID_SCANNER_OP_GET_STATUS, + .status_ptr = (__u64)(uintptr_t)&status + }; + + return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd) == 0 != 0 && status; +} + +bool set_uid_scanner_enabled(bool enabled) +{ + struct ksu_enable_uid_scanner_cmd cmd = { + .operation = UID_SCANNER_OP_TOGGLE, + .enabled = enabled + }; + return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd); +} + +bool clear_uid_scanner_environment(void) +{ + struct ksu_enable_uid_scanner_cmd cmd = { + .operation = UID_SCANNER_OP_CLEAR_ENV + }; + return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd); +} bool verify_module_signature(const char* input) { #if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM) @@ -329,32 +374,3 @@ bool verify_module_signature(const char* input) { return false; #endif } - -bool is_uid_scanner_enabled(void) -{ - bool status = false; - - struct ksu_enable_uid_scanner_cmd cmd = { - .operation = UID_SCANNER_OP_GET_STATUS, - .status_ptr = (__u64)(uintptr_t)&status - }; - - return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd) == 0 != 0 && status; -} - -bool set_uid_scanner_enabled(bool enabled) -{ - struct ksu_enable_uid_scanner_cmd cmd = { - .operation = UID_SCANNER_OP_TOGGLE, - .enabled = enabled - }; - return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd); -} - -bool clear_uid_scanner_environment(void) -{ - struct ksu_enable_uid_scanner_cmd cmd = { - .operation = UID_SCANNER_OP_CLEAR_ENV - }; - return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd); -} \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.h b/manager/app/src/main/cpp/ksu.h index 9c2c360d..d1a786da 100644 --- a/manager/app/src/main/cpp/ksu.h +++ b/manager/app/src/main/cpp/ksu.h @@ -12,40 +12,6 @@ #include #include -#define KERNEL_SU_OPTION 0xDEADBEEF - -#define CMD_GRANT_ROOT 0 - -#define CMD_BECOME_MANAGER 1 -#define CMD_GET_VERSION 2 -#define CMD_ALLOW_SU 3 -#define CMD_DENY_SU 4 -#define CMD_GET_SU_LIST 5 -#define CMD_GET_DENY_LIST 6 -#define CMD_CHECK_SAFEMODE 9 - -#define CMD_GET_APP_PROFILE 10 -#define CMD_SET_APP_PROFILE 11 - -#define CMD_IS_UID_GRANTED_ROOT 12 -#define CMD_IS_UID_SHOULD_UMOUNT 13 -#define CMD_IS_SU_ENABLED 14 -#define CMD_ENABLE_SU 15 - -#define CMD_GET_VERSION_FULL 0xC0FFEE1A - -#define CMD_ENABLE_KPM 100 -#define CMD_HOOK_TYPE 101 -#define CMD_DYNAMIC_MANAGER 103 -#define CMD_GET_MANAGERS 104 -#define CMD_ENABLE_UID_SCANNER 105 - -static inline bool ksuctl_prctl(int cmd, void* arg1, void* arg2) { - int32_t result = 0; - int32_t rtn = prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result); - return result == KERNEL_SU_OPTION && rtn == -1; -} - #define KSU_FULL_VERSION_STRING 255 uint32_t get_version(); @@ -59,7 +25,6 @@ bool is_lkm_mode(); bool is_manager(); void get_full_version(char* buff); -void legacy_get_full_version(char* buff); #define KSU_APP_PROFILE_VER 2 #define KSU_MAX_PACKAGE_NAME 256 @@ -296,6 +261,7 @@ struct ksu_enable_uid_scanner_cmd { bool get_allow_list(struct ksu_get_allow_list_cmd *); +// Legacy Compatible struct ksu_version_info legacy_get_info(); struct ksu_version_info { @@ -303,4 +269,22 @@ struct ksu_version_info { int32_t flags; }; +bool legacy_get_allow_list(int *uids, int *size); +bool legacy_is_safe_mode(); +bool legacy_uid_should_umount(int uid); +bool legacy_set_app_profile(const struct app_profile* profile); +bool legacy_get_app_profile(char* key, struct app_profile* profile); +bool legacy_set_su_enabled(bool enabled); +bool legacy_is_su_enabled(); +bool legacy_is_KPM_enable(); +bool legacy_get_hook_type(char* hook_type, size_t size); +void legacy_get_full_version(char* buff); +bool legacy_set_dynamic_manager(unsigned int size, const char* hash); +bool legacy_get_dynamic_manager(struct dynamic_manager_user_config* config); +bool legacy_clear_dynamic_manager(); +bool legacy_get_managers_list(struct manager_list_info* info); +bool legacy_is_uid_scanner_enabled(); +bool legacy_set_uid_scanner_enabled(bool enabled); +bool legacy_clear_uid_scanner_environment(); + #endif //KERNELSU_KSU_H \ No newline at end of file diff --git a/manager/app/src/main/cpp/legacy.c b/manager/app/src/main/cpp/legacy.c new file mode 100644 index 00000000..de72a326 --- /dev/null +++ b/manager/app/src/main/cpp/legacy.c @@ -0,0 +1,163 @@ +// +// Created by shirkneko on 2025/11/3. +// +// Legacy Compatible +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prelude.h" +#include "ksu.h" + +#define KERNEL_SU_OPTION 0xDEADBEEF + +#define CMD_GRANT_ROOT 0 + +#define CMD_BECOME_MANAGER 1 +#define CMD_GET_VERSION 2 +#define CMD_ALLOW_SU 3 +#define CMD_DENY_SU 4 +#define CMD_GET_SU_LIST 5 +#define CMD_GET_DENY_LIST 6 +#define CMD_CHECK_SAFEMODE 9 + +#define CMD_GET_APP_PROFILE 10 +#define CMD_SET_APP_PROFILE 11 + +#define CMD_IS_UID_GRANTED_ROOT 12 +#define CMD_IS_UID_SHOULD_UMOUNT 13 +#define CMD_IS_SU_ENABLED 14 +#define CMD_ENABLE_SU 15 + +#define CMD_GET_VERSION_FULL 0xC0FFEE1A + +#define CMD_ENABLE_KPM 100 +#define CMD_HOOK_TYPE 101 +#define CMD_DYNAMIC_MANAGER 103 +#define CMD_GET_MANAGERS 104 +#define CMD_ENABLE_UID_SCANNER 105 + +static bool ksuctl(int cmd, void* arg1, void* arg2) { + int32_t result = 0; + int32_t rtn = prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result); + return result == KERNEL_SU_OPTION && rtn == -1; +} + +struct ksu_version_info legacy_get_info() +{ + int32_t version = -1; + int32_t flags = 0; + ksuctl(CMD_GET_VERSION, &version, &flags); + return (struct ksu_version_info){version, flags}; +} + +bool legacy_get_allow_list(int *uids, int *size) { + return ksuctl(CMD_GET_SU_LIST, uids, size); +} + +bool legacy_is_safe_mode() { + return ksuctl(CMD_CHECK_SAFEMODE, NULL, NULL); +} + +bool legacy_uid_should_umount(int uid) { + int should; + return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, (void*) ((size_t) uid), &should) && should; +} + +bool legacy_set_app_profile(const struct app_profile* profile) { + return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, NULL); +} + +bool legacy_get_app_profile(char* key, struct app_profile* profile) { + return ksuctl(CMD_GET_APP_PROFILE, profile, NULL); +} + +bool legacy_set_su_enabled(bool enabled) { + return ksuctl(CMD_ENABLE_SU, (void*) enabled, NULL); +} + +bool legacy_is_su_enabled() { + int enabled = true; + // if ksuctl failed, we assume su is enabled, and it cannot be disabled. + ksuctl(CMD_IS_SU_ENABLED, &enabled, NULL); + return enabled; +} + +bool legacy_is_KPM_enable() { + int enabled = false; + ksuctl(CMD_ENABLE_KPM, &enabled, NULL); + return enabled; +} + +bool legacy_get_hook_type(char* hook_type, size_t size) { + if (hook_type == NULL || size == 0) { + return false; + } + + static char cached_hook_type[16] = {0}; + if (cached_hook_type[0] == '\0') { + if (!ksuctl(CMD_HOOK_TYPE, cached_hook_type, NULL)) { + strcpy(cached_hook_type, "Unknown"); + } + } + + strncpy(hook_type, cached_hook_type, size - 1); + hook_type[size - 1] = '\0'; + return true; +} + +void legacy_get_full_version(char* buff) { + ksuctl(CMD_GET_VERSION_FULL, buff, NULL); +} + +bool legacy_set_dynamic_manager(unsigned int size, const char* hash) { + if (hash == NULL) { + return false; + } + struct dynamic_manager_user_config config; + config.operation = DYNAMIC_MANAGER_OP_SET; + config.size = size; + strncpy(config.hash, hash, sizeof(config.hash) - 1); + config.hash[sizeof(config.hash) - 1] = '\0'; + return ksuctl(CMD_DYNAMIC_MANAGER, &config, NULL); +} + +bool legacy_get_dynamic_manager(struct dynamic_manager_user_config* config) { + if (config == NULL) { + return false; + } + config->operation = DYNAMIC_MANAGER_OP_GET; + return ksuctl(CMD_DYNAMIC_MANAGER, config, NULL); +} + +bool legacy_clear_dynamic_manager() { + struct dynamic_manager_user_config config; + config.operation = DYNAMIC_MANAGER_OP_CLEAR; + return ksuctl(CMD_DYNAMIC_MANAGER, &config, NULL); +} + +bool legacy_get_managers_list(struct manager_list_info* info) { + if (info == NULL) { + return false; + } + return ksuctl(CMD_GET_MANAGERS, info, NULL); +} + +bool legacy_is_uid_scanner_enabled() { + bool status = false; + ksuctl(CMD_ENABLE_UID_SCANNER, (void*)0, &status); + return status; +} + +bool legacy_set_uid_scanner_enabled(bool enabled) { + return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)1, (void*)enabled); +} + +bool legacy_clear_uid_scanner_environment() { + return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)2, NULL); +} \ No newline at end of file