* 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).