• Sebastian Andrzej Siewior's avatar
    random: add a spinlock_t to struct batched_entropy · b7d5dc21
    Sebastian Andrzej Siewior authored
    The per-CPU variable batched_entropy_uXX is protected by get_cpu_var().
    This is just a preempt_disable() which ensures that the variable is only
    from the local CPU. It does not protect against users on the same CPU
    from another context. It is possible that a preemptible context reads
    slot 0 and then an interrupt occurs and the same value is read again.
    
    The above scenario is confirmed by lockdep if we add a spinlock:
    | ================================
    | WARNING: inconsistent lock state
    | 5.1.0-rc3+ #42 Not tainted
    | --------------------------------
    | inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
    | ksoftirqd/9/56 [HC0[0]:SC1[1]:HE0:SE0] takes:
    | (____ptrval____) (batched_entropy_u32.lock){+.?.}, at: get_random_u32+0x3e/0xe0
    | {SOFTIRQ-ON-W} state was registered at:
    |   _raw_spin_lock+0x2a/0x40
    |   get_random_u32+0x3e/0xe0
    |   new_slab+0x15c/0x7b0
    |   ___slab_alloc+0x492/0x620
    |   __slab_alloc.isra.73+0x53/0xa0
    |   kmem_cache_alloc_node+0xaf/0x2a0
    |   copy_process.part.41+0x1e1/0x2370
    |   _do_fork+0xdb/0x6d0
    |   kernel_thread+0x20/0x30
    |   kthreadd+0x1ba/0x220
    |   ret_from_fork+0x3a/0x50
    …
    | other info that might help us debug this:
    |  Possible unsafe locking scenario:
    |
    |        CPU0
    |        ----
    |   lock(batched_entropy_u32.lock);
    |   <Interrupt>
    |     lock(batched_entropy_u32.lock);
    |
    |  *** DEADLOCK ***
    |
    | stack backtrace:
    | Call Trace:
    …
    |  kmem_cache_alloc_trace+0x20e/0x270
    |  ipmi_alloc_recv_msg+0x16/0x40
    …
    |  __do_softirq+0xec/0x48d
    |  run_ksoftirqd+0x37/0x60
    |  smpboot_thread_fn+0x191/0x290
    |  kthread+0xfe/0x130
    |  ret_from_fork+0x3a/0x50
    
    Add a spinlock_t to the batched_entropy data structure and acquire the
    lock while accessing it. Acquire the lock with disabled interrupts
    because this function may be used from interrupt context.
    
    Remove the batched_entropy_reset_lock lock. Now that we have a lock for
    the data scructure, we can access it from a remote CPU.
    Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
    b7d5dc21
random.c 71.1 KB