From 9f869090d2a3b567a62c5356ecd8b449b634fbad Mon Sep 17 00:00:00 2001 From: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Date: Thu, 13 Nov 2025 19:50:54 +0800 Subject: [PATCH] kernel: refine syscall_hook_manager - Don't unmark process when setuid if syscall tracepoint is in use - Remark process when app profile updated - Ensure zygote is marked on first boot --- kernel/allowlist.c | 6 ++- kernel/ksud.c | 1 - kernel/selinux/selinux.c | 13 ++++++- kernel/selinux/selinux.h | 2 + kernel/setuid_hook.c | 2 +- kernel/syscall_hook_manager.c | 70 +++++++++++++++++++++++------------ kernel/syscall_hook_manager.h | 2 + 7 files changed, 68 insertions(+), 28 deletions(-) diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 568809e5..0cf994eb 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -18,6 +18,7 @@ #include "selinux/selinux.h" #include "allowlist.h" #include "manager.h" +#include "syscall_hook_manager.h" #define FILE_MAGIC 0x7f4b5355 // ' KSU', u32 #define FILE_FORMAT_VERSION 3 // u32 @@ -256,8 +257,11 @@ out: sizeof(default_root_profile)); } - if (persist) + if (persist) { persistent_allow_list(); + // FIXME: use a new flag + ksu_mark_running_process(); + } return result; } diff --git a/kernel/ksud.c b/kernel/ksud.c index 80430b1e..08b2d5b3 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -128,7 +128,6 @@ void on_boot_completed(void){ pr_info("on_boot_completed!\n"); // remark process, we don't want to mark other init // forked process excepte zygote and adbd - ksu_unmark_all_process(); ksu_mark_running_process(); } diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 0e007fc9..dfc48313 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -111,7 +111,7 @@ bool is_ksu_domain() return is_task_ksu_domain(current_cred()); } -bool is_zygote(const struct cred* cred) +bool is_context(const struct cred* cred, const char* context) { if (!cred) { return false; @@ -126,11 +126,20 @@ bool is_zygote(const struct cred* cred) if (err) { return false; } - result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0; + result = strncmp(context, ctx.context, ctx.len) == 0; __security_release_secctx(&ctx); return result; } +bool is_zygote(const struct cred* cred) +{ + return is_context(cred, "u:r:zygote:s0"); +} + +bool is_init(const struct cred* cred) { + return is_context(cred, "u:r:init:s0"); +} + #define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0" u32 ksu_get_ksu_file_sid() diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h index 37c82bfa..431e0441 100644 --- a/kernel/selinux/selinux.h +++ b/kernel/selinux/selinux.h @@ -17,6 +17,8 @@ bool is_ksu_domain(); bool is_zygote(const struct cred* cred); +bool is_init(const struct cred* cred); + void apply_kernelsu_rules(); u32 ksu_get_ksu_file_sid(); diff --git a/kernel/setuid_hook.c b/kernel/setuid_hook.c index b49cef18..df513826 100644 --- a/kernel/setuid_hook.c +++ b/kernel/setuid_hook.c @@ -131,7 +131,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) } ksu_set_task_tracepoint_flag(current); } else { - ksu_clear_task_tracepoint_flag(current); + ksu_clear_task_tracepoint_flag_if_needed(current); } #else if (ksu_is_allow_uid_for_current(new_uid)) { diff --git a/kernel/syscall_hook_manager.c b/kernel/syscall_hook_manager.c index d39b5959..65430600 100644 --- a/kernel/syscall_hook_manager.c +++ b/kernel/syscall_hook_manager.c @@ -20,9 +20,21 @@ #include "selinux/selinux.h" // Tracepoint registration count management +// == 1: just us +// > 1: someone else is also using syscall tracepoint e.g. ftrace static int tracepoint_reg_count = 0; static DEFINE_SPINLOCK(tracepoint_reg_lock); +void ksu_clear_task_tracepoint_flag_if_needed(struct task_struct *t) +{ + unsigned long flags; + spin_lock_irqsave(&tracepoint_reg_lock, flags); + if (tracepoint_reg_count <= 1) { + ksu_clear_task_tracepoint_flag(t); + } + spin_unlock_irqrestore(&tracepoint_reg_lock, flags); +} + // Process marking management static void handle_process_mark(bool mark) { @@ -49,7 +61,7 @@ void ksu_unmark_all_process(void) pr_info("hook_manager: unmark all user process done!\n"); } -void ksu_mark_running_process(void) +static void ksu_mark_running_process_locked() { struct task_struct *p, *t; read_lock(&tasklist_lock); @@ -70,12 +82,28 @@ void ksu_mark_running_process(void) ksu_set_task_tracepoint_flag(t); pr_info("hook_manager: mark process: pid:%d, uid: %d, comm:%s\n", t->pid, uid, t->comm); + } else { + ksu_clear_task_tracepoint_flag(t); + pr_info("hook_manager: unmark process: pid:%d, uid: %d, comm:%s\n", + t->pid, uid, t->comm); } put_cred(cred); } read_unlock(&tasklist_lock); } +void ksu_mark_running_process() +{ + unsigned long flags; + spin_lock_irqsave(&tracepoint_reg_lock, flags); + if (tracepoint_reg_count <= 1) { + ksu_mark_running_process_locked(); + } else { + pr_info("hook_manager: not mark running process since syscall tracepoint is in use\n"); + } + spin_unlock_irqrestore(&tracepoint_reg_lock, flags); +} + // Get task mark status // Returns: 1 if marked, 0 if not marked, -ESRCH if task not found int ksu_get_task_mark(pid_t pid) @@ -169,10 +197,9 @@ static int syscall_regfunc_handler(struct kretprobe_instance *ri, struct pt_regs spin_lock_irqsave(&tracepoint_reg_lock, flags); if (tracepoint_reg_count < 1) { // while install our tracepoint, mark our processes - ksu_unmark_all_process(); - ksu_mark_running_process(); - } else { - // while installing other tracepoint, mark all processes + ksu_mark_running_process_locked(); + } else if (tracepoint_reg_count == 1) { + // while other tracepoint first added, mark all processes ksu_mark_all_process(); } tracepoint_reg_count++; @@ -184,15 +211,14 @@ static int syscall_unregfunc_handler(struct kretprobe_instance *ri, struct pt_re { unsigned long flags; spin_lock_irqsave(&tracepoint_reg_lock, flags); - if (tracepoint_reg_count <= 1) { - // while uninstall our tracepoint, unmark all processes - ksu_unmark_all_process(); - } else { - // while uninstalling other tracepoint, mark our processes - ksu_unmark_all_process(); - ksu_mark_running_process(); - } tracepoint_reg_count--; + if (tracepoint_reg_count <= 0) { + // while no tracepoint left, unmark all processes + ksu_unmark_all_process(); + } else if (tracepoint_reg_count == 1) { + // while just our tracepoint left, unmark disallowed processes + ksu_mark_running_process_locked(); + } spin_unlock_irqrestore(&tracepoint_reg_lock, flags); return 0; } @@ -216,20 +242,19 @@ static inline bool check_syscall_fastpath(int nr) } } -int ksu_handle_init_mark_tracker(const char __user **filename_user, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) +// Unmark init's child that are not zygote or adbd +int ksu_handle_init_mark_tracker(const char __user **filename_user) { char path[64]; if (unlikely(!filename_user)) return 0; - + memset(path, 0, sizeof(path)); strncpy_from_user_nofault(path, *filename_user, sizeof(path)); - if (likely(strstr(path, "adbd") == NULL)){ - ksu_clear_task_tracepoint_flag(current); + if (likely(strstr(path, "/app_process") == NULL && strstr(path, "/adbd") == NULL)) { + ksu_clear_task_tracepoint_flag_if_needed(current); } return 0; @@ -273,8 +298,8 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id) if (id == __NR_execve) { const char __user **filename_user = (const char __user **)&PT_REGS_PARM1(regs); - if (current->pid == 1) { - ksu_handle_init_mark_tracker(filename_user, NULL, NULL, NULL); + if (current->pid != 1 && is_init(get_current_cred())) { + ksu_handle_init_mark_tracker(filename_user); } else { ksu_handle_execve_sucompat(filename_user, NULL, NULL, NULL); } @@ -316,8 +341,7 @@ void ksu_syscall_hook_manager_init(void) #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS ret = register_trace_sys_enter(ksu_sys_enter_handler, NULL); #ifndef CONFIG_KRETPROBES - ksu_unmark_all_process(); - ksu_mark_running_process(); + ksu_mark_running_process_locked(); #endif if (ret) { pr_err("hook_manager: failed to register sys_enter tracepoint: %d\n", ret); diff --git a/kernel/syscall_hook_manager.h b/kernel/syscall_hook_manager.h index a9c5b13f..90245c22 100644 --- a/kernel/syscall_hook_manager.h +++ b/kernel/syscall_hook_manager.h @@ -42,4 +42,6 @@ static inline void ksu_clear_task_tracepoint_flag(struct task_struct *t) #endif } +void ksu_clear_task_tracepoint_flag_if_needed(struct task_struct *t); + #endif