Hi,
I noticed the Sashiko AI review [1] in this thread flagged that
kfree_call_rcu_nolock() dereferences slab->slab_cache even when
virt_to_slab() returns NULL (for large kmalloc objects that bypass
SLUB, or vmalloc addresses). The VM_WARN_ON_ONCE fires but does not
stop execution, and the subsequent NULL dereference is deterministic.
I was able to reproduce this in QEMU with KASAN. The trigger is as
simple as passing a large (>8KB) kmalloc buffer to the new function.
On Tue, Jun 16, 2026 at 12:06:14AM +0800, Harry Yoo (Oracle) wrote:
> This commit introduces kfree_rcu_nolock(), a variant of kfree_rcu()
> designed to be safely called from unknown contexts without falling
> back to batched processing.
...
> +void kfree_call_rcu_nolock(struct rcu_head *head, void *ptr)
> +{
> + struct slab *slab;
> + struct kmem_cache *s;
> +
> + VM_WARN_ON_ONCE(is_vmalloc_addr(ptr) || !virt_to_slab(ptr));
> +
> + slab = virt_to_slab(ptr);
> + s = slab->slab_cache;
The problem: if ptr is a large kmalloc object (> KMALLOC_MAX_CACHE_SIZE,
which is 8 KB on x86_64), the allocation bypasses SLUB and comes from
the page allocator. virt_to_slab() returns NULL. VM_WARN_ON_ONCE
prints a warning but does NOT return, and the next line dereferences
NULL->slab_cache at offset 0x8.
[Reproduction]
I rebuilt the kernel with CONFIG_KASAN=y and added a small late_initcall
that allocates a 16 KB buffer and passes it to kfree_call_rcu_nolock():
static int __init kfree_rcu_nolock_poc_trigger(void)
{
void *p = kmalloc(16384, GFP_KERNEL);
struct rcu_head *head = kmalloc(sizeof(*head), GFP_KERNEL);
kfree_call_rcu_nolock(head, p);
return 0;
}
late_initcall(kfree_rcu_nolock_poc_trigger);
[Crash log — kernel 6.19.0-rc5, CONFIG_KASAN=y, CONFIG_DEBUG_VM=y]
kfree_rcu_nolock PoC: calling kfree_call_rcu_nolock on large obj
ffff888026c5c000
WARNING: mm/slab_common.c:1271 at kfree_call_rcu_nolock+0x1e/0xc0
VM_WARN_ON_ONCE(is_vmalloc_addr(ptr) || !virt_to_slab(ptr))
BUG: kernel NULL pointer dereference, address: 0000000000000008
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
RIP: 0010:kfree_call_rcu_nolock+0x5c/0xc0
Call Trace:
<TASK>
poc_trigger_init+0x2a/0x40
do_one_initcall+0x131/0x730
kernel_init_freeable+0x471/0x7e0
kernel_init+0x28/0x300
ret_from_fork+0x2c/0xc0
</TASK>
Kernel panic - not syncing: Fatal exception
The crash is at offset 0x5c inside kfree_call_rcu_nolock(), which
corresponds to `s = slab->slab_cache`. The fault address 0x8 is
exactly offsetof(struct slab, slab_cache).
[1]
https://sashiko.dev/#/patchset/20260615-kfree_rcu_nolock-v3-0-70a54f3775bb%40kernel.org
(Sashiko AI code review — "Null Pointer Dereference", Severity:
Critical)
Thanks,
XIAO