KASAN: slab-out-of-bounds Write in rxrpc_send_ACK

Status: moderation: reported on 2026/11/03 08:53
Subsystems: afs net
Labels: prio:high
[Documentation on labels]
Reported-by: syzbot+0cd6f4783442ac67b56d@syzkaller.appspotmail.com
First crash: 4d02h, last: 4d02h
✨ AI-generated root cause summary:

In AF_RXRPC, when extending an ACK packet with zero pages for Path MTU Discovery probing (PMTUD), rxrpc_send_ACK() loops while len < probe_mtu and appends kvec entries to call->local->kvec without bounds-checking nr_kv against the array size (47 elements). When probe_mtu is sufficiently large (which can occur due to unsigned underflow in rxrpc_assess_MTU_size() when peer->if_mtu < peer->hdrsize, or large MTUs), nr_kv reaches and exceeds 47. This results in an out-of-bounds write of 8-byte pointers (and sizes) past the end of struct rxrpc_local in the kmalloc-2k slab cache, corrupting adjacent heap memory and causing a kernel crash.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 4dd16e31135e:

Technical Root Cause Analysis

1. Executive Summary

In AF_RXRPC, Path MTU Discovery (PMTUD) probes are implemented as RXRPC_ACK_PING packets padded with zero pages up to the trial probe MTU size (probe_mtu = call->peer->pmtud_trial + sizeof(struct rxrpc_wire_header)). In rxrpc_send_ACK() (net/rxrpc/output.c), when why == rxrpc_propose_ack_ping_for_mtu_probe, the kernel appends up to PAGE_SIZE chunks of zero pages to call->local->kvec inside a while (len < probe_mtu) loop. However, the loop fails to validate nr_kv against the capacity of call->local->kvec (which is 47 elements). When probe_mtu is large (which can occur due to unsigned underflow in rxrpc_assess_MTU_size() when peer->if_mtu < peer->hdrsize, or an excessively large MTU), nr_kv advances past index 46, performing an out-of-bounds write past the allocated 1584-byte region of struct rxrpc_local in the kmalloc-2k slab cache.


2. Detailed Technical Breakdown

Struct Layout and Object Sizing

struct rxrpc_local is defined in net/rxrpc/ar-internal.h:347. At the end of the structure (byte offset 832):

struct rxrpc_local {
    ...
    struct sockaddr_rxrpc srx; /* local address, offset 792, size 36 */
    /* offset 832 (6656 bits) */
    union {
        struct kvec kvec[1 + RXRPC_MAX_NR_JUMBO > 3 + 16 ?
                         1 + RXRPC_MAX_NR_JUMBO : 3 + 16];
        struct bio_vec bvec[3 + 16];
    };
};
  • RXRPC_MAX_NR_JUMBO is defined as 46 (net/rxrpc/protocol.h:99).
  • Therefore, kvec has 1 + 46 = 47 elements (indices 0..46).
  • Each struct kvec on 64-bit systems is 16 bytes (iov_base [8 bytes] + iov_len [8 bytes]).
  • Sizing: 47 * 16 = 752 bytes.
  • Total size of struct rxrpc_local: 832 + 752 = 1584 bytes.
  • When allocated by rxrpc_alloc_local() (net/rxrpc/local_object.c:115), it is placed in the kmalloc-2k cache with an allocated size of 1584 bytes.
PMTUD Probe Construction in rxrpc_send_ACK()

When an MTU probe ping is generated (net/rxrpc/call_event.c:484 -> rxrpc_send_probe_for_pmtud() -> rxrpc_send_ACK()):

  1. rxrpc_alloc_ack() reserves the first 3 kvec entries:
    • kv[0]: wire header and ack packet (whdr and ack)
    • kv[1]: SACK table
    • kv[2]: ack filler and trailer It returns nr_kv = 3.
  2. In rxrpc_send_ACK() (net/rxrpc/output.c:325-338):
    /* Extend a path MTU probe ACK. */
    if (why == rxrpc_propose_ack_ping_for_mtu_probe) {
        size_t probe_mtu = call->peer->pmtud_trial + sizeof(struct rxrpc_wire_header);

        if (len > probe_mtu)
            goto skip;
        while (len < probe_mtu) {
            size_t part = umin(probe_mtu - len, PAGE_SIZE);

            kv[nr_kv].iov_base = page_address(ZERO_PAGE(0));
            kv[nr_kv].iov_len = part;
            len += part;
            nr_kv++;
        }
    }
  1. The author of the union sized it assuming a PING ACK would only ever be padded up to 64K (3 + 16 entries, since 16 * 4096 = 65536).
  2. However, there is no check ensuring nr_kv < ARRAY_SIZE(call->local->kvec).
How probe_mtu Exceeds the Array Limit

In net/rxrpc/peer_object.c:210-213:

    peer->max_data      = umin(RXRPC_JUMBO(1), peer->if_mtu - peer->hdrsize);
    peer->pmtud_good    = 500;
    peer->pmtud_bad     = peer->if_mtu - peer->hdrsize + 1;
    peer->pmtud_trial   = umin(peer->max_data, peer->pmtud_bad - 1);
    peer->pmtud_pending = true;

peer->if_mtu and peer->hdrsize are unsigned integers (unsigned int and unsigned short). When peer->if_mtu is less than peer->hdrsize (for instance, when a network device MTU is configured to a very small value, or when MTU is 0 on devices where dev->min_mtu == 0), peer->if_mtu - peer->hdrsize unsigned-underflows to a value near UINT_MAX. In net/rxrpc/peer_event.c:450, rxrpc_input_probe_for_pmtud() updates trial:

    trial = (good + bad) / 2;
    peer->pmtud_trial = trial;

Without strict bounding against the maximum allowable probe size or ARRAY_SIZE(call->local->kvec), pmtud_trial can easily reach or exceed 180,224 bytes.

When probe_mtu >= 180,250, the padding loop executes 44 or more times:

  • nr_kv increments from 3 to 47.
  • At iteration 44 (nr_kv == 47), the code accesses kv[47].iov_base.
  • Offset calculation: 832 + 47 * 16 = 1584 bytes.
  • This immediately writes 8 bytes (page_address(ZERO_PAGE(0))) at byte offset 1584—exactly 0 bytes past the end of the 1584-byte allocated rxrpc_local object.

3. Classification and Production Impact

  • RootCauseFiles:
    • net/rxrpc/output.c: Missing bounds check on nr_kv against ARRAY_SIZE(call->local->kvec) in rxrpc_send_ACK().
    • net/rxrpc/peer_object.c: Unsigned underflow vulnerability in rxrpc_assess_MTU_size() when calculating peer->if_mtu - peer->hdrsize.
  • MemoryCorruption: true. Writing iov_base (8 bytes) and iov_len (8 bytes) beyond the boundary of struct rxrpc_local corrupts the slab metadata and/or the payload of the neighboring object in the kmalloc-2k slab cache.
  • InfoLeak: "none". The memory appended to the I/O vector consists of zero-page addresses (ZERO_PAGE(0)). No out-of-bounds or uninitialized heap/stack memory is leaked or transmitted.
  • RawDenialOfService: true. Corrupting adjacent slab objects in kmalloc-2k leads to kernel crashes, data structure corruption, or kernel panic in production kernels.
  • IsNetCandidate: true. The defect is in the RxRPC network socket implementation (AF_RXRPC), specifically in packet output and PMTUD processing.
  • IsKVMCandidate: false. Virtualization and KVM subsystems are not involved.
▶ ▼ ✨ AI Jobs (3)
ID Workflow Result Correct Bug Created Started Finished Revision
bddfaa40 repro-c 💥 KASAN: slab-out-of-bounds Write in rxrpc_send_ACK 2026/11/03 00:04 2026/11/03 00:04 2026/11/03 10:34 0a94d799
206df64d repro-c 💥 KASAN: slab-out-of-bounds Write in rxrpc_send_ACK 2026/11/02 00:03 2026/11/02 00:03 2026/11/02 09:12 25a0ae84
d27e7f23 assessment-security DenialOfService: ✅ Exploitable: ✅ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ✅ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ✅ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KASAN: slab-out-of-bounds Write in rxrpc_send_ACK 2026/10/30 08:42 2026/10/30 08:43 2026/10/30 10:23 b498adee

Sample crash report:
==================================================================
BUG: KASAN: slab-out-of-bounds in rxrpc_send_ACK+0x1764/0x2f50 net/rxrpc/output.c:333
Write of size 8 at addr ffff88807622b630 by task krxrpcio/22136/14026

CPU: 1 UID: 0 PID: 14026 Comm: krxrpcio/22136 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/07/2026
Call Trace:
 <TASK>
 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
 rxrpc_send_ACK+0x1764/0x2f50 net/rxrpc/output.c:333
 rxrpc_input_call_event+0x1201/0x17c0 net/rxrpc/call_event.c:484
 rxrpc_io_thread+0x2b9a/0x3290 net/rxrpc/io_thread.c:531
 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>

Allocated by task 14023:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:409 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:426
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __kmalloc_cache_noprof+0x31c/0x600 mm/slub.c:5680
 _kmalloc_noprof include/linux/slab.h:991 [inline]
 _kzalloc_noprof include/linux/slab.h:1312 [inline]
 rxrpc_alloc_local net/rxrpc/local_object.c:115 [inline]
 rxrpc_lookup_local+0x57e/0x15d0 net/rxrpc/local_object.c:289
 rxrpc_bind+0x187/0x450 net/rxrpc/af_rxrpc.c:151
 __sys_bind_socket net/socket.c:1947 [inline]
 __sys_bind+0x2e3/0x410 net/socket.c:1978
 __do_sys_bind net/socket.c:1983 [inline]
 __se_sys_bind net/socket.c:1981 [inline]
 __x64_sys_bind+0x7a/0x90 net/socket.c:1981
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88807622b000
 which belongs to the cache kmalloc-2k of size 2048
The buggy address is located 0 bytes to the right of
 allocated 1584-byte region [ffff88807622b000, ffff88807622b630)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x76228
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000040 ffff88813ff23000 dead000000000100 dead000000000122
raw: 0000000000000000 0000000000080008 00000000f5000000 0000000000000000
head: 00fff00000000040 ffff88813ff23000 dead000000000100 dead000000000122
head: 0000000000000000 0000000000080008 00000000f5000000 0000000000000000
head: 00fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 12448, tgid 12445 (syz.2.1590), ts 304361135443
 set_page_owner include/linux/page_owner.h:33 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1856
 prep_new_page mm/page_alloc.c:1864 [inline]
 get_page_from_freelist+0x220f/0x2280 mm/page_alloc.c:3935
 __alloc_frozen_pages_noprof+0x1fe/0x410 mm/page_alloc.c:5444
 alloc_slab_page mm/slub.c:3384 [inline]
 allocate_slab+0x7d/0x5e0 mm/slub.c:3499
 new_slab mm/slub.c:3550 [inline]
 refill_objects+0x2d5/0x350 mm/slub.c:7539
 refill_sheaf mm/slub.c:2917 [inline]
 __pcs_replace_empty_main+0x2c8/0x6c0 mm/slub.c:4811
 alloc_from_pcs mm/slub.c:4887 [inline]
 slab_alloc_node mm/slub.c:5021 [inline]
 __do_kmalloc_node mm/slub.c:5530 [inline]
 __kmalloc_node_track_caller_noprof+0x543/0x720 mm/slub.c:5662
 kmalloc_reserve net/core/skbuff.c:638 [inline]
 __alloc_skb+0x2c1/0x7a0 net/core/skbuff.c:716
 alloc_skb include/linux/skbuff.h:1390 [inline]
 nlmsg_new include/net/netlink.h:1055 [inline]
 rtmsg_ifinfo_build_skb+0x7f/0x260 net/core/rtnetlink.c:4617
 unregister_netdevice_many_notify+0x14b9/0x1d80 net/core/dev.c:12728
 vlan_device_event+0x143d/0x1580 net/8021q/vlan.c:453
 notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:86
 call_netdevice_notifiers_extack net/core/dev.c:2351 [inline]
 call_netdevice_notifiers net/core/dev.c:2365 [inline]
 unregister_netdevice_many_notify+0x1432/0x1d80 net/core/dev.c:12725
 rtnl_delete_link net/core/rtnetlink.c:3689 [inline]
 rtnl_dellink+0x5bc/0x810 net/core/rtnetlink.c:3731
 rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7169
 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2584
page last free pid 12455 tgid 12455 ts 304307498007 stack trace:
 reset_page_owner include/linux/page_owner.h:26 [inline]
 __free_pages_prepare mm/page_alloc.c:1403 [inline]
 __free_frozen_pages+0xc97/0xd90 mm/page_alloc.c:2954
 __slab_free+0x269/0x2c0 mm/slub.c:5926
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:361
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4720 [inline]
 slab_alloc_node mm/slub.c:5033 [inline]
 kmem_cache_alloc_noprof+0x2b4/0x600 mm/slub.c:5047
 vm_area_alloc+0x24/0x140 mm/vma_init.c:36
 __mmap_new_vma mm/vma.c:2700 [inline]
 __mmap_region mm/vma.c:3054 [inline]
 mmap_region+0x18ff/0x2840 mm/vma.c:3136
 do_mmap+0xe0a/0x1300 mm/mmap.c:573
 vm_mmap_pgoff+0x27a/0x520 mm/util.c:581
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Memory state around the buggy address:
 ffff88807622b500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff88807622b580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffff88807622b600: 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc
                                     ^
 ffff88807622b680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff88807622b700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/10/30 08:42 net-next 4dd16e31135e b498adee .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-net-kasan-gce KASAN: slab-out-of-bounds Write in rxrpc_send_ACK
* Struck through repros no longer work on HEAD.