• Jann Horn's avatar
    ipc/sem: Fix dangling sem_array access in semtimedop race · b52be557
    Jann Horn authored
    When __do_semtimedop() goes to sleep because it has to wait for a
    semaphore value becoming zero or becoming bigger than some threshold, it
    links the on-stack sem_queue to the sem_array, then goes to sleep
    without holding a reference on the sem_array.
    
    When __do_semtimedop() comes back out of sleep, one of two things must
    happen:
    
     a) We prove that the on-stack sem_queue has been disconnected from the
        (possibly freed) sem_array, making it safe to return from the stack
        frame that the sem_queue exists in.
    
     b) We stabilize our reference to the sem_array, lock the sem_array, and
        detach the sem_queue from the sem_array ourselves.
    
    sem_array has RCU lifetime, so for case (b), the reference can be
    stabilized inside an RCU read-side critical section by locklessly
    checking whether the sem_queue is still connected to the sem_array.
    
    However, the current code does the lockless check on sem_queue before
    starting an RCU read-side critical section, so the result of the
    lockless check immediately becomes useless.
    
    Fix it by doing rcu_read_lock() before the lockless check.  Now RCU
    ensures that if we observe the object being on our queue, the object
    can't be freed until rcu_read_unlock().
    
    This bug is only hittable on kernel builds with full preemption support
    (either CONFIG_PREEMPT or PREEMPT_DYNAMIC with preempt=full).
    
    Fixes: 370b262c ("ipc/sem: avoid idr tree lookup for interrupted semop")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarJann Horn <jannh@google.com>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    b52be557
sem.c 63.2 KB