From 51e6a1b6c78d0e62db61fa18c2d7eb43948de0aa Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Mon, 29 Sep 2025 06:50:39 +0800 Subject: [PATCH] kernel: Add `CONFIG_KSU_MANUAL_SU` configuration - Use random passphrase protection for manual su functionality --- kernel/Kconfig | 7 +++++++ kernel/Makefile | 13 +++++++++++++ kernel/allowlist.c | 2 ++ kernel/allowlist.h | 2 ++ kernel/core_hook.c | 17 +++++++++++++++-- kernel/ksu.h | 2 ++ kernel/manual_su.c | 12 ++++++++---- 7 files changed, 49 insertions(+), 6 deletions(-) diff --git a/kernel/Kconfig b/kernel/Kconfig index 2bd538f1..04c7ce1e 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -31,6 +31,13 @@ config KSU_THRONE_TRACKER_LEGACY This is kept for Ultra-Legacy Linux 4.4-3.X kernels which are prone to deadlocks. Enable this if default scanning deadlocks/crashes on you. +config KSU_MANUAL_SU + bool "Use manual su" + depends on KSU + default y + help + Use manual su and authorize the corresponding command line and application via prctl + config KSU_ALLOWLIST_WORKAROUND bool "KernelSU Session Keyring Init workaround" depends on KSU diff --git a/kernel/Makefile b/kernel/Makefile index 1922518d..40ce8384 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,9 @@ kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o kernelsu-objs += throne_comm.o +ifeq ($(CONFIG_KSU_MANUAL_SU), y) kernelsu-objs += manual_su.o +endif ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) kernelsu-objs += ksu_trace.o @@ -114,6 +116,17 @@ else $(info -- KPM is disabled) endif +ifeq ($(CONFIG_KSU_MANUAL_SU), y) +KSU_PW_POOL := abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 +KSU_PW_LEN := $(shell awk 'BEGIN{srand(); print int(rand()*9)+8}') +KSU_SU_PASSWORD := $(shell \ + tr -dc '$(KSU_PW_POOL)' selinux_domain); } +#ifdef CONFIG_KSU_MANUAL_SU void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { struct cred *newcreds; @@ -364,6 +368,7 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); } +#endif int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry) { @@ -479,7 +484,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, if (!current->mm || current->in_execve) { return 0; } - +#ifdef CONFIG_KSU_MANUAL_SU if (arg2 == CMD_SU_ESCALATION_REQUEST) { uid_t target_uid = (uid_t)arg3; struct su_request_arg __user *user_req = (struct su_request_arg __user *)arg4; @@ -518,7 +523,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, pr_err("prctl: CMD_ADD_PENDING_ROOT reply error\n"); return 0; } - +#endif if (!from_root && !from_manager && !(is_allow_su() && is_system_bin_su())) { // only root or manager can access this interface @@ -1637,6 +1642,7 @@ int ksu_inode_permission(struct inode *inode, int mask) return 0; } +#ifdef CONFIG_KSU_MANUAL_SU static void ksu_try_escalate_for_uid(uid_t uid) { if (!is_pending_root(uid)) @@ -1645,6 +1651,7 @@ static void ksu_try_escalate_for_uid(uid_t uid) pr_info("pending_root: UID=%d temporarily allowed\n", uid); remove_pending_root(uid); } +#endif #ifdef CONFIG_COMPAT bool ksu_is_compat __read_mostly = false; @@ -1671,18 +1678,22 @@ int ksu_bprm_check(struct linux_binprm *bprm) ksu_handle_pre_ksud(filename); +#ifdef CONFIG_KSU_MANUAL_SU ksu_try_escalate_for_uid(current_uid().val); +#endif return 0; } +#ifdef CONFIG_KSU_MANUAL_SU static int ksu_task_alloc(struct task_struct *task, unsigned long clone_flags) { ksu_try_escalate_for_uid(task_uid(task).val); return 0; } +#endif static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) @@ -1702,7 +1713,9 @@ static struct security_hook_list ksu_hooks[] = { LSM_HOOK_INIT(inode_rename, ksu_inode_rename), LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid), LSM_HOOK_INIT(inode_permission, ksu_inode_permission), +#ifdef CONFIG_KSU_MANUAL_SU LSM_HOOK_INIT(task_alloc, ksu_task_alloc), +#endif #ifndef CONFIG_KSU_KPROBES_HOOK LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check), #endif diff --git a/kernel/ksu.h b/kernel/ksu.h index 1610da5a..cdf3cb15 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -24,8 +24,10 @@ #define CMD_IS_SU_ENABLED 14 #define CMD_ENABLE_SU 15 +#ifdef CONFIG_KSU_MANUAL_SU #define CMD_SU_ESCALATION_REQUEST 50 #define CMD_ADD_PENDING_ROOT 51 +#endif #define CMD_GET_FULL_VERSION 0xC0FFEE1A diff --git a/kernel/manual_su.c b/kernel/manual_su.c index 9a87b21a..2f749cb8 100644 --- a/kernel/manual_su.c +++ b/kernel/manual_su.c @@ -12,7 +12,7 @@ #include "manager.h" #include "allowlist.h" -static const char *ksu_su_password = "zakozako"; +static const char *ksu_su_password = KSU_SU_PASSWORD; extern void escape_to_root_for_cmd_su(uid_t, pid_t); #define MAX_PENDING 16 #define REMOVE_DELAY_CALLS 150 @@ -42,12 +42,16 @@ int ksu_manual_su_escalate(uid_t target_uid, pid_t target_pid, return -EACCES; } char buf[64]; - if (strncpy_from_user(buf, user_password, sizeof(buf) - 1) < 0) + long copied; + + copied = ksu_strncpy_from_user_retry(buf, user_password, sizeof(buf) - 1); + if (copied < 0) return -EFAULT; - buf[sizeof(buf) - 1] = '\0'; + + buf[copied] = '\0'; if (strcmp(buf, ksu_su_password) != 0) { - pr_warn("manual_su: wrong password\n"); + pr_warn("manual_su: wrong password (input=%s, expect=%s)\n", buf, ksu_su_password); return -EACCES; }