manager: Provide backward compatibility for legacy kernels

This commit is contained in:
ShirkNeko
2025-11-03 14:32:16 +08:00
parent e0bce04e79
commit 7051b22536
4 changed files with 276 additions and 112 deletions

View File

@@ -10,6 +10,7 @@ add_library(kernelsu
SHARED SHARED
jni.c jni.c
ksu.c ksu.c
legacy.c
) )
find_library(log-lib log) find_library(log-lib log)

View File

@@ -90,22 +90,30 @@ uint32_t get_version() {
return info.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) { 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() { bool is_safe_mode() {
struct ksu_check_safemode_cmd cmd = {}; struct ksu_check_safemode_cmd cmd = {};
ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &cmd); if (ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &cmd) == 0) {
return cmd.in_safe_mode; return cmd.in_safe_mode;
}
// fallback
return legacy_is_safe_mode();
} }
bool is_lkm_mode() { bool is_lkm_mode() {
@@ -113,6 +121,7 @@ bool is_lkm_mode() {
if (info.version > 0) { if (info.version > 0) {
return (info.flags & 0x1) != 0; return (info.flags & 0x1) != 0;
} }
// Legacy Compatible
return (legacy_get_info().flags & 0x1) != 0; return (legacy_get_info().flags & 0x1) != 0;
} }
@@ -121,46 +130,55 @@ bool is_manager() {
if (info.version > 0) { if (info.version > 0) {
return (info.flags & 0x2) != 0; return (info.flags & 0x2) != 0;
} }
// Legacy Compatible
return legacy_get_info().version; return legacy_get_info().version;
} }
bool uid_should_umount(int uid) { bool uid_should_umount(int uid) {
struct ksu_uid_should_umount_cmd cmd = {}; struct ksu_uid_should_umount_cmd cmd = {};
cmd.uid = uid; cmd.uid = uid;
ksuctl(KSU_IOCTL_UID_SHOULD_UMOUNT, &cmd); if (ksuctl(KSU_IOCTL_UID_SHOULD_UMOUNT, &cmd) == 0) {
return cmd.should_umount; return cmd.should_umount;
}
return legacy_uid_should_umount(uid);
} }
bool set_app_profile(const struct app_profile *profile) { bool set_app_profile(const struct app_profile *profile) {
struct ksu_set_app_profile_cmd cmd = {}; struct ksu_set_app_profile_cmd cmd = {};
cmd.profile = *profile; cmd.profile = *profile;
return ksuctl(KSU_IOCTL_SET_APP_PROFILE, &cmd) == 0; 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) { int get_app_profile(struct app_profile *profile) {
struct ksu_get_app_profile_cmd cmd = {.profile = *profile}; struct ksu_get_app_profile_cmd cmd = {.profile = *profile};
int ret = ksuctl(KSU_IOCTL_GET_APP_PROFILE, &cmd); int ret = ksuctl(KSU_IOCTL_GET_APP_PROFILE, &cmd);
if (ret == 0) {
*profile = cmd.profile; *profile = cmd.profile;
return ret; return 0;
}
return legacy_get_app_profile(profile->key, profile) ? 0 : -1;
} }
bool set_su_enabled(bool enabled) { bool set_su_enabled(bool enabled) {
struct ksu_set_feature_cmd cmd = {}; struct ksu_set_feature_cmd cmd = {};
cmd.feature_id = KSU_FEATURE_SU_COMPAT; cmd.feature_id = KSU_FEATURE_SU_COMPAT;
cmd.value = enabled ? 1 : 0; 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() { bool is_su_enabled() {
struct ksu_get_feature_cmd cmd = {}; struct ksu_get_feature_cmd cmd = {};
cmd.feature_id = KSU_FEATURE_SU_COMPAT; cmd.feature_id = KSU_FEATURE_SU_COMPAT;
if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) != 0) { if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) == 0 && cmd.supported) {
return false;
}
if (!cmd.supported) {
return false;
}
return cmd.value != 0; 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) { 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; return value != 0;
} }
// 1. 获取完整版本名称
void get_full_version(char* buff) { void get_full_version(char* buff) {
struct ksu_get_full_version_cmd cmd = {0}; struct ksu_get_full_version_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_GET_FULL_VERSION, &cmd) == 0) { if (ksuctl(KSU_IOCTL_GET_FULL_VERSION, &cmd) == 0) {
@@ -207,24 +225,23 @@ void get_full_version(char* buff) {
} }
} }
void legacy_get_full_version(char* buff) { // 2. 获取KPM启用状态
ksuctl_prctl(CMD_GET_VERSION_FULL, buff, NULL); bool is_KPM_enable(void) {
}
bool is_KPM_enable(void)
{
struct ksu_enable_kpm_cmd cmd = {}; struct ksu_enable_kpm_cmd cmd = {};
return ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled; if (ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled) {
return true;
}
return legacy_is_KPM_enable();
} }
void get_hook_type(char *buff) // 3. 获取钩子类型
{ void get_hook_type(char *buff) {
struct ksu_hook_type_cmd cmd = {0}; struct ksu_hook_type_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) { if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) {
strncpy(buff, cmd.hook_type, 32 - 1); strncpy(buff, cmd.hook_type, 32 - 1);
buff[32 - 1] = '\0'; buff[32 - 1] = '\0';
} else { } else {
strcpy(buff, "Unknown"); legacy_get_hook_type(buff, 32);
} }
} }
@@ -272,6 +289,34 @@ bool get_managers_list(struct manager_list_info *info)
return true; 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) { bool verify_module_signature(const char* input) {
#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM) #if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
@@ -329,32 +374,3 @@ bool verify_module_signature(const char* input) {
return false; return false;
#endif #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);
}

View File

@@ -12,40 +12,6 @@
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/syscall.h> #include <sys/syscall.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 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 #define KSU_FULL_VERSION_STRING 255
uint32_t get_version(); uint32_t get_version();
@@ -59,7 +25,6 @@ bool is_lkm_mode();
bool is_manager(); bool is_manager();
void get_full_version(char* buff); void get_full_version(char* buff);
void legacy_get_full_version(char* buff);
#define KSU_APP_PROFILE_VER 2 #define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256 #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 *); bool get_allow_list(struct ksu_get_allow_list_cmd *);
// Legacy Compatible
struct ksu_version_info legacy_get_info(); struct ksu_version_info legacy_get_info();
struct ksu_version_info { struct ksu_version_info {
@@ -303,4 +269,22 @@ struct ksu_version_info {
int32_t flags; 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 #endif //KERNELSU_KSU_H

View File

@@ -0,0 +1,163 @@
//
// Created by shirkneko on 2025/11/3.
//
// Legacy Compatible
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <android/log.h>
#include <dirent.h>
#include <stdlib.h>
#include <limits.h>
#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);
}