• Matthew Wilcox (Oracle)'s avatar
    idr: Fix idr_get_next race with idr_remove · c6e2eab0
    Matthew Wilcox (Oracle) authored
    commit 5c089fd0 upstream.
    
    If the entry is deleted from the IDR between the call to
    radix_tree_iter_find() and rcu_dereference_raw(), idr_get_next()
    will return NULL, which will end the iteration prematurely.  We should
    instead continue to the next entry in the IDR.  This only happens if the
    iteration is protected by the RCU lock.  Most IDR users use a spinlock
    or semaphore to exclude simultaneous modifications.  It was noticed once
    the PID allocator was converted to use the IDR, as it uses the RCU lock,
    but there may be other users elsewhere in the kernel.
    
    We can't use the normal pattern of calling radix_tree_deref_retry()
    (which catches both a retry entry in a leaf node and a node entry in
    the root) as the IDR supports storing entries which are unaligned,
    which will trigger an infinite loop if they are encountered.  Instead,
    we have to explicitly check whether the entry is a retry entry.
    
    Fixes: 0a835c4f ("Reimplement IDR and IDA using the radix tree")
    Reported-by: default avatarBrendan Gregg <bgregg@netflix.com>
    Tested-by: default avatarBrendan Gregg <bgregg@netflix.com>
    Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    c6e2eab0
idr.c 17.5 KB