* Re: [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention [not found] <20241120132156.207250-1-zhen.ni@easystack.cn> @ 2024-11-28 1:45 ` Andrew Morton 2024-11-28 7:13 ` Oleg Nesterov 0 siblings, 1 reply; 4+ messages in thread From: Andrew Morton @ 2024-11-28 1:45 UTC (permalink / raw) To: Zhen Ni Cc: viro, oleg, catalin.marinas, brauner, zev, linux-kernel, linux-security-module On Wed, 20 Nov 2024 21:21:56 +0800 Zhen Ni <zhen.ni@easystack.cn> wrote: > Refines the lock scope in the do_prlimit function to reduce > contention on task_lock(tsk->group_leader). The lock now protects only > sections that access or modify shared resources (rlim). Permission > checks (capable) and security validations (security_task_setrlimit) > are placed outside the lock, as they do not modify rlim and are > independent of shared data protection. Let's cc linux-security-module@vger.kernel.org, as we're proposing altering their locking environment! > The security_task_setrlimit function is a Linux Security Module (LSM) > hook that evaluates resource limit changes based on security policies. > It does not alter the rlim data structure, as confirmed by existing > LSM implementations (e.g., SELinux and AppArmor). Thus, this function > does not require locking, ensuring correctness while improving > concurrency. Seems sane. Does any code call do_prlimit() frequently enough for this to matter? > --- a/kernel/sys.c > +++ b/kernel/sys.c > @@ -1481,18 +1481,20 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource, > > /* Holding a refcount on tsk protects tsk->signal from disappearing. */ > rlim = tsk->signal->rlim + resource; > - task_lock(tsk->group_leader); > if (new_rlim) { > /* > * Keep the capable check against init_user_ns until cgroups can > * contain all limits. > */ > if (new_rlim->rlim_max > rlim->rlim_max && > - !capable(CAP_SYS_RESOURCE)) > - retval = -EPERM; > - if (!retval) > - retval = security_task_setrlimit(tsk, resource, new_rlim); > + !capable(CAP_SYS_RESOURCE)) > + return -EPERM; > + retval = security_task_setrlimit(tsk, resource, new_rlim); > + if (retval) > + return retval; > } > + > + task_lock(tsk->group_leader); > if (!retval) { > if (old_rlim) > *old_rlim = *rlim; ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention 2024-11-28 1:45 ` [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention Andrew Morton @ 2024-11-28 7:13 ` Oleg Nesterov 2024-11-28 7:39 ` Oleg Nesterov 0 siblings, 1 reply; 4+ messages in thread From: Oleg Nesterov @ 2024-11-28 7:13 UTC (permalink / raw) To: Andrew Morton Cc: Zhen Ni, viro, catalin.marinas, brauner, zev, linux-kernel, linux-security-module On 11/27, Andrew Morton wrote: > > On Wed, 20 Nov 2024 21:21:56 +0800 Zhen Ni <zhen.ni@easystack.cn> wrote: > > > The security_task_setrlimit function is a Linux Security Module (LSM) > > hook that evaluates resource limit changes based on security policies. > > It does not alter the rlim data structure, as confirmed by existing > > LSM implementations (e.g., SELinux and AppArmor). Thus, this function > > does not require locking, ensuring correctness while improving > > concurrency. > > Seems sane. > > Does any code call do_prlimit() frequently enough for this to matter? I have the same question... > > - task_lock(tsk->group_leader); > > if (new_rlim) { > > /* > > * Keep the capable check against init_user_ns until cgroups can > > * contain all limits. > > */ > > if (new_rlim->rlim_max > rlim->rlim_max && > > - !capable(CAP_SYS_RESOURCE)) > > - retval = -EPERM; > > - if (!retval) > > - retval = security_task_setrlimit(tsk, resource, new_rlim); > > + !capable(CAP_SYS_RESOURCE)) > > + return -EPERM; > > + retval = security_task_setrlimit(tsk, resource, new_rlim); > > + if (retval) > > + return retval; > > } > > + > > + task_lock(tsk->group_leader); The problem is that task_lock(tsk->group_leader) doesn't look right with or without this patch. I'll try to make a fix on weekend. If the caller is sys_prlimit64() and tsk != current, then ->group_leader is not stable, do_prlimit() can race with mt exec and take the wrong lock. Oleg. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention 2024-11-28 7:13 ` Oleg Nesterov @ 2024-11-28 7:39 ` Oleg Nesterov 2024-11-28 8:08 ` Oleg Nesterov 0 siblings, 1 reply; 4+ messages in thread From: Oleg Nesterov @ 2024-11-28 7:39 UTC (permalink / raw) To: Andrew Morton Cc: Zhen Ni, viro, catalin.marinas, brauner, zev, linux-kernel, linux-security-module On 11/28, Oleg Nesterov wrote: > > The problem is that task_lock(tsk->group_leader) doesn't look right with or > without this patch. I'll try to make a fix on weekend. > > If the caller is sys_prlimit64() and tsk != current, then ->group_leader is > not stable, do_prlimit() can race with mt exec and take the wrong lock. ... and task_unlock(tsk->group_leader) is simply unsafe. perhaps something like below, but it doesn't look nice, I'll try to think more. And grep, may be there are more lockless users of tsk->group_leader when tsk != current. Oleg. --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1464,6 +1464,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) static int do_prlimit(struct task_struct *tsk, unsigned int resource, struct rlimit *new_rlim, struct rlimit *old_rlim) { + struct task_struct *leader; struct rlimit *rlim; int retval = 0; @@ -1481,7 +1482,14 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource, /* Holding a refcount on tsk protects tsk->signal from disappearing. */ rlim = tsk->signal->rlim + resource; - task_lock(tsk->group_leader); + + if (tsk != current) + read_lock(&tasklist_lock); + leader = READ_ONCE(tsk->group_leader); + task_lock(leader); + if (tsk != current) + read_unlock(&tasklist_lock); + if (new_rlim) { /* * Keep the capable check against init_user_ns until cgroups can @@ -1499,7 +1507,7 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource, if (new_rlim) *rlim = *new_rlim; } - task_unlock(tsk->group_leader); + task_unlock(leader); /* * RLIMIT_CPU handling. Arm the posix CPU timer if the limit is not ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention 2024-11-28 7:39 ` Oleg Nesterov @ 2024-11-28 8:08 ` Oleg Nesterov 0 siblings, 0 replies; 4+ messages in thread From: Oleg Nesterov @ 2024-11-28 8:08 UTC (permalink / raw) To: Andrew Morton Cc: Zhen Ni, viro, catalin.marinas, brauner, zev, linux-kernel, linux-security-module On 11/28, Oleg Nesterov wrote: > > On 11/28, Oleg Nesterov wrote: > > > > The problem is that task_lock(tsk->group_leader) doesn't look right with or > > without this patch. I'll try to make a fix on weekend. > > > > If the caller is sys_prlimit64() and tsk != current, then ->group_leader is > > not stable, do_prlimit() can race with mt exec and take the wrong lock. > > ... and task_unlock(tsk->group_leader) is simply unsafe. > > perhaps something like below, No, this is wrong too, > I'll try to think more. Yes... Oleg. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-11-28 8:08 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20241120132156.207250-1-zhen.ni@easystack.cn>
2024-11-28 1:45 ` [PATCH] kernel/sys: Optimize do_prlimit lock scope to reduce contention Andrew Morton
2024-11-28 7:13 ` Oleg Nesterov
2024-11-28 7:39 ` Oleg Nesterov
2024-11-28 8:08 ` Oleg Nesterov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).