KASAN: use-after-free Read in wg_packet_receive

Status: moderation: reported on 2026/11/03 12:02
Subsystems: wireguard
Labels: prio:high
[Documentation on labels]
Reported-by: syzbot+1ec8bc6aa38738327f91@syzkaller.appspotmail.com
First crash: 4d06h, last: 4d06h
✨ AI-generated root cause summary:

In WireGuard packet reception (wg_packet_receive()), incoming handshake packets are scheduled via queue_work_on() onto the per-CPU handshake_receive_wq. When __queue_work() resolves the pool_workqueue for the target CPU via pwq = rcu_dereference(*per_cpu_ptr(wq->cpu_pwq, cpu)), it dereferences pwq->pool. If the pool_workqueue has been released or destroyed (for instance due to CPU offline rebalancing or workqueue teardown racing with packet ingestion), this results in a use-after-free read of the freed pool_workqueue. In a production kernel, this causes memory corruption and kernel oops/panic.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 5838f10563d5:

Detailed Technical Analysis

1. Root Cause Analysis

The crash report shows a KASAN use-after-free read of 8 bytes at address 0xffff88814d151c00 inside __queue_work+0x609/0x1360 (kernel/workqueue.c:2463):

pwq = rcu_dereference(*per_cpu_ptr(wq->cpu_pwq, cpu));
pool = pwq->pool;

In struct pool_workqueue, the pointer struct worker_pool *pool is located at offset 0 (pool = pwq->pool). The address 0xffff88814d151c00 corresponds to a struct pool_workqueue (pwq) that resides on a slab page which has already been returned to the page allocator (KASAN_PAGE_FREE shadow value 0xff, physical page refcount 0).

The invocation originates from the WireGuard packet reception path:

  1. wg_packet_handshake_send_worker() (drivers/net/wireguard/send.c:51) executes on workqueue wg-kex-wg1 to send a handshake initiation.
  2. In wg_socket_send_skb_to_peer(), read_unlock_bh(&peer->endpoint_lock) enables bottom-halves (__local_bh_enable_ip), invoking pending softirqs.
  3. Softirq processing (net_rx_action -> process_backlog -> udp_rcv -> wg_receive) receives a packet destined for a WireGuard UDP tunnel socket.
  4. wg_receive() retrieves wg = sk->sk_user_data and invokes wg_packet_receive(wg, skb).
  5. For incoming handshake packets, wg_packet_receive() chooses a CPU via wg_cpumask_next_online(&wg->handshake_queue.last_cpu) and attempts to enqueue work on wg->handshake_receive_wq:
    queue_work_on(cpu, wg->handshake_receive_wq,
                  &per_cpu_ptr(wg->handshake_queue.worker, cpu)->work);
    
  6. In __queue_work() (kernel/workqueue.c:2462-2463), the target CPU is passed as req_cpu. Under RCU read lock, pwq = rcu_dereference(*per_cpu_ptr(wq->cpu_pwq, cpu)) is dereferenced.
  7. If the pool_workqueue (or workqueue attributes/topology) was destroyed or reallocated (for example during CPU offline/hotplug operations or asynchronous workqueue teardown), pwq points to memory that has been reclaimed by RCU (kfree_rcu(pwq, rcu)). Dereferencing pwq->pool at offset 0 accesses freed memory.

2. Exact Functions, Structs, and Files Involved

3. Runtime Consequences in a Production Kernel

  • MemoryCorruption: true. Dereferencing freed memory inside __queue_work() leads to accessing wild/stale pool pointers and acquiring uninitialized/stale spinlocks (raw_spin_lock(&pool->lock)). Subsequent operations attempt to manipulate linked lists (insert_work()), leading to arbitrary kernel memory corruption.
  • InfoLeak: none. The defect does not expose or copy kernel memory buffers to userspace or network interfaces.
  • RawDenialOfService: true. The invalid dereference triggers a kernel oops / page fault panic in production environments.
  • IsNetCandidate: true. The issue occurs directly in network packet processing (WireGuard UDP encapsulation receiving path via net_rx_action / udp_rcv / wg_receive).
  • IsKVMCandidate: false. The issue is unrelated to KVM, virtualization, or guest/hypervisor boundaries.
▶ ▼ ✨ AI Jobs (2)
ID Workflow Result Correct Bug Created Started Finished Revision
129c4e93 repro-c 💥 KASAN: use-after-free Read in wg_packet_receive 2026/11/02 15:09 2026/11/02 15:09 2026/11/03 04:04 0a94d799
b1e6806c assessment-security DenialOfService: ✅ Exploitable: ✅ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ✅ NetworkNeedsSetup: ✅ NetworkTrigger: ✅ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ✅ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KASAN: use-after-free Read in wg_packet_receive 2026/10/30 11:51 2026/10/30 11:51 2026/10/30 12:55 b498adee
▶ ▼ Similar bugs (3)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
android-6-1 KASAN: use-after-free Read in wg_packet_receive 19 1 876d 876d 0/2 auto-obsoleted due to no activity on 2024/09/07 23:22
upstream general protection fault in wg_packet_receive (2) wireguard 2 2 678d 770d 0/29 auto-obsoleted due to no activity on 2025/04/04 16:15
upstream general protection fault in wg_packet_receive wireguard 2 3 871d 890d 0/29 auto-obsoleted due to no activity on 2024/09/22 21:29

Sample crash report:
==================================================================
BUG: KASAN: use-after-free in __queue_work+0x609/0x1360 kernel/workqueue.c:2463
Read of size 8 at addr ffff88814d151c00 by task kworker/u8:4/62

CPU: 1 UID: 0 PID: 62 Comm: kworker/u8:4 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/07/2026
Workqueue: wg-kex-wg1 wg_packet_handshake_send_worker
Call Trace:
 <IRQ>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 __queue_work+0x609/0x1360 kernel/workqueue.c:2463
 queue_work_on+0x106/0x1d0 kernel/workqueue.c:2599
 wg_packet_receive+0x115d/0x2350 drivers/net/wireguard/receive.c:570
 wg_receive+0x75/0xa0 drivers/net/wireguard/socket.c:325
 udp_queue_rcv_one_skb+0xfc5/0x10e0 net/ipv4/udp.c:2433
 udp_unicast_rcv_skb+0x21a/0x3a0 net/ipv4/udp.c:2621
 udp_rcv+0xf2d/0x1e60 net/ipv4/udp.c:2698
 ip_protocol_deliver_rcu+0x27e/0x440 net/ipv4/ip_input.c:207
 ip_local_deliver_finish+0x3bb/0x6f0 net/ipv4/ip_input.c:241
 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
 NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:325
 __netif_receive_skb_one_core net/core/dev.c:6433 [inline]
 __netif_receive_skb net/core/dev.c:6546 [inline]
 process_backlog+0xa6b/0x18b0 net/core/dev.c:6897
 __napi_poll+0xaa/0x330 net/core/dev.c:7966
 napi_poll net/core/dev.c:8029 [inline]
 net_rx_action+0x61d/0xf50 net/core/dev.c:8186
 handle_softirqs+0x265/0x8d0 kernel/softirq.c:669
 do_softirq+0x77/0xd0 kernel/softirq.c:569
 </IRQ>
 <TASK>
 __local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
 wg_socket_send_skb_to_peer+0x16b/0x1d0 drivers/net/wireguard/socket.c:183
 wg_packet_send_handshake_initiation drivers/net/wireguard/send.c:40 [inline]
 wg_packet_handshake_send_worker+0x204/0x370 drivers/net/wireguard/send.c:51
 process_one_work kernel/workqueue.c:3495 [inline]
 process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3578
 worker_thread+0xa47/0xfb0 kernel/workqueue.c:3659
 kthread+0x38b/0x480 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x14d151
flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff)
raw: 057ff00000000000 ffffea0005345448 ffffea0005345448 0000000000000000
raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
page_owner info is not present (never set?)

Memory state around the buggy address:
 ffff88814d151b00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff88814d151b80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff88814d151c00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
                   ^
 ffff88814d151c80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff88814d151d00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/10/30 11:51 net 5838f10563d5 b498adee .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-net-this-kasan-gce KASAN: use-after-free Read in wg_packet_receive
* Struck through repros no longer work on HEAD.