Fix RCU lockdep splats in keys and sched
Subsystems (2)
PATCH 1/1 Fix RCU lockdep splats in keys and sched
Hello!
This series fixes a pair of RCU lockdep splats in the keys subsystem (courtesy of David Howells) and another in the scheduler.
Thanx, Paul
kernel/sched.c | 6 +++++- security/keys/request_key.c | 13 ++++++++----- security/keys/user_defined.c | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-)
PATCH 1/3 KEYS: Fix an RCU warning
From: David Howells <[email protected]>
Fix the following RCU warning:
===================================================
[ INFO: suspicious rcu_dereference_check() usage. ]
---------------------------------------------------security/keys/request_key.c:116 invoked rcu_dereference_check() without protection!
other info that might help us debug this:
rcu_scheduler_active = 1, debug_locks = 0
1 lock held by keyctl/5372:
#0: (key_types_sem){.+.+.+}, at: [<ffffffff811a4e3d>] key_type_lookup+0x1c/0x70
stack backtrace: Pid: 5372, comm: keyctl Not tainted 2.6.34-rc3-cachefs #150 Call Trace: [<ffffffff810515f8>] lockdep_rcu_dereference+0xaa/0xb2 [<ffffffff811a9220>] call_sbin_request_key+0x156/0x2b6 [<ffffffff811a4c66>] ? __key_instantiate_and_link+0xb1/0xdc [<ffffffff811a4cd3>] ? key_instantiate_and_link+0x42/0x5f [<ffffffff811a96b8>] ? request_key_auth_new+0x17b/0x1f3 [<ffffffff811a8e00>] ? request_key_and_link+0x271/0x400 [<ffffffff810aba6f>] ? kmem_cache_alloc+0xe1/0x118 [<ffffffff811a8f1a>] request_key_and_link+0x38b/0x400 [<ffffffff811a7b72>] sys_request_key+0xf7/0x14a [<ffffffff81052227>] ? trace_hardirqs_on_caller+0x10c/0x130 [<ffffffff81393f5c>] ? trace_hardirqs_on_thunk+0x3a/0x3f [<ffffffff81001eeb>] system_call_fastpath+0x16/0x1b
This was caused by doing:
[root@andromeda ~]# keyctl newring fred @s 539196288 [root@andromeda ~]# keyctl request2 user a a 539196288 request_key: Required key not available
--- security/keys/request_key.c | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-)
security/keys/request_key.c +8 -5
@@ -68,7 +68,8 @@ static int call_sbin_request_key(struct key_construction *cons, {const struct cred *cred =current_cred ();key_serial_t prkey, sskey; -struct key *key = cons->key, *authkey = cons->authkey, *keyring; +struct key *key = cons->key, *authkey = cons->authkey, *keyring, + *session;char *argv[9 ], *envp[3 ], uid_str[12 ], gid_str[12 ];char key_str[12 ], keyring_str[3 ][12 ];char desc[20 ];
@@ -112,10 +113,12 @@ static int call_sbin_request_key(struct key_construction *cons,if (cred->tgcred->process_keyring) prkey = cred->tgcred->process_keyring->serial; -if (cred->tgcred->session_keyring) - sskey =rcu_dereference (cred->tgcred->session_keyring)->serial; -else - sskey = cred->user->session_keyring->serial; +rcu_read_lock (); + session =rcu_dereference (cred->tgcred->session_keyring); +if (!session) + session = cred->user->session_keyring; + sskey = session->serial; +rcu_read_unlock ();sprintf (keyring_str[2 ],"%d" , sskey);
Signature · 1 line
1.7.0
PATCH 2/3 KEYS: Fix an RCU warning in the reading of user keys
In reply to Paul E. McKenneyFrom: David Howells <[email protected]>
Fix an RCU warning in the reading of user keys:
===================================================
[ INFO: suspicious rcu_dereference_check() usage. ]
---------------------------------------------------security/keys/user_defined.c:202 invoked rcu_dereference_check() without protection!
other info that might help us debug this:
rcu_scheduler_active = 1, debug_locks = 0
1 lock held by keyctl/3637:
#0: (&key->sem){+++++.}, at: [<ffffffff811a80ae>] keyctl_read_key+0x9c/0xcf
stack backtrace: Pid: 3637, comm: keyctl Not tainted 2.6.34-rc5-cachefs #18 Call Trace: [<ffffffff81051f6c>] lockdep_rcu_dereference+0xaa/0xb2 [<ffffffff811aa55f>] user_read+0x47/0x91 [<ffffffff811a80be>] keyctl_read_key+0xac/0xcf [<ffffffff811a8a06>] sys_keyctl+0x75/0xb7 [<ffffffff81001eeb>] system_call_fastpath+0x16/0x1b
--- security/keys/user_defined.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
security/keys/user_defined.c +2 -1
@@ -199,7 +199,8 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)struct user_key_payload *upayload;long ret; - upayload =rcu_dereference (key->payload.data); + upayload =rcu_dereference_protected ( + key->payload.data,rwsem_is_locked (&((struct key *)key)->sem)); ret = upayload->datalen;/* we can return the data as is */
Signature · 1 line
1.7.0
PATCH 3/3 sched: protect __sched_setscheduler() access to cgroups
In reply to Paul E. McKenneyA given task's cgroups structures must remain while that task is running due to reference counting, so this is presumably a false positive. Updated to reflect feedback from Tetsuo Handa.
--- kernel/sched.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
kernel/sched.c +5 -1
@@ -4575,9 +4575,13 @@ recheck:* Do not allow realtime tasks into groups that have no runtime * assigned. */ +rcu_read_lock ();if (rt_bandwidth_enabled () &&rt_policy (policy) && -task_group (p)->rt_bandwidth.rt_runtime ==0 ) +task_group (p)->rt_bandwidth.rt_runtime ==0 ) { +rcu_read_unlock ();return -EPERM ; + } +rcu_read_unlock ();#endif retval =security_task_setscheduler (p, policy, param);
Signature · 1 line
1.7.0
Re: [PATCH tip/core/urgent 3/3] sched: protect __sched_setscheduler() access to cgroups
Quoted 3 lines · Paul E. McKenney
A given task's cgroups structures must remain while that task is running due to reference counting, so this is presumably a false positive. Updated to reflect feedback from Tetsuo Handa.
I think its not a false positive, I think we can race with the task being placed in another cgroup. We don't hold task_lock() [our other discussion] nor does it hold rq->lock [used by the sched ->attach() method].
That said, we should probably cure the race condition of sched_setscheduler() vs ->attach().
Something like the below perhaps?
--- kernel/sched.c | 38 ++++++++++++++++++++++++++------------ 1 files changed, 26 insertions(+), 12 deletions(-)
kernel/sched.c +26 -12
@@ -4425,16 +4425,6 @@ recheck: }if (user) { -#ifdef CONFIG_RT_GROUP_SCHED -/* -* Do not allow realtime tasks into groups that have no runtime -* assigned. -*/ -if (rt_bandwidth_enabled () &&rt_policy (policy) && -task_group (p)->rt_bandwidth.rt_runtime ==0 ) -return -EPERM ; -#endif - retval =security_task_setscheduler (p, policy, param);if (retval)return retval;
@@ -4450,6 +4440,28 @@ recheck:* runqueue lock must be held. */ rq =__task_rq_lock (p); + retval =0 ; +#ifdef CONFIG_RT_GROUP_SCHED +if (user) { +/* +* Do not allow realtime tasks into groups that have no runtime +* assigned. +* +* RCU read lock not strictly required but here for PROVE_RCU, +* the task is pinned by holding rq->lock which avoids races +* with ->attach(). +*/ +rcu_read_lock (); +if (rt_bandwidth_enabled () &&rt_policy (policy) && +task_group (p)->rt_bandwidth.rt_runtime ==0 ) + retval = -EPERM ; +rcu_read_unlock (); + +if (retval) + goto unlock; + } +#endif +/* recheck policy now with rq lock held */ if (unlikely (oldpolicy !=-1 && oldpolicy != p->policy)) { policy = oldpolicy =-1 ;
@@ -4477,12 +4489,14 @@ recheck:check_class_changed (rq, p, prev_class, oldprio, running); } +unlock:__task_rq_unlock (rq);raw_spin_unlock_irqrestore (&p->pi_lock, flags); -rt_mutex_adjust_pi (p); +if (!retval) +rt_mutex_adjust_pi (p); -return 0 ; +return retval; }/**
Re: [PATCH tip/core/urgent 3/3] sched: protect __sched_setscheduler() access to cgroups
Quoted 9 lines · Peter Zijlstra
Quoted 3 lines · Paul E. McKenney
A given task's cgroups structures must remain while that task is running due to reference counting, so this is presumably a false positive. Updated to reflect feedback from Tetsuo Handa.
I think its not a false positive, I think we can race with the task being placed in another cgroup. We don't hold
task_lock()[our other discussion] nor does it holdrq->lock[used by the sched ->attach() method].
Ah, I am dropping this patch then.
Ingo, please accept my apologies for the confusion submitting it too soon!
Thanx, Paul
Quoted 79 lines
That said, we should probably cure the race condition of
sched_setscheduler()vs ->attach().Something like the below perhaps?
Signed-off-by Peter Zijlstra <[email protected]>--- kernel/sched.c | 38 ++++++++++++++++++++++++++------------ 1 files changed, 26 insertions(+), 12 deletions(-)kernel/sched.c +26
-12@@ -4425,16 +4425,6 @@ recheck: }if (user) { -#ifdef CONFIG_RT_GROUP_SCHED -/* -* Do not allow realtime tasks into groups that have no runtime -* assigned. -*/ -if (rt_bandwidth_enabled () &&rt_policy (policy) && -task_group (p)->rt_bandwidth.rt_runtime ==0 ) -return -EPERM ; -#endif - retval =security_task_setscheduler (p, policy, param);if (retval)return retval;@@ -4450,6 +4440,28 @@ recheck:* runqueue lock must be held. */ rq =__task_rq_lock (p); + retval =0 ; +#ifdef CONFIG_RT_GROUP_SCHED +if (user) { +/* +* Do not allow realtime tasks into groups that have no runtime +* assigned. +* +* RCU read lock not strictly required but here for PROVE_RCU, +* the task is pinned by holding rq->lock which avoids races +* with ->attach(). +*/ +rcu_read_lock (); +if (rt_bandwidth_enabled () &&rt_policy (policy) && +task_group (p)->rt_bandwidth.rt_runtime ==0 ) + retval = -EPERM ; +rcu_read_unlock (); + +if (retval) + goto unlock; + } +#endif +/* recheck policy now with rq lock held */ if (unlikely (oldpolicy !=-1 && oldpolicy != p->policy)) { policy = oldpolicy =-1 ;@@ -4477,12 +4489,14 @@ recheck:check_class_changed (rq, p, prev_class, oldprio, running); } +unlock:__task_rq_unlock (rq);raw_spin_unlock_irqrestore (&p->pi_lock, flags); -rt_mutex_adjust_pi (p); +if (!retval) +rt_mutex_adjust_pi (p); -return 0 ; +return retval; }/**