From 088ce97697a7a7e3e1b2643aef23d7986057bad9 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:53:54 +0800 Subject: [PATCH] kernel: Remove prctl; use netlink communication to control manual_su --- kernel/Makefile | 3 +- kernel/core_hook.c | 116 +++------------------------------------ kernel/ksu.h | 4 -- kernel/ksu_netlink.c | 119 ++++++++++++++++++++++++++++++++++++++++ kernel/ksu_netlink.h | 23 ++++++++ kernel/throne_tracker.c | 10 ++-- 6 files changed, 158 insertions(+), 117 deletions(-) create mode 100644 kernel/ksu_netlink.c create mode 100644 kernel/ksu_netlink.h diff --git a/kernel/Makefile b/kernel/Makefile index 1c67ea10..e640f387 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -13,6 +13,7 @@ kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o +kernelsu-objs += ksu_netlink.o ifeq ($(CONFIG_KSU_MANUAL_SU), y) ccflags-y += -DCONFIG_KSU_MANUAL_SU @@ -166,7 +167,7 @@ ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS endif ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -ccflags-y += -Wno-declaration-after-statement -Wno-unused-function +ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable all: make -C $(KDIR) M=$(MDIR) modules diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 5b7560ca..0f0f2ab7 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -389,81 +389,6 @@ bool is_system_uid(void) return caller_uid <= 2000; } -#if __SULOG_GATE -static void sulog_prctl_cmd(uid_t uid, unsigned long cmd) -{ - const char *name = NULL; - - switch (cmd) { - -#ifdef CONFIG_KSU_MANUAL_SU - case CMD_MANUAL_SU_REQUEST: name = "prctl_manual_su_request"; break; -#endif - - default: name = "prctl_unknown"; break; - } - - ksu_sulog_report_syscall(uid, NULL, name, NULL); -} -#endif - -int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) -{ - // if success, we modify the arg5 as result! - __maybe_unused u32 *result = (u32 *)arg5; - __maybe_unused u32 reply_ok = KERNEL_SU_OPTION; - - if (likely(ksu_is_current_proc_umounted())) - return 0; // prevent side channel attack in ksu side - - if (KERNEL_SU_OPTION != option) - return 0; - -#if __SULOG_GATE - sulog_prctl_cmd(current_uid().val, arg2); -#endif - - if (!is_system_uid()) { - return 0; - } - -#ifdef CONFIG_KSU_DEBUG - pr_info("option: 0x%x, cmd: %ld\n", option, arg2); -#endif - -#ifdef CONFIG_KSU_MANUAL_SU - if (arg2 == CMD_MANUAL_SU_REQUEST) { - struct manual_su_request request; - int su_option = (int)arg3; - - if (copy_from_user(&request, (void __user *)arg4, sizeof(request))) { - pr_err("manual_su: failed to copy request from user\n"); - return 0; - } - - int ret = ksu_handle_manual_su_request(su_option, &request); - - // Copy back result for token generation - if (ret == 0 && su_option == MANUAL_SU_OP_GENERATE_TOKEN) { - if (copy_to_user((void __user *)arg4, &request, sizeof(request))) { - pr_err("manual_su: failed to copy request back to user\n"); - return 0; - } - } - - if (ret == 0) { - if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) { - pr_err("manual_su: prctl reply error\n"); - } - } - return 0; - } -#endif - - return 0; -} - static bool is_appuid(kuid_t uid) { #define PER_USER_RANGE 100000 @@ -723,26 +648,7 @@ static struct kprobe cap_task_fix_setuid_kp = { .pre_handler = cap_task_fix_setuid_handler_pre, }; -// 3. prctl hook for handling ksu prctl commands -static int handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int option = (int)PT_REGS_PARM1(real_regs); - unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs); - unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs); - // PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall - unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); - unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs); - - return ksu_handle_prctl(option, arg2, arg3, arg4, arg5); -} - -static struct kprobe prctl_kp = { - .symbol_name = PRCTL_SYMBOL, - .pre_handler = handler_pre, -}; - -// 4.inode_permission hook for handling devpts +// 3.inode_permission hook for handling devpts static int ksu_inode_permission_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct inode *inode = (struct inode *)PT_REGS_PARM1(regs); @@ -761,7 +667,7 @@ static struct kprobe ksu_inode_permission_kp = { }; -// 5. bprm_check_security hook for handling ksud compatibility +// 4. bprm_check_security hook for handling ksud compatibility static int ksu_bprm_check_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct linux_binprm *bprm = (struct linux_binprm *)PT_REGS_PARM1(regs); @@ -797,7 +703,7 @@ static struct kprobe ksu_bprm_check_kp = { }; #ifdef CONFIG_KSU_MANUAL_SU -// 6. task_alloc hook for handling manual su escalation +// 5. task_alloc hook for handling manual su escalation static int ksu_task_alloc_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct task_struct *task = (struct task_struct *)PT_REGS_PARM1(regs); @@ -831,15 +737,6 @@ __maybe_unused int ksu_kprobe_init(void) } else { pr_info("cap_task_fix_setuid_kp kprobe registered successfully\n"); } - - - // Register prctl kprobe - rc = register_kprobe(&prctl_kp); - if (rc) { - pr_info("prctl kprobe failed: %d.\n", rc); - } else { - pr_info("prctl kprobe registered successfully.\n"); - } // Register inode_permission kprobe rc = register_kprobe(&ksu_inode_permission_kp); @@ -874,7 +771,6 @@ __maybe_unused int ksu_kprobe_exit(void) { unregister_kprobe(&reboot_kp); unregister_kprobe(&cap_task_fix_setuid_kp); - unregister_kprobe(&prctl_kp); unregister_kprobe(&ksu_inode_permission_kp); unregister_kprobe(&ksu_bprm_check_kp); #ifdef CONFIG_KSU_MANUAL_SU @@ -894,6 +790,9 @@ void __init ksu_core_init(void) if (ksu_register_feature_handler(&kernel_umount_handler)) { pr_err("Failed to register umount feature handler\n"); } +#ifdef CONFIG_KSU_MANUAL_SU + ksu_netlink_init(); +#endif } void ksu_core_exit(void) @@ -908,4 +807,7 @@ void ksu_core_exit(void) ksu_kprobe_exit(); #endif ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT); +#ifdef CONFIG_KSU_MANUAL_SU + ksu_netlink_exit(); +#endif } diff --git a/kernel/ksu.h b/kernel/ksu.h index cb36e35a..302fb935 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -9,10 +9,6 @@ extern bool ksu_uid_scanner_enabled; -#ifdef CONFIG_KSU_MANUAL_SU -#define CMD_MANUAL_SU_REQUEST 50 -#endif - #define EVENT_POST_FS_DATA 1 #define EVENT_BOOT_COMPLETED 2 #define EVENT_MODULE_MOUNTED 3 diff --git a/kernel/ksu_netlink.c b/kernel/ksu_netlink.c new file mode 100644 index 00000000..230416bf --- /dev/null +++ b/kernel/ksu_netlink.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include "ksu_netlink.h" +#include "manual_su.h" +#include "ksu.h" + +static struct sock *ksu_nl_sock = NULL; + +extern int ksu_handle_manual_su_request(int option, struct manual_su_request *request); + +static void ksu_netlink_recv_msg(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct ksu_netlink_msg *msg; + struct ksu_netlink_msg reply; + struct sk_buff *skb_out; + int msg_size; + int res; + u32 pid; + + if (!skb) { + pr_err("ksu_netlink: received NULL skb\n"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + pid = nlh->nlmsg_pid; + + if (!nlh || nlh->nlmsg_len < NLMSG_HDRLEN + sizeof(struct ksu_netlink_msg)) { + pr_err("ksu_netlink: invalid message size\n"); + return; + } + + msg = (struct ksu_netlink_msg *)nlmsg_data(nlh); + + if (msg->cmd != KSU_NETLINK_CMD_MANUAL_SU) { + pr_warn("ksu_netlink: unknown command %d\n", msg->cmd); + return; + } + + pr_info("ksu_netlink: received manual_su request, option=%d, uid=%d, pid=%d\n", + msg->option, msg->target_uid, msg->target_pid); + + memset(&reply, 0, sizeof(reply)); + reply.cmd = msg->cmd; + reply.option = msg->option; + reply.target_uid = msg->target_uid; + reply.target_pid = msg->target_pid; + + struct manual_su_request request = { + .target_uid = msg->target_uid, + .target_pid = msg->target_pid + }; + + if (msg->option == MANUAL_SU_OP_GENERATE_TOKEN || + msg->option == MANUAL_SU_OP_ESCALATE) { + memcpy(request.token_buffer, msg->token_buffer, KSU_TOKEN_LENGTH + 1); + } + + res = ksu_handle_manual_su_request(msg->option, &request); + + reply.result = res; + if (msg->option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) { + memcpy(reply.token_buffer, request.token_buffer, KSU_TOKEN_LENGTH + 1); + } + + msg_size = sizeof(struct ksu_netlink_msg); + skb_out = nlmsg_new(msg_size, GFP_KERNEL); + if (!skb_out) { + pr_err("ksu_netlink: failed to allocate reply skb\n"); + return; + } + + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + if (!nlh) { + pr_err("ksu_netlink: nlmsg_put failed\n"); + kfree_skb(skb_out); + return; + } + + NETLINK_CB(skb_out).dst_group = 0; + memcpy(nlmsg_data(nlh), &reply, sizeof(reply)); + + res = nlmsg_unicast(ksu_nl_sock, skb_out, pid); + if (res < 0) { + pr_err("ksu_netlink: failed to send reply: %d\n", res); + } else { + pr_info("ksu_netlink: reply sent successfully\n"); + } +} + +int ksu_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = ksu_netlink_recv_msg, + }; + + ksu_nl_sock = netlink_kernel_create(&init_net, KSU_NETLINK_PROTOCOL, &cfg); + if (!ksu_nl_sock) { + pr_err("ksu_netlink: failed to create netlink socket\n"); + return -ENOMEM; + } + + pr_info("ksu_netlink: initialized with protocol %d\n", KSU_NETLINK_PROTOCOL); + return 0; +} + +void ksu_netlink_exit(void) +{ + if (ksu_nl_sock) { + netlink_kernel_release(ksu_nl_sock); + ksu_nl_sock = NULL; + pr_info("ksu_netlink: released\n"); + } +} diff --git a/kernel/ksu_netlink.h b/kernel/ksu_netlink.h new file mode 100644 index 00000000..bbfa2c3f --- /dev/null +++ b/kernel/ksu_netlink.h @@ -0,0 +1,23 @@ +#ifndef __KSU_NETLINK_H +#define __KSU_NETLINK_H + +#include +#include +#include + +#define KSU_NETLINK_PROTOCOL 2 +#define KSU_NETLINK_CMD_MANUAL_SU 50 + +struct ksu_netlink_msg { + int cmd; + int option; + uid_t target_uid; + pid_t target_pid; + char token_buffer[33]; + int result; +}; + +int ksu_netlink_init(void); +void ksu_netlink_exit(void); + +#endif diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index 47e2c371..ca491309 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -430,11 +430,11 @@ void track_throne(void) { struct list_head uid_list; struct uid_data *np, *n; - __maybe_unused struct file *fp; - __maybe_unused char chr = 0; - __maybe_unused loff_t pos = 0; - __maybe_unused loff_t line_start = 0; - __maybe_unused char buf[KSU_MAX_PACKAGE_NAME]; + struct file *fp; + char chr = 0; + loff_t pos = 0; + loff_t line_start = 0; + char buf[KSU_MAX_PACKAGE_NAME]; static bool manager_exist = false; static bool dynamic_manager_exist = false; int current_manager_uid = ksu_get_manager_uid() % 100000;