ipc,sem: fix use after free on IPC_RMID after a task using same semaphore set exits
[pandora-kernel.git] / ipc / sem.c
index 5215a81..67f2110 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1606,16 +1606,27 @@ void exit_sem(struct task_struct *tsk)
                rcu_read_lock();
                un = list_entry_rcu(ulp->list_proc.next,
                                    struct sem_undo, list_proc);
-               if (&un->list_proc == &ulp->list_proc)
-                       semid = -1;
-                else
-                       semid = un->semid;
+               if (&un->list_proc == &ulp->list_proc) {
+                       /*
+                        * We must wait for freeary() before freeing this ulp,
+                        * in case we raced with last sem_undo. There is a small
+                        * possibility where we exit while freeary() didn't
+                        * finish unlocking sem_undo_list.
+                        */
+                       spin_unlock_wait(&ulp->lock);
+                       rcu_read_unlock();
+                       break;
+               }
+               spin_lock(&ulp->lock);
+               semid = un->semid;
+               spin_unlock(&ulp->lock);
                rcu_read_unlock();
 
+               /* exit_sem raced with IPC_RMID, nothing to do */
                if (semid == -1)
-                       break;
+                       continue;
 
-               sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
+               sma = sem_lock_check(tsk->nsproxy->ipc_ns, semid);
 
                /* exit_sem raced with IPC_RMID, nothing to do */
                if (IS_ERR(sma))