diff options
author | Davidlohr Bueso <davidlohr.bueso@hp.com> | 2013-07-08 16:01:12 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-10-18 07:45:46 -0700 |
commit | ac9bc6e396285ab732dd869c3edb353662134022 (patch) | |
tree | 182b0be2e0238d96e02c8669e372c254d6ea81a1 /ipc/sem.c | |
parent | 115d40dbef93b70e6f32732b0fdd5903c1f7fce4 (diff) | |
download | linux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.tar.gz linux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.tar.bz2 linux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.zip |
ipc: move locking out of ipcctl_pre_down_nolock
commit 7b4cc5d8411bd4e9d61d8714f53859740cf830c2 upstream.
This function currently acquires both the rw_mutex and the rcu lock on
successful lookups, leaving the callers to explicitly unlock them,
creating another two level locking situation.
Make the callers (including those that still use ipcctl_pre_down())
explicitly lock and unlock the rwsem and rcu lock.
Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/ipc/sem.c b/ipc/sem.c index 92ec6c69bab..b4b892b5c5f 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1289,39 +1289,44 @@ static int semctl_down(struct ipc_namespace *ns, int semid, return -EFAULT; } + down_write(&sem_ids(ns).rw_mutex); + rcu_read_lock(); + ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, &semid64.sem_perm, 0); - if (IS_ERR(ipcp)) - return PTR_ERR(ipcp); + if (IS_ERR(ipcp)) { + err = PTR_ERR(ipcp); + /* the ipc lock is not held upon failure */ + goto out_unlock1; + } sma = container_of(ipcp, struct sem_array, sem_perm); err = security_sem_semctl(sma, cmd); - if (err) { - rcu_read_unlock(); - goto out_up; - } + if (err) + goto out_unlock1; - switch(cmd){ + switch (cmd) { case IPC_RMID: sem_lock(sma, NULL, -1); + /* freeary unlocks the ipc object and rcu */ freeary(ns, ipcp); goto out_up; case IPC_SET: sem_lock(sma, NULL, -1); err = ipc_update_perm(&semid64.sem_perm, ipcp); if (err) - goto out_unlock; + goto out_unlock0; sma->sem_ctime = get_seconds(); break; default: - rcu_read_unlock(); err = -EINVAL; - goto out_up; + goto out_unlock1; } -out_unlock: +out_unlock0: sem_unlock(sma, -1); +out_unlock1: rcu_read_unlock(); out_up: up_write(&sem_ids(ns).rw_mutex); |