diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2009-12-09 19:52:51 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2009-12-10 17:04:11 -0500 |
commit | d4581a239a40319205762b76c01eb6363f277efa (patch) | |
tree | d05b5f7103c9585e8485b581dc90f5a4ed9d18e3 /kernel/sys.c | |
parent | 7cf7db8df0b78076eafa4ead47559344ca7b7a43 (diff) |
sys: Fix missing rcu protection for __task_cred() access
commit c69e8d9 (CRED: Use RCU to access another task's creds and to
release a task's own creds) added non rcu_read_lock() protected access
to task creds of the target task in set_prio_one().
The comment above the function says:
* - the caller must hold the RCU read lock
The calling code in sys_setpriority does read_lock(&tasklist_lock) but
not rcu_read_lock(). This works only when CONFIG_TREE_PREEMPT_RCU=n.
With CONFIG_TREE_PREEMPT_RCU=y the rcu_callbacks can run in the tick
interrupt when they see no read side critical section.
There is another instance of __task_cred() in sys_setpriority() itself
which is equally unprotected.
Wrap the whole code section into a rcu read side critical section to
fix this quick and dirty.
Will be revisited in course of the read_lock(&tasklist_lock) -> rcu
crusade.
Oleg noted further:
This also fixes another bug here. find_task_by_vpid() is not safe
without rcu_read_lock(). I do not mean it is not safe to use the
result, just find_pid_ns() by itself is not safe.
Usually tasklist gives enough protection, but if copy_process() fails
it calls free_pid() lockless and does call_rcu(delayed_put_pid().
This means, without rcu lock find_pid_ns() can't scan the hash table
safely.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <20091210004703.029784964@linutronix.de>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 9968c5fb55b9..bc1dc61c31ed 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -163,6 +163,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
163 | if (niceval > 19) | 163 | if (niceval > 19) |
164 | niceval = 19; | 164 | niceval = 19; |
165 | 165 | ||
166 | rcu_read_lock(); | ||
166 | read_lock(&tasklist_lock); | 167 | read_lock(&tasklist_lock); |
167 | switch (which) { | 168 | switch (which) { |
168 | case PRIO_PROCESS: | 169 | case PRIO_PROCESS: |
@@ -200,6 +201,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
200 | } | 201 | } |
201 | out_unlock: | 202 | out_unlock: |
202 | read_unlock(&tasklist_lock); | 203 | read_unlock(&tasklist_lock); |
204 | rcu_read_unlock(); | ||
203 | out: | 205 | out: |
204 | return error; | 206 | return error; |
205 | } | 207 | } |