* refact: use feature subsystem

* use 64bit feature

* fix

* add fixme

* add feature max to get_info

* use 32bit feature id

* allow root to get/set feature

* more clean perm_check functions

* fix

* add feature command to ksud

kernel: do not expose perm checker

* fix security_task_fix_setuid_handler_pre

* add android16-6.12 ci

* manager: add kernel_umount switch

Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>

* manager: Reinstate the LKM selection function

* kernel: add name and print command value

- Optimise sulog log display

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>

* fix

* ksud: clippy

---------

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
ShirkNeko
2025-11-02 20:01:24 +08:00
committed by GitHub
parent 00de4e1c64
commit 47bcc956a3
26 changed files with 963 additions and 852 deletions

View File

@@ -7,6 +7,7 @@ kernelsu-objs += pkg_observer.o
kernelsu-objs += throne_tracker.o
kernelsu-objs += core_hook.o
kernelsu-objs += supercalls.o
kernelsu-objs += feature.o
kernelsu-objs += ksud.o
kernelsu-objs += embed_ksud.o
kernelsu-objs += kernel_compat.o

View File

@@ -31,6 +31,7 @@
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "ksud.h"
@@ -78,6 +79,29 @@ struct ksu_umount_work {
struct mnt_namespace *mnt_ns;
};
static bool ksu_kernel_umount_enabled = true;
static int kernel_umount_feature_get(u64 *value)
{
*value = ksu_kernel_umount_enabled ? 1 : 0;
return 0;
}
static int kernel_umount_feature_set(u64 value)
{
bool enable = value != 0;
ksu_kernel_umount_enabled = enable;
pr_info("kernel_umount: set to %d\n", enable);
return 0;
}
static const struct ksu_feature_handler kernel_umount_handler = {
.feature_id = KSU_FEATURE_KERNEL_UMOUNT,
.name = "kernel_umount",
.get_handler = kernel_umount_feature_get,
.set_handler = kernel_umount_feature_set,
};
static inline bool is_allow_su()
{
if (is_manager()) {
@@ -539,8 +563,8 @@ static void do_umount_work(struct work_struct *work)
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
// fixme: dec refcount
current->nsproxy->mnt_ns = old_mnt_ns;
put_mnt_ns(umount_work->mnt_ns);
kfree(umount_work);
}
@@ -588,6 +612,10 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0;
}
if (!ksu_kernel_umount_enabled) {
return 0;
}
if (!ksu_uid_should_umount(new_uid.val)) {
return 0;
} else {
@@ -622,8 +650,8 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0;
}
// fixme: inc refcount
umount_work->mnt_ns = current->nsproxy->mnt_ns;
get_mnt_ns(umount_work->mnt_ns);
INIT_WORK(&umount_work->work, do_umount_work);
@@ -668,9 +696,8 @@ static struct kprobe reboot_kp = {
// 2. security_task_fix_setuid hook for handling setuid
static int security_task_fix_setuid_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
struct cred *new = (struct cred *)PT_REGS_PARM1(real_regs);
const struct cred *old = (const struct cred *)PT_REGS_PARM2(real_regs);
struct cred *new = (struct cred *)PT_REGS_PARM1(regs);
const struct cred *old = (const struct cred *)PT_REGS_PARM2(regs);
ksu_handle_setuid(new, old);
@@ -844,6 +871,10 @@ __maybe_unused int ksu_kprobe_exit(void)
void __init ksu_core_init(void)
{
if (ksu_register_feature_handler(&kernel_umount_handler)) {
pr_err("Failed to register kernel_umount feature handler\n");
}
ksu_workqueue = alloc_workqueue("ksu_umount", WQ_UNBOUND, 0);
if (!ksu_workqueue) {
pr_err("Failed to create ksu workqueue\n");

188
kernel/feature.c Normal file
View File

@@ -0,0 +1,188 @@
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include <linux/slab.h>
#include <linux/mutex.h>
static struct ksu_feature_handler *feature_handlers[KSU_FEATURE_MAX];
static DEFINE_MUTEX(feature_mutex);
int ksu_register_feature_handler(const struct ksu_feature_handler *handler)
{
int ret = 0;
if (!handler) {
pr_err("feature: register handler is NULL\n");
return -EINVAL;
}
if (handler->feature_id >= KSU_FEATURE_MAX) {
pr_err("feature: invalid feature_id %u\n", handler->feature_id);
return -EINVAL;
}
if (!handler->get_handler && !handler->set_handler) {
pr_err("feature: no handler provided for feature %u\n", handler->feature_id);
return -EINVAL;
}
mutex_lock(&feature_mutex);
if (feature_handlers[handler->feature_id]) {
pr_warn("feature: handler for %u already registered, overwriting\n",
handler->feature_id);
}
feature_handlers[handler->feature_id] = kmalloc(sizeof(struct ksu_feature_handler), GFP_KERNEL);
if (!feature_handlers[handler->feature_id]) {
pr_err("feature: failed to allocate handler for %u\n", handler->feature_id);
ret = -ENOMEM;
goto out;
}
memcpy(feature_handlers[handler->feature_id], handler, sizeof(struct ksu_feature_handler));
pr_info("feature: registered handler for %s (id=%u)\n",
handler->name ? handler->name : "unknown", handler->feature_id);
out:
mutex_unlock(&feature_mutex);
return ret;
}
int ksu_unregister_feature_handler(u32 feature_id)
{
int ret = 0;
if (feature_id >= KSU_FEATURE_MAX) {
pr_err("feature: invalid feature_id %u\n", feature_id);
return -EINVAL;
}
mutex_lock(&feature_mutex);
if (!feature_handlers[feature_id]) {
pr_warn("feature: no handler registered for %u\n", feature_id);
ret = -ENOENT;
goto out;
}
kfree(feature_handlers[feature_id]);
feature_handlers[feature_id] = NULL;
pr_info("feature: unregistered handler for id=%u\n", feature_id);
out:
mutex_unlock(&feature_mutex);
return ret;
}
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported)
{
int ret = 0;
struct ksu_feature_handler *handler;
if (feature_id >= KSU_FEATURE_MAX) {
pr_err("feature: invalid feature_id %u\n", feature_id);
return -EINVAL;
}
if (!value || !supported) {
pr_err("feature: invalid parameters\n");
return -EINVAL;
}
mutex_lock(&feature_mutex);
handler = feature_handlers[feature_id];
if (!handler) {
*supported = false;
*value = 0;
pr_debug("feature: feature %u not supported\n", feature_id);
goto out;
}
*supported = true;
if (!handler->get_handler) {
pr_warn("feature: no get_handler for feature %u\n", feature_id);
ret = -EOPNOTSUPP;
goto out;
}
ret = handler->get_handler(value);
if (ret) {
pr_err("feature: get_handler for %u failed: %d\n", feature_id, ret);
}
out:
mutex_unlock(&feature_mutex);
return ret;
}
int ksu_set_feature(u32 feature_id, u64 value)
{
int ret = 0;
struct ksu_feature_handler *handler;
if (feature_id >= KSU_FEATURE_MAX) {
pr_err("feature: invalid feature_id %u\n", feature_id);
return -EINVAL;
}
mutex_lock(&feature_mutex);
handler = feature_handlers[feature_id];
if (!handler) {
pr_err("feature: feature %u not registered\n", feature_id);
ret = -EOPNOTSUPP;
goto out;
}
if (!handler->set_handler) {
pr_warn("feature: no set_handler for feature %u\n", feature_id);
ret = -EOPNOTSUPP;
goto out;
}
ret = handler->set_handler(value);
if (ret) {
pr_err("feature: set_handler for %u failed: %d\n", feature_id, ret);
}
out:
mutex_unlock(&feature_mutex);
return ret;
}
void ksu_feature_init(void)
{
int i;
for (i = 0; i < KSU_FEATURE_MAX; i++) {
feature_handlers[i] = NULL;
}
pr_info("feature: feature management initialized\n");
}
void ksu_feature_exit(void)
{
int i;
mutex_lock(&feature_mutex);
for (i = 0; i < KSU_FEATURE_MAX; i++) {
if (feature_handlers[i]) {
kfree(feature_handlers[i]);
feature_handlers[i] = NULL;
}
}
mutex_unlock(&feature_mutex);
pr_info("feature: feature management cleaned up\n");
}

35
kernel/feature.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef __KSU_H_FEATURE
#define __KSU_H_FEATURE
#include <linux/types.h>
enum ksu_feature_id {
KSU_FEATURE_SU_COMPAT = 0,
KSU_FEATURE_KERNEL_UMOUNT = 1,
KSU_FEATURE_MAX
};
typedef int (*ksu_feature_get_t)(u64 *value);
typedef int (*ksu_feature_set_t)(u64 value);
struct ksu_feature_handler {
u32 feature_id;
const char *name;
ksu_feature_get_t get_handler;
ksu_feature_set_t set_handler;
};
int ksu_register_feature_handler(const struct ksu_feature_handler *handler);
int ksu_unregister_feature_handler(u32 feature_id);
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported);
int ksu_set_feature(u32 feature_id, u64 value);
void ksu_feature_init(void);
void ksu_feature_exit(void);
#endif // __KSU_H_FEATURE

View File

@@ -8,6 +8,7 @@
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "throne_tracker.h"
@@ -26,6 +27,7 @@ extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
extern void ksu_ksud_init();
extern void ksu_ksud_exit();
extern void ksu_supercalls_init();
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
extern void ksu_trace_register();
extern void ksu_trace_unregister();
@@ -43,6 +45,10 @@ int __init kernelsu_init(void)
pr_alert("*************************************************************");
#endif
ksu_feature_init();
ksu_supercalls_init();
ksu_core_init();
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
@@ -89,6 +95,7 @@ void kernelsu_exit(void)
#endif
ksu_core_exit();
ksu_feature_exit();
}
module_init(kernelsu_init);

View File

@@ -13,6 +13,7 @@
#include "objsec.h"
#include "allowlist.h"
#include "arch.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "kernel_compat.h"
@@ -22,6 +23,44 @@
#define SH_PATH "/system/bin/sh"
extern void escape_to_root();
void ksu_sucompat_enable();
void ksu_sucompat_disable();
bool ksu_su_compat_enabled = true;
static int su_compat_feature_get(u64 *value)
{
*value = ksu_su_compat_enabled ? 1 : 0;
return 0;
}
static int su_compat_feature_set(u64 value)
{
bool enable = value != 0;
if (enable == ksu_su_compat_enabled) {
pr_info("su_compat: no need to change\n");
return 0;
}
if (enable) {
ksu_sucompat_enable();
} else {
ksu_sucompat_disable();
}
ksu_su_compat_enabled = enable;
pr_info("su_compat: set to %d\n", enable);
return 0;
}
static const struct ksu_feature_handler su_compat_handler = {
.feature_id = KSU_FEATURE_SU_COMPAT,
.name = "su_compat",
.get_handler = su_compat_feature_get,
.set_handler = su_compat_feature_set,
};
#ifndef CONFIG_KSU_KPROBES_HOOK
static bool ksu_sucompat_hook_state __read_mostly = true;
@@ -340,7 +379,7 @@ static void destroy_kprobe(struct kprobe **kp_ptr)
#endif
// sucompat: permited process can execute 'su' to gain root access.
void ksu_sucompat_init()
void ksu_sucompat_enable()
{
#ifdef CONFIG_KSU_KPROBES_HOOK
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
@@ -353,7 +392,7 @@ void ksu_sucompat_init()
#endif
}
void ksu_sucompat_exit()
void ksu_sucompat_disable()
{
#ifdef CONFIG_KSU_KPROBES_HOOK
int i;
@@ -365,3 +404,23 @@ void ksu_sucompat_exit()
pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\n");
#endif
}
// sucompat: permited process can execute 'su' to gain root access.
void ksu_sucompat_init()
{
if (ksu_register_feature_handler(&su_compat_handler)) {
pr_err("Failed to register su_compat feature handler\n");
}
if (ksu_su_compat_enabled) {
ksu_sucompat_enable();
}
}
void ksu_sucompat_exit()
{
if (ksu_su_compat_enabled) {
ksu_sucompat_disable();
}
ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT);
}

View File

@@ -11,6 +11,7 @@
#include <linux/version.h>
#include "allowlist.h"
#include "feature.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "manager.h"
@@ -32,29 +33,25 @@ extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
extern void ksu_sucompat_init(void);
extern void ksu_sucompat_exit(void);
// Forward declaration for anon_ksu_fops
static const struct file_operations anon_ksu_fops;
static bool ksu_su_compat_enabled = true;
bool ksu_uid_scanner_enabled = false;
// Permission check functions
bool perm_check_manager(void)
bool only_manager(void)
{
return is_manager();
}
bool perm_check_root(void)
bool only_root(void)
{
return current_uid().val == 0;
}
bool perm_check_basic(void)
bool manager_or_root(void)
{
return current_uid().val == 0 || is_manager();
}
bool perm_check_all(void)
bool always_allow(void)
{
return true; // No permission check
}
@@ -101,6 +98,7 @@ static int do_get_info(void __user *arg)
if (is_manager()) {
cmd.flags |= 0x2;
}
cmd.features = KSU_FEATURE_MAX;
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_version: copy_to_user failed\n");
@@ -318,42 +316,49 @@ static int do_set_app_profile(void __user *arg)
return 0;
}
static int do_is_su_enabled(void __user *arg)
static int do_get_feature(void __user *arg)
{
struct ksu_is_su_enabled_cmd cmd;
struct ksu_get_feature_cmd cmd;
bool supported;
int ret;
cmd.enabled = ksu_su_compat_enabled;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("get_feature: copy_from_user failed\n");
return -EFAULT;
}
ret = ksu_get_feature(cmd.feature_id, &cmd.value, &supported);
cmd.supported = supported ? 1 : 0;
if (ret && supported) {
pr_err("get_feature: failed for feature %u: %d\n", cmd.feature_id, ret);
return ret;
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("is_su_enabled: copy_to_user failed\n");
pr_err("get_feature: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_enable_su(void __user *arg)
static int do_set_feature(void __user *arg)
{
struct ksu_enable_su_cmd cmd;
struct ksu_set_feature_cmd cmd;
int ret;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("enable_su: copy_from_user failed\n");
pr_err("set_feature: copy_from_user failed\n");
return -EFAULT;
}
if (cmd.enable == ksu_su_compat_enabled) {
pr_info("enable_su: no need to change\n");
return 0;
ret = ksu_set_feature(cmd.feature_id, cmd.value);
if (ret) {
pr_err("set_feature: failed for feature %u: %d\n", cmd.feature_id, ret);
return ret;
}
if (cmd.enable) {
ksu_sucompat_init();
} else {
ksu_sucompat_exit();
}
ksu_su_compat_enabled = cmd.enable;
return 0;
}
@@ -517,80 +522,79 @@ static int do_enable_uid_scanner(void __user *arg)
// IOCTL handlers mapping table
static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
{ .cmd = KSU_IOCTL_GRANT_ROOT, .handler = do_grant_root, .perm_check = perm_check_basic, .name = "do_grant_root"},
{ .cmd = KSU_IOCTL_GET_INFO, .handler = do_get_info, .perm_check = perm_check_all, .name = "do_get_info"},
{ .cmd = KSU_IOCTL_REPORT_EVENT, .handler = do_report_event, .perm_check = perm_check_root, .name = "do_report_event"},
{ .cmd = KSU_IOCTL_SET_SEPOLICY, .handler = do_set_sepolicy, .perm_check = perm_check_root, .name = "do_set_sepolicy"},
{ .cmd = KSU_IOCTL_CHECK_SAFEMODE, .handler = do_check_safemode, .perm_check = perm_check_all, .name = "do_check_safemode"},
{ .cmd = KSU_IOCTL_GET_ALLOW_LIST, .handler = do_get_allow_list, .perm_check = perm_check_basic, .name = "do_get_allow_list"},
{ .cmd = KSU_IOCTL_GET_DENY_LIST, .handler = do_get_deny_list, .perm_check = perm_check_basic, .name = "do_get_deny_list"},
{ .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .handler = do_uid_granted_root, .perm_check = perm_check_basic, .name = "do_uid_granted_root"},
{ .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .handler = do_uid_should_umount, .perm_check = perm_check_basic, .name = "do_uid_should_umount"},
{ .cmd = KSU_IOCTL_GET_MANAGER_UID, .handler = do_get_manager_uid, .perm_check = perm_check_basic, .name = "do_get_manager_uid"},
{ .cmd = KSU_IOCTL_GET_APP_PROFILE, .handler = do_get_app_profile, .perm_check = perm_check_manager, .name = "do_get_app_profile"},
{ .cmd = KSU_IOCTL_SET_APP_PROFILE, .handler = do_set_app_profile, .perm_check = perm_check_manager, .name = "do_set_app_profile"},
{ .cmd = KSU_IOCTL_IS_SU_ENABLED, .handler = do_is_su_enabled, .perm_check = perm_check_manager, .name = "do_is_su_enabled"},
{ .cmd = KSU_IOCTL_ENABLE_SU, .handler = do_enable_su, .perm_check = perm_check_manager, .name = "do_enable_su"},
{ .cmd = KSU_IOCTL_GET_FULL_VERSION, .handler = do_get_full_version, .perm_check = perm_check_manager, .name = "do_get_full_version"},
{ .cmd = KSU_IOCTL_HOOK_TYPE, .handler = do_get_hook_type, .perm_check = perm_check_basic, .name = "do_get_hook_type"},
{ .cmd = KSU_IOCTL_ENABLE_KPM, .handler = do_enable_kpm, .perm_check = perm_check_basic, .name = "do_enable_kpm"},
{ .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .handler = do_dynamic_manager, .perm_check = perm_check_basic, .name = "do_dynamic_manager"},
{ .cmd = KSU_IOCTL_GET_MANAGERS, .handler = do_get_managers, .perm_check = perm_check_basic, .name = "do_get_managers"},
{ .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .handler = do_enable_uid_scanner, .perm_check = perm_check_basic, .name = "do_enable_uid_scanner"},
{ .cmd = 0, .handler = NULL, .perm_check = NULL, .name = NULL} // Sentinel
{ .cmd = KSU_IOCTL_GRANT_ROOT, .name = "GRANT_ROOT", .handler = do_grant_root, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_GET_INFO, .name = "GET_INFO", .handler = do_get_info, .perm_check = always_allow },
{ .cmd = KSU_IOCTL_REPORT_EVENT, .name = "REPORT_EVENT", .handler = do_report_event, .perm_check = only_root },
{ .cmd = KSU_IOCTL_SET_SEPOLICY, .name = "SET_SEPOLICY", .handler = do_set_sepolicy, .perm_check = only_root },
{ .cmd = KSU_IOCTL_CHECK_SAFEMODE, .name = "CHECK_SAFEMODE", .handler = do_check_safemode, .perm_check = always_allow },
{ .cmd = KSU_IOCTL_GET_ALLOW_LIST, .name = "GET_ALLOW_LIST", .handler = do_get_allow_list, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_GET_DENY_LIST, .name = "GET_DENY_LIST", .handler = do_get_deny_list, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .name = "UID_GRANTED_ROOT", .handler = do_uid_granted_root, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .name = "UID_SHOULD_UMOUNT", .handler = do_uid_should_umount, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_GET_MANAGER_UID, .name = "GET_MANAGER_UID", .handler = do_get_manager_uid, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_GET_APP_PROFILE, .name = "GET_APP_PROFILE", .handler = do_get_app_profile, .perm_check = only_manager },
{ .cmd = KSU_IOCTL_SET_APP_PROFILE, .name = "SET_APP_PROFILE", .handler = do_set_app_profile, .perm_check = only_manager },
{ .cmd = KSU_IOCTL_GET_FEATURE, .name = "GET_FEATURE", .handler = do_get_feature, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root },
{ .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow},
{ .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root},
{ .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root},
{ .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .name = "SET_DYNAMIC_MANAGER", .handler = do_dynamic_manager, .perm_check = manager_or_root},
{ .cmd = KSU_IOCTL_GET_MANAGERS, .name = "GET_MANAGERS", .handler = do_get_managers, .perm_check = manager_or_root},
{ .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .name = "SET_ENABLE_UID_SCANNER", .handler = do_enable_uid_scanner, .perm_check = manager_or_root},
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine
};
void ksu_supercalls_init(void)
{
int i;
pr_info("KernelSU IOCTL Commands:\n");
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
pr_info(" %-18s = 0x%08x\n", ksu_ioctl_handlers[i].name, ksu_ioctl_handlers[i].cmd);
}
}
static inline void ksu_ioctl_audit(unsigned int cmd, const char *cmd_name, uid_t uid, int ret)
{
#if __SULOG_GATE
const char *result = (ret == 0) ? "SUCCESS" :
(ret == -EPERM) ? "DENIED" : "FAILED";
ksu_sulog_report_syscall(uid, NULL, cmd_name, result);
#endif
}
// IOCTL dispatcher
static long anon_ksu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int i;
const char *cmd_name = "unknown";
int ret = -ENOTTY;
#ifdef CONFIG_KSU_DEBUG
pr_info("ksu ioctl: cmd=0x%x from uid=%d\n", cmd, current_uid().val);
#endif
// Determine the command name based on the cmd value
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
if (cmd == ksu_ioctl_handlers[i].cmd) {
cmd_name = ksu_ioctl_handlers[i].name;
break;
// Check permission first
if (ksu_ioctl_handlers[i].perm_check &&
!ksu_ioctl_handlers[i].perm_check()) {
pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n",
cmd, current_uid().val);
ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name,
current_uid().val, -EPERM);
return -EPERM;
}
// Execute handler
int ret = ksu_ioctl_handlers[i].handler(argp);
ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name,
current_uid().val, ret);
return ret;
}
}
// Check permission first
if (ksu_ioctl_handlers[i].perm_check &&
!ksu_ioctl_handlers[i].perm_check()) {
pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n",
cmd, current_uid().val);
#if __SULOG_GATE
ksu_sulog_report_syscall(current_uid().val, NULL, cmd_name, "DENIED");
#endif
return -EPERM;
}
// Execute handler
ret = ksu_ioctl_handlers[i].handler(argp);
// Log the result of the ioctl command
if (ret == 0) {
#if __SULOG_GATE
ksu_sulog_report_syscall(current_uid().val, NULL, cmd_name, "SUCCESS");
#endif
} else {
#if __SULOG_GATE
ksu_sulog_report_syscall(current_uid().val, NULL, cmd_name, "FAILED");
#endif
}
if (ksu_ioctl_handlers[i].handler == NULL) {
pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd);
ret = -ENOTTY;
}
return ret;
pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd);
return -ENOTTY;
}
// File release handler

View File

@@ -18,6 +18,7 @@ struct ksu_become_daemon_cmd {
struct ksu_get_info_cmd {
__u32 version; // Output: KERNEL_SU_VERSION
__u32 flags; // Output: flags (bit 0: MODULE mode)
__u32 features; // Output: max feature ID supported
};
struct ksu_report_event_cmd {
@@ -61,12 +62,15 @@ struct ksu_set_app_profile_cmd {
struct app_profile profile; // Input: app profile structure
};
struct ksu_is_su_enabled_cmd {
__u8 enabled; // Output: true if su compat enabled
struct ksu_get_feature_cmd {
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
__u64 value; // Output: feature value/state
__u8 supported; // Output: true if feature is supported, false otherwise
};
struct ksu_enable_su_cmd {
__u8 enable; // Input: true to enable, false to disable
struct ksu_set_feature_cmd {
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
__u64 value; // Input: feature value/state to set
};
// Other command structures
@@ -109,8 +113,8 @@ struct ksu_enable_uid_scanner_cmd {
#define KSU_IOCTL_GET_MANAGER_UID _IOR('K', 10, struct ksu_get_manager_uid_cmd)
#define KSU_IOCTL_GET_APP_PROFILE _IOWR('K', 11, struct ksu_get_app_profile_cmd)
#define KSU_IOCTL_SET_APP_PROFILE _IOW('K', 12, struct ksu_set_app_profile_cmd)
#define KSU_IOCTL_IS_SU_ENABLED _IOR('K', 13, struct ksu_is_su_enabled_cmd)
#define KSU_IOCTL_ENABLE_SU _IOW('K', 14, struct ksu_enable_su_cmd)
#define KSU_IOCTL_GET_FEATURE _IOWR('K', 13, struct ksu_get_feature_cmd)
#define KSU_IOCTL_SET_FEATURE _IOW('K', 14, struct ksu_set_feature_cmd)
// Other IOCTL command definitions
#define KSU_IOCTL_GET_FULL_VERSION _IOR('K', 100, struct ksu_get_full_version_cmd)
#define KSU_IOCTL_HOOK_TYPE _IOR('K', 101, struct ksu_hook_type_cmd)
@@ -123,18 +127,12 @@ struct ksu_enable_uid_scanner_cmd {
typedef int (*ksu_ioctl_handler_t)(void __user *arg);
typedef bool (*ksu_perm_check_t)(void);
// Permission check functions
bool perm_check_manager(void);
bool perm_check_root(void);
bool perm_check_basic(void);
bool perm_check_all(void);
// IOCTL command mapping
struct ksu_ioctl_cmd_map {
unsigned int cmd;
const char *name;
ksu_ioctl_handler_t handler;
ksu_perm_check_t perm_check; // Permission check function
const char *name; // Command name for logging
};
// Install KSU fd to current process