Skip to content

Commit 99a3e3a

Browse files
Swaraj-1925tehcaster
authored andcommitted
slab: fix kmalloc_nolock() context check for PREEMPT_RT
On PREEMPT_RT kernels, local_lock becomes a sleeping lock. The current check in kmalloc_nolock() only verifies we're not in NMI or hard IRQ context, but misses the case where preemption is disabled. When a BPF program runs from a tracepoint with preemption disabled (preempt_count > 0), kmalloc_nolock() proceeds to call local_lock_irqsave() which attempts to acquire a sleeping lock, triggering: BUG: sleeping function called from invalid context in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 6128 preempt_count: 2, expected: 0 Fix this by checking !preemptible() on PREEMPT_RT, which directly expresses the constraint that we cannot take a sleeping lock when preemption is disabled. This encompasses the previous checks for NMI and hard IRQ contexts while also catching cases where preemption is disabled. Fixes: af92793 ("slab: Introduce kmalloc_nolock() and kfree_nolock().") Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=b1546ad4a95331b2101e Signed-off-by: Swaraj Gaikwad <[email protected]> Acked-by: Sebastian Andrzej Siewior <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Acked-by: Harry Yoo <[email protected]> Link: https://patch.msgid.link/[email protected] Cc: <[email protected]> Signed-off-by: Vlastimil Babka <[email protected]>
1 parent 0f61b18 commit 99a3e3a

1 file changed

Lines changed: 6 additions & 2 deletions

File tree

mm/slub.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5694,8 +5694,12 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node)
56945694
if (unlikely(!size))
56955695
return ZERO_SIZE_PTR;
56965696

5697-
if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
5698-
/* kmalloc_nolock() in PREEMPT_RT is not supported from irq */
5697+
if (IS_ENABLED(CONFIG_PREEMPT_RT) && !preemptible())
5698+
/*
5699+
* kmalloc_nolock() in PREEMPT_RT is not supported from
5700+
* non-preemptible context because local_lock becomes a
5701+
* sleeping lock on RT.
5702+
*/
56995703
return NULL;
57005704
retry:
57015705
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))

0 commit comments

Comments
 (0)