BUG: soft lockup in bpf_map_free_deferred

Status: moderation: reported on 2026/11/01 09:14
Subsystems: bpf
Labels: prio:low
[Documentation on labels]
Reported-by: syzbot+50f5cdeeb17c0abe2f99@syzkaller.appspotmail.com
First crash: 4d07h, last: 4d07h
✨ AI-generated root cause summary:

During the release of a BPF arena map (arena_map_free), free_vm_area() calls remove_vm_area(), which invokes debug_check_no_obj_freed() on the ~4 GiB sparse virtual address range (KERN_VM_SZ). In __debug_check_no_obj_freed(), the address range is divided into PAGE_SIZE chunks (~1,048,592 iterations), and the loop repeatedly acquires and releases hash bucket spinlocks without bounding iterations to the hash table size (16,384 buckets) and without calling cond_resched(). This excessive loop hogs the CPU for over 23 seconds in debug kernels with CONFIG_DEBUG_OBJECTS_FREE enabled, triggering a soft lockup watchdog panic. In production kernels without debugging sanitizers, CONFIG_DEBUG_OBJECTS_FREE is disabled, making debug_check_no_obj_freed() an empty inline function with no runtime impact.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 62c457528529:

Technical Breakdown & Root Cause Analysis

1. Triggering Context and Call Path

When a BPF arena map (BPF_MAP_TYPE_ARENA) is created in kernel/bpf/arena.c:arena_map_alloc(), it reserves a kernel virtual address area of size KERN_VM_SZ (SZ_4G + GUARD_SZ, roughly 4 GiB):

kern_vm = get_vm_area(KERN_VM_SZ, VM_SPARSE | VM_USERMAP);

This area is a sparse vmalloc reservation used for shared memory between BPF programs and userspace.

When the BPF map is destroyed asynchronously via the deferred workqueue callback bpf_map_free_deferred() -> arena_map_free() (kernel/bpf/arena.c:400):

free_vm_area(arena->kern_vm);

free_vm_area() calls remove_vm_area() (mm/vmalloc.c:3352), which executes debug validation hooks across the full allocated range before freeing the vmap_area:

debug_check_no_locks_freed(vm->addr, get_vm_area_size(vm));
debug_check_no_obj_freed(vm->addr, get_vm_area_size(vm));

2. Root Cause Mechanism in lib/debugobjects.c

When CONFIG_DEBUG_OBJECTS_FREE is enabled, debug_check_no_obj_freed() calls __debug_check_no_obj_freed() (lib/debugobjects.c:1141):

static void __debug_check_no_obj_freed(const void *address, unsigned long size)
{
	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
    ...
	saddr = (unsigned long) address;
	eaddr = saddr + size;
	paddr = saddr & ODEBUG_CHUNK_MASK;
	chunks = ((eaddr - paddr) + (ODEBUG_CHUNK_SIZE - 1));
	chunks >>= ODEBUG_CHUNK_SHIFT;

	for (;chunks > 0; chunks--, paddr += ODEBUG_CHUNK_SIZE) {
		db = get_bucket(paddr);
repeat:
		cnt = 0;
		raw_spin_lock_irqsave(&db->lock, flags);
		hlist_for_each_entry_safe(obj, tmp, &db->list, node) {
            ...
		}
		raw_spin_unlock_irqrestore(&db->lock, flags);
        ...
	}
  • ODEBUG_CHUNK_SHIFT is PAGE_SHIFT (PAGE_SIZE, typically 4 KiB).
  • For a 4 GiB range (KERN_VM_SZ), chunks evaluates to (SZ_4G + GUARD_SZ) / PAGE_SIZE, which is approximately 1,048,592 iterations.
  • ODEBUG_HASH_SIZE is only 1 << 14 = 16,384 buckets. As chunks advances through the linear address space, get_bucket(paddr) repeatedly wraps around and revisits the exact same 16,384 hash buckets 64 times over.
  • In each iteration, raw_spin_lock_irqsave(&db->lock, flags) disables local IRQs and takes the bucket lock.
  • There is no cond_resched() in the loop, nor is chunks capped to ODEBUG_HASH_SIZE (scanning every hash bucket once would suffice to detect any debug object falling in [saddr, eaddr)).
  • Consequently, executing over 1 million iterations of spinlock acquire/release operations in kernel worker context monopolizes the CPU for more than 23 seconds, tripping the kernel watchdog (watchdog: BUG: soft lockup - CPU#1 stuck for 23s! [kworker/u8:8:4093]).

3. Production Kernel Impact

  • Denial of Service (RawDenialOfService = false): In standard production builds, kernel debugging options (CONFIG_DEBUG_OBJECTS and CONFIG_DEBUG_OBJECTS_FREE) are disabled. In include/linux/debugobjects.h:115, debug_check_no_obj_freed() compiles to a complete no-op (static inline void debug_check_no_obj_freed(...) {}). Therefore, the loop is entirely omitted, and no CPU stall or watchdog lockup occurs at runtime in production.
  • Memory Corruption (MemoryCorruption = false): No invalid memory access, write, use-after-free, or corrupted state occurs; this is purely an excessive CPU iteration stall in the debugobjects checker.
  • Information Leak (InfoLeak = "none"): No kernel memory contents or addresses are leaked.
  • Network / KVM Candidacy (IsNetCandidate = false, IsKVMCandidate = false): The issue resides in BPF arena virtual memory tear-down and the core debugobjects hash iteration logic; it is unrelated to networking (CPU 0's NMI backtrace was simply interrupted handling SSH traffic) or hypervisor virtualization.
▶ ▼ ✨ AI Jobs (1)
ID Workflow Result Correct Bug Created Started Finished Revision
1f64ff98 assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ BUG: soft lockup in bpf_map_free_deferred 2026/10/29 00:01 2026/10/29 00:01 2026/10/29 00:40 b1d00f76
▶ ▼ Similar bugs (2)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
android-5-15 BUG: soft lockup in bpf_map_free_deferred 1 8 858d 930d 0/2 auto-obsoleted due to no activity on 2024/09/24 15:46
upstream INFO: rcu detected stall in bpf_map_free_deferred prio:low bpf 1 1 110d 110d 0/29 auto-obsoleted due to no activity on 2026/10/12 05:37

Sample crash report:
watchdog: BUG: soft lockup - CPU#1 stuck for 23s! [kworker/u8:8:4093]
Modules linked in:
irq event stamp: 2945274
hardirqs last  enabled at (2945273): [<ffff800085a84f0c>] __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:210 [inline]
hardirqs last  enabled at (2945273): [<ffff800085a84f0c>] _raw_spin_unlock_irqrestore+0x80/0xb4 kernel/locking/spinlock.c:221
hardirqs last disabled at (2945274): [<ffff800085a5d3b0>] __el1_irq arch/arm64/kernel/entry-common.c:565 [inline]
hardirqs last disabled at (2945274): [<ffff800085a5d3b0>] el1_interrupt+0x28/0x60 arch/arm64/kernel/entry-common.c:581
softirqs last  enabled at (2940022): [<ffff8000800203d4>] __do_softirq+0x14/0x20 kernel/softirq.c:703
softirqs last disabled at (2939807): [<ffff8000800203d4>] __do_softirq+0x14/0x20 kernel/softirq.c:703
CPU: 1 UID: 0 PID: 4093 Comm: kworker/u8:8 Tainted: G             L       syzkaller #0 PREEMPT 
Tainted: [L]=SOFTLOCKUP
Hardware name: linux,dummy-virt (DT)
Workqueue: events_unbound bpf_map_free_deferred
pstate: 10000005 (nzcV daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:211 [inline]
pc : _raw_spin_unlock_irqrestore+0x40/0xb4 kernel/locking/spinlock.c:221
lr : __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:210 [inline]
lr : _raw_spin_unlock_irqrestore+0x80/0xb4 kernel/locking/spinlock.c:221
sp : ffff8000a3247890
x29: ffff8000a3247890 x28: dfff800000000000 x27: 0000000000000003
x26: 0000000000090d61 x25: 0000000000000000 x24: 0000000000000004
x23: 0000000000000378 x22: dead000000000122 x21: dead000000000100
x20: ffff80008e5d9d88 x19: 0000000000000000 x18: 0000000000000000
x17: 1ffff00011cfef18 x16: 00000000f1f1f1f1 x15: ffff8000883da920
x14: 1ffff0001107b524 x13: ffff80008ab24658 x12: ffff700011cbb3b2
x11: 1ffff00011cbb3b1 x10: ffff700011cbb3b1 x9 : dfff800000000000
x8 : ffff8000a3247730 x7 : ffff8000a32478a0 x6 : ffff8000a3247850
x5 : ffff8000a3247790 x4 : 0000000000000002 x3 : 1fffe00002df93a9
x2 : 0000000000000000 x1 : 00000000002cf0f9 x0 : 00000000000000c0
Call trace:
 __daif_local_irq_restore arch/arm64/include/asm/irqflags.h:175 [inline] (P)
 arch_local_irq_restore arch/arm64/include/asm/irqflags.h:195 [inline] (P)
 __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:210 [inline] (P)
 _raw_spin_unlock_irqrestore+0x40/0xb4 kernel/locking/spinlock.c:221 (P)
 __debug_check_no_obj_freed lib/debugobjects.c:1180 [inline]
 debug_check_no_obj_freed+0x280/0x558 lib/debugobjects.c:1201
 remove_vm_area+0x130/0x2a4 mm/vmalloc.c:3352
 free_vm_area+0x34/0x60 mm/vmalloc.c:4903
 arena_map_free+0xcc/0x160 kernel/bpf/arena.c:400
 bpf_map_free kernel/bpf/syscall.c:906 [inline]
 bpf_map_free_deferred+0x194/0x640 kernel/bpf/syscall.c:933
 process_one_work+0x820/0x1940 kernel/workqueue.c:3495
 process_scheduled_works kernel/workqueue.c:3578 [inline]
 worker_thread+0x42c/0xc90 kernel/workqueue.c:3659
 kthread+0x2ec/0x384 kernel/kthread.c:436
 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:870
Sending NMI from CPU 1 to CPUs 0:
NMI backtrace for cpu 0
CPU: 0 UID: 0 PID: 3404 Comm: sshd-session Tainted: G             L       syzkaller #0 PREEMPT 
Tainted: [L]=SOFTLOCKUP
Hardware name: linux,dummy-virt (DT)
pstate: 10000005 (nzcV daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : security_sock_rcv_skb+0x0/0x16c security/security.c:4497
lr : sk_filter_trim_cap+0xb8/0xb20 net/core/filter.c:156
sp : ffff80008e7e7430
x29: ffff80008e7e74e0 x28: ffff000018c59a80 x27: ffff00001be554e8
x26: ffff00001b0ff0e0 x25: 1fffe000037caab6 x24: 000000000000003f
x23: ffff000018c59a80 x22: ffff00001be555a8 x21: 0000000000000020
x20: 1ffff00011cfce8c x19: ffff00001be554e8 x18: 0000000000000000
x17: ffff7fffe1a43000 x16: ffff80008e7e0000 x15: 1fffe0000d3bb2c5
x14: 0000000000005855 x13: 0000000000000001 x12: 00000000f1f1f1f1
x11: 00000000f3f30000 x10: 1fffe000037caab3 x9 : 0000000000000000
x8 : 00000000f3f3f3f3 x7 : ffff700011cfce8c x6 : 0000000000000000
x5 : ffff00001be55566 x4 : 1fffe000037caaac x3 : 0000000000000006
x2 : 0000000000000020 x1 : ffff00001be554e8 x0 : ffff000018c59a80
Call trace:
 security_sock_rcv_skb+0x0/0x16c (P)
 tcp_filter include/net/tcp.h:1740 [inline]
 tcp_v4_rcv+0x1b90/0x3620 net/ipv4/tcp_ipv4.c:2229
 ip_protocol_deliver_rcu+0xbc/0x400 net/ipv4/ip_input.c:207
 ip_local_deliver_finish+0x288/0x5b0 net/ipv4/ip_input.c:241
 NF_HOOK include/linux/netfilter.h:325 [inline]
 NF_HOOK include/linux/netfilter.h:319 [inline]
 ip_local_deliver+0x15c/0x398 net/ipv4/ip_input.c:262
 dst_input include/net/dst.h:481 [inline]
 ip_rcv_finish+0x140/0x224 net/ipv4/ip_input.c:492
 NF_HOOK include/linux/netfilter.h:325 [inline]
 NF_HOOK include/linux/netfilter.h:319 [inline]
 ip_rcv+0xc4/0x2c4 net/ipv4/ip_input.c:612
 __netif_receive_skb_one_core+0xf8/0x174 net/core/dev.c:6405
 __netif_receive_skb+0x24/0x154 net/core/dev.c:6518
 process_backlog+0x35c/0x11e0 net/core/dev.c:6869
 __napi_poll.constprop.0+0x90/0x3c0 net/core/dev.c:7938
 napi_poll net/core/dev.c:8001 [inline]
 net_rx_action+0x774/0xad0 net/core/dev.c:8158
 handle_softirqs+0x3b4/0xf60 kernel/softirq.c:669
 __do_softirq+0x14/0x20 kernel/softirq.c:703
 ____do_softirq+0x10/0x20 arch/arm64/kernel/irq.c:78
 call_on_irq_stack+0x30/0x48 arch/arm64/kernel/entry.S:901
 do_softirq_own_stack+0x1c/0x40 arch/arm64/kernel/irq.c:83
 do_softirq kernel/softirq.c:569 [inline]
 do_softirq+0x130/0x154 kernel/softirq.c:556
 __local_bh_enable_ip+0x274/0x2e4 kernel/softirq.c:473
 local_bh_enable include/linux/bottom_half.h:33 [inline]
 rcu_read_unlock_bh include/linux/rcupdate.h:923 [inline]
 __dev_queue_xmit+0x720/0x3474 net/core/dev.c:5101
 dev_queue_xmit include/linux/netdevice.h:3483 [inline]
 neigh_hh_output include/net/neighbour.h:538 [inline]
 neigh_output include/net/neighbour.h:552 [inline]
 ip_finish_output2+0xa50/0x1e40 net/ipv4/ip_output.c:236
 __ip_finish_output net/ipv4/ip_output.c:314 [inline]
 __ip_finish_output+0x48c/0x6dc net/ipv4/ip_output.c:296
 ip_finish_output+0x34/0x2e4 net/ipv4/ip_output.c:324
 NF_HOOK_COND include/linux/netfilter.h:314 [inline]
 ip_output+0x198/0x524 net/ipv4/ip_output.c:437
 dst_output include/net/dst.h:471 [inline]
 ip_local_out net/ipv4/ip_output.c:131 [inline]
 __ip_queue_xmit+0x584/0x1780 net/ipv4/ip_output.c:533
 ip_queue_xmit+0x44/0x64 net/ipv4/ip_output.c:547
 __tcp_transmit_skb+0x174c/0x40c0 net/ipv4/tcp_output.c:1772
 tcp_transmit_skb net/ipv4/tcp_output.c:1790 [inline]
 tcp_write_xmit+0x11bc/0x7960 net/ipv4/tcp_output.c:3126
 __tcp_push_pending_frames+0x88/0x2bc net/ipv4/tcp_output.c:3309
 tcp_send_fin+0x100/0xd9c net/ipv4/tcp_output.c:3908
 tcp_shutdown+0xe4/0x12c net/ipv4/tcp.c:3084
 inet_shutdown+0x20c/0x318 net/ipv4/af_inet.c:929
 __sys_shutdown_sock net/socket.c:2556 [inline]
 __sys_shutdown_sock net/socket.c:2550 [inline]
 __sys_shutdown+0xd0/0x15c net/socket.c:2572
 __do_sys_shutdown net/socket.c:2577 [inline]
 __se_sys_shutdown net/socket.c:2575 [inline]
 __arm64_sys_shutdown+0x54/0x78 net/socket.c:2575
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x74/0x240 arch/arm64/kernel/syscall.c:49
 el0_svc_common.constprop.0+0xac/0x230 arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x40/0x58 arch/arm64/kernel/syscall.c:140
 el0_svc+0x58/0x21c arch/arm64/kernel/entry-common.c:796
 el0t_64_sync_handler+0xa0/0xe4 arch/arm64/kernel/entry-common.c:815
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:606

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/10/28 09:07 https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux master 62c457528529 96923c60 .config console log report info [disk image (non-bootable)] [vmlinux] [kernel image] ci-qemu2-arm64 BUG: soft lockup in bpf_map_free_deferred
* Struck through repros no longer work on HEAD.