aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
authorRafael Aquini <aquini@redhat.com>2014-01-27 20:07:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-28 00:02:39 -0500
commit0f3d2b0135f4bdbfe47a99753923a64efd373d11 (patch)
tree4b211b7502e2412aedd94400bdcb012a2b5814b3 /ipc/sem.c
parent78f5009cc35eb5e52d276a046d90ee2f41b60f8c (diff)
ipc: introduce ipc_valid_object() helper to sort out IPC_RMID races
After the locking semantics for the SysV IPC API got improved, a couple of IPC_RMID race windows were opened because we ended up dropping the 'kern_ipc_perm.deleted' check performed way down in ipc_lock(). The spotted races got sorted out by re-introducing the old test within the racy critical sections. This patch introduces ipc_valid_object() to consolidate the way we cope with IPC_RMID races by using the same abstraction across the API implementation. Signed-off-by: Rafael Aquini <aquini@redhat.com> Acked-by: Rik van Riel <riel@redhat.com> Acked-by: Greg Thelen <gthelen@google.com> Reviewed-by: Davidlohr Bueso <davidlohr@hp.com> Cc: Manfred Spraul <manfred@colorfullife.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index cc9ac35b793c..4d88194a5ffe 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1284,7 +1284,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
1284 1284
1285 sem_lock(sma, NULL, -1); 1285 sem_lock(sma, NULL, -1);
1286 1286
1287 if (sma->sem_perm.deleted) { 1287 if (!ipc_valid_object(&sma->sem_perm)) {
1288 sem_unlock(sma, -1); 1288 sem_unlock(sma, -1);
1289 rcu_read_unlock(); 1289 rcu_read_unlock();
1290 return -EIDRM; 1290 return -EIDRM;
@@ -1344,7 +1344,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1344 int i; 1344 int i;
1345 1345
1346 sem_lock(sma, NULL, -1); 1346 sem_lock(sma, NULL, -1);
1347 if (sma->sem_perm.deleted) { 1347 if (!ipc_valid_object(&sma->sem_perm)) {
1348 err = -EIDRM; 1348 err = -EIDRM;
1349 goto out_unlock; 1349 goto out_unlock;
1350 } 1350 }
@@ -1363,7 +1363,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1363 1363
1364 rcu_read_lock(); 1364 rcu_read_lock();
1365 sem_lock_and_putref(sma); 1365 sem_lock_and_putref(sma);
1366 if (sma->sem_perm.deleted) { 1366 if (!ipc_valid_object(&sma->sem_perm)) {
1367 err = -EIDRM; 1367 err = -EIDRM;
1368 goto out_unlock; 1368 goto out_unlock;
1369 } 1369 }
@@ -1411,7 +1411,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1411 } 1411 }
1412 rcu_read_lock(); 1412 rcu_read_lock();
1413 sem_lock_and_putref(sma); 1413 sem_lock_and_putref(sma);
1414 if (sma->sem_perm.deleted) { 1414 if (!ipc_valid_object(&sma->sem_perm)) {
1415 err = -EIDRM; 1415 err = -EIDRM;
1416 goto out_unlock; 1416 goto out_unlock;
1417 } 1417 }
@@ -1437,7 +1437,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1437 goto out_rcu_wakeup; 1437 goto out_rcu_wakeup;
1438 1438
1439 sem_lock(sma, NULL, -1); 1439 sem_lock(sma, NULL, -1);
1440 if (sma->sem_perm.deleted) { 1440 if (!ipc_valid_object(&sma->sem_perm)) {
1441 err = -EIDRM; 1441 err = -EIDRM;
1442 goto out_unlock; 1442 goto out_unlock;
1443 } 1443 }
@@ -1701,7 +1701,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
1701 /* step 3: Acquire the lock on semaphore array */ 1701 /* step 3: Acquire the lock on semaphore array */
1702 rcu_read_lock(); 1702 rcu_read_lock();
1703 sem_lock_and_putref(sma); 1703 sem_lock_and_putref(sma);
1704 if (sma->sem_perm.deleted) { 1704 if (!ipc_valid_object(&sma->sem_perm)) {
1705 sem_unlock(sma, -1); 1705 sem_unlock(sma, -1);
1706 rcu_read_unlock(); 1706 rcu_read_unlock();
1707 kfree(new); 1707 kfree(new);
@@ -1848,7 +1848,15 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1848 1848
1849 error = -EIDRM; 1849 error = -EIDRM;
1850 locknum = sem_lock(sma, sops, nsops); 1850 locknum = sem_lock(sma, sops, nsops);
1851 if (sma->sem_perm.deleted) 1851 /*
1852 * We eventually might perform the following check in a lockless
1853 * fashion, considering ipc_valid_object() locking constraints.
1854 * If nsops == 1 and there is no contention for sem_perm.lock, then
1855 * only a per-semaphore lock is held and it's OK to proceed with the
1856 * check below. More details on the fine grained locking scheme
1857 * entangled here and why it's RMID race safe on comments at sem_lock()
1858 */
1859 if (!ipc_valid_object(&sma->sem_perm))
1852 goto out_unlock_free; 1860 goto out_unlock_free;
1853 /* 1861 /*
1854 * semid identifiers are not unique - find_alloc_undo may have 1862 * semid identifiers are not unique - find_alloc_undo may have
@@ -2070,7 +2078,7 @@ void exit_sem(struct task_struct *tsk)
2070 2078
2071 sem_lock(sma, NULL, -1); 2079 sem_lock(sma, NULL, -1);
2072 /* exit_sem raced with IPC_RMID, nothing to do */ 2080 /* exit_sem raced with IPC_RMID, nothing to do */
2073 if (sma->sem_perm.deleted) { 2081 if (!ipc_valid_object(&sma->sem_perm)) {
2074 sem_unlock(sma, -1); 2082 sem_unlock(sma, -1);
2075 rcu_read_unlock(); 2083 rcu_read_unlock();
2076 continue; 2084 continue;