Skip to content
  • Al Viro's avatar
    fix __legitimize_mnt()/mntput() race · 119e1ef8
    Al Viro authored
    
    
    __legitimize_mnt() has two problems - one is that in case of success
    the check of mount_lock is not ordered wrt preceding increment of
    refcount, making it possible to have successful __legitimize_mnt()
    on one CPU just before the otherwise final mntpu() on another,
    with __legitimize_mnt() not seeing mntput() taking the lock and
    mntput() not seeing the increment done by __legitimize_mnt().
    Solved by a pair of barriers.
    
    Another is that failure of __legitimize_mnt() on the second
    read_seqretry() leaves us with reference that'll need to be
    dropped by caller; however, if that races with final mntput()
    we can end up with caller dropping rcu_read_lock() and doing
    mntput() to release that reference - with the first mntput()
    having freed the damn thing just as rcu_read_lock() had been
    dropped.  Solution: in "do mntput() yourself" failure case
    grab mount_lock, check if MNT_DOOMED has been set by racing
    final mntput() that has missed our increment and if it has -
    undo the increment and treat that as "failure, caller doesn't
    need to drop anything" case.
    
    It's not easy to hit - the final mntput() has to come right
    after the first read_seqretry() in __legitimize_mnt() *and*
    manage to miss the increment done by __legitimize_mnt() before
    the second read_seqretry() in there.  The things that are almost
    impossible to hit on bare hardware are not impossible on SMP
    KVM, though...
    
    Reported-by: default avatarOleg Nesterov <oleg@redhat.com>
    Fixes: 48a066e7
    
     ("RCU'd vsfmounts")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    119e1ef8