[PATCH net 1/1] rxrpc: fix encap_rcv skb accounting exhaustion
From: Ren Wei <hidden>
Date: 2026-07-23 17:43:49
Subsystem:
networking [general], rxrpc sockets (af_rxrpc), the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Howells, Marc Dionne, Linus Torvalds
From: Zihan Xi <redacted>
rxrpc_encap_rcv() moves encapsulated UDP packets onto the local
RxRPC 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 local queue grows
without bound and consumes large amounts of memory.
Reaccount encapsulated packets against the UDP socket before queueing
them on the RxRPC local queue and drop packets once the socket rcvbuf
limit is reached. Clear sk_user_data under RCU protection and release
the socket only after queued skbs are purged so the new skb ownership
does not outlive the UDP socket.
Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <redacted>
Signed-off-by: Ren Wei <redacted>
---
net/rxrpc/io_thread.c | 15 +++++++++++++--
net/rxrpc/local_object.c | 8 ++++++--
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
index dc5184a2f..85411a2d8 100644
--- a/net/rxrpc/io_thread.c
+++ b/net/rxrpc/io_thread.c@@ -41,8 +41,6 @@ int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb) if (skb->tstamp == 0) skb->tstamp = ktime_get_real(); - skb->mark = RXRPC_SKB_MARK_PACKET; - rxrpc_new_skb(skb, rxrpc_skb_new_encap_rcv); rx_queue = &local->rx_queue; #ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY if (rxrpc_inject_rx_delay ||
@@ -52,6 +50,19 @@ int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb) } #endif + if (atomic_read(&udp_sk->sk_rmem_alloc) >= READ_ONCE(udp_sk->sk_rcvbuf) || + !sk_rmem_schedule(udp_sk, skb, skb->truesize)) { + atomic_inc(&udp_sk->sk_drops); + kfree_skb(skb); + return 0; + } + + skb->dev = NULL; + skb_set_owner_r(skb, udp_sk); + skb_dst_force(skb); + + skb->mark = RXRPC_SKB_MARK_PACKET; + rxrpc_new_skb(skb, rxrpc_skb_new_encap_rcv); skb_queue_tail(rx_queue, skb); wake_up_process(io_thread); return 0;
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c
index 169f9dfda..6604f9f95 100644
--- a/net/rxrpc/local_object.c
+++ b/net/rxrpc/local_object.c@@ -437,8 +437,8 @@ void rxrpc_destroy_local(struct rxrpc_local *local) if (socket) { local->socket = NULL; kernel_sock_shutdown(socket, SHUT_RDWR); - socket->sk->sk_user_data = NULL; - sock_release(socket); + rcu_assign_sk_user_data(socket->sk, NULL); + synchronize_rcu(); } /* At this point, there should be no more packets coming in to the
@@ -448,6 +448,10 @@ void rxrpc_destroy_local(struct rxrpc_local *local) rxrpc_purge_queue(&local->rx_delay_queue); #endif rxrpc_purge_queue(&local->rx_queue); + + if (socket) + sock_release(socket); + rxrpc_purge_client_connections(local); page_frag_cache_drain(&local->tx_alloc); }
--
2.43.0