From 5df821ed41d14145d1f483d384af487ff9ca35bd Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:55:06 +0800 Subject: [PATCH] kernel: Resolved potential deadlock issues arising from operations not being performed within locks. --- kernel/app_profile.c | 46 +++++++++++++++----------------------------- kernel/app_profile.h | 2 +- kernel/setuid_hook.c | 2 +- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/kernel/app_profile.c b/kernel/app_profile.c index ca356b07..9567e3dc 100644 --- a/kernel/app_profile.c +++ b/kernel/app_profile.c @@ -62,10 +62,9 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) put_group_info(group_info); } -void disable_seccomp(struct task_struct *tsk) +void disable_seccomp(void) { - assert_spin_locked(&tsk->sighand->siglock); - + assert_spin_locked(¤t->sighand->siglock); // disable seccomp #if defined(CONFIG_GENERIC_ENTRY) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) @@ -75,20 +74,10 @@ void disable_seccomp(struct task_struct *tsk) #endif #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = 0; - if (tsk->seccomp.filter) { - // 5.9+ have filter_count and use seccomp_filter_release -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - seccomp_filter_release(tsk); - atomic_set(&tsk->seccomp.filter_count, 0); + current->seccomp.mode = 0; + current->seccomp.filter = NULL; + atomic_set(¤t->seccomp.filter_count, 0); #else - // for 6.11+ kernel support? -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) - put_seccomp_filter(tsk); -#endif - tsk->seccomp.filter = NULL; -#endif - } #endif } @@ -148,7 +137,7 @@ void escape_with_root_profile(void) // Refer to kernel/seccomp.c: seccomp_set_mode_strict // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(current); + disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); setup_selinux(profile->selinux_domain); @@ -198,23 +187,19 @@ static int __manual_su_handle_devpts(struct inode *inode) static void disable_seccomp_for_task(struct task_struct *tsk) { - if (!tsk->seccomp.filter && tsk->seccomp.mode == SECCOMP_MODE_DISABLED) - return; - - if (WARN_ON(!spin_is_locked(&tsk->sighand->siglock))) - return; - + assert_spin_locked(&tsk->sighand->siglock); #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = 0; + if (tsk->seccomp.mode == SECCOMP_MODE_DISABLED && !tsk->seccomp.filter) + return; +#endif + clear_tsk_thread_flag(tsk, TIF_SECCOMP); +#ifdef CONFIG_SECCOMP + tsk->seccomp.mode = SECCOMP_MODE_DISABLED; if (tsk->seccomp.filter) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) seccomp_filter_release(tsk); - atomic_set(&tsk->seccomp.filter_count, 0); #else - // for 6.11+ kernel support? -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) put_seccomp_filter(tsk); -#endif tsk->seccomp.filter = NULL; #endif } @@ -225,6 +210,7 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { struct cred *newcreds; struct task_struct *target_task; + unsigned long flags; struct task_struct *p = current; struct task_struct *t; @@ -288,9 +274,9 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) task_unlock(target_task); if (target_task->sighand) { - spin_lock_irq(&target_task->sighand->siglock); + spin_lock_irqsave(&target_task->sighand->siglock, flags); disable_seccomp_for_task(target_task); - spin_unlock_irq(&target_task->sighand->siglock); + spin_unlock_irqrestore(&target_task->sighand->siglock, flags); } setup_selinux(profile->selinux_domain); diff --git a/kernel/app_profile.h b/kernel/app_profile.h index 80b2f916..871abb6f 100644 --- a/kernel/app_profile.h +++ b/kernel/app_profile.h @@ -65,6 +65,6 @@ void escape_with_root_profile(void); void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid); -void disable_seccomp(struct task_struct *tsk); +void disable_seccomp(void); #endif diff --git a/kernel/setuid_hook.c b/kernel/setuid_hook.c index df513826..44dffd98 100644 --- a/kernel/setuid_hook.c +++ b/kernel/setuid_hook.c @@ -136,7 +136,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid) #else if (ksu_is_allow_uid_for_current(new_uid)) { spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(current); + disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); if (ksu_get_manager_uid() == new_uid) {