FAILED: patch "[PATCH] rxrpc: Fix potential UAF after skb_unshare() failure" failed to apply to 6.6-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 1f2740150f904bfa60e4bad74d65add3ccb5e7f8
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026050105-bless-arrogant-1e69@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 1f2740150f904bfa60e4bad74d65add3ccb5e7f8 Mon Sep 17 00:00:00 2001
From: David Howells <[email protected]>
Date: Wed, 22 Apr 2026 17:14:32 +0100
Subject: [PATCH] rxrpc: Fix potential UAF after skb_unshare() failure
If skb_unshare() fails to unshare a packet due to allocation failure in rxrpc_input_packet(), the skb pointer in the parent (rxrpc_io_thread()) will be NULL'd out. This will likely cause the call to trace_rxrpc_rx_done() to oops.
Fix this by moving the unsharing down to where rxrpc_input_call_event() calls rxrpc_input_call_packet(). There are a number of places prior to that where we ignore DATA packets for a variety of reasons (such as the call already being complete) for which an unshare is then avoided.
And with that, rxrpc_input_packet() doesn't need to take a pointer to the pointer to the packet, so change that to just a pointer.
include/trace/events/rxrpc.h +2 -2
@@ -162,8 +162,6 @@ E_(rxrpc_call_poke_timer_now, "Timer-now")#define rxrpc_skb_traces \ - EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \ - EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \ EM(rxrpc_skb_get_call_rx, "GET call-rx ") \ EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \ EM(rxrpc_skb_get_conn_work, "GET conn-work") \
@@ -190,6 +188,7 @@ EM(rxrpc_skb_put_purge, "PUT purge ") \ EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \ EM(rxrpc_skb_put_response, "PUT response ") \ + EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \ EM(rxrpc_skb_put_rotate, "PUT rotate ") \ EM(rxrpc_skb_put_unknown, "PUT unknown ") \EM (rxrpc_skb_see_conn_work,"SEE conn-work" ) \
@@ -198,6 +197,7 @@ EM(rxrpc_skb_see_recvmsg_oob, "SEE recvm-oob") \ EM(rxrpc_skb_see_reject, "SEE reject ") \ EM(rxrpc_skb_see_rotate, "SEE rotate ") \ + EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \ E_(rxrpc_skb_see_version, "SEE version ")#define rxrpc_local_traces \
net/rxrpc/ar-internal.h +0 -1
@@ -1486,7 +1486,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);void rxrpc_kernel_data_consumed (struct rxrpc_call *,struct sk_buff *);void rxrpc_new_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_see_skb (struct sk_buff *,enum rxrpc_skb_trace ); -void rxrpc_eaten_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_get_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_free_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_purge_queue (struct sk_buff_head *);
net/rxrpc/call_event.c +18 -1
@@ -332,7 +332,24 @@ bool rxrpc_input_call_event(struct rxrpc_call *call) saw_ack |= sp->hdr.type ==RXRPC_PACKET_TYPE_ACK ; -rxrpc_input_call_packet (call, skb); +if (sp->hdr.securityIndex !=0 && +skb_cloned (skb)) { +/* Unshare the packet so that it can be +* modified by in-place decryption. +*/ +struct sk_buff *nskb =skb_copy (skb,GFP_ATOMIC ); + +if (nskb) { +rxrpc_new_skb (nskb, rxrpc_skb_new_unshared); +rxrpc_input_call_packet (call, nskb); +rxrpc_free_skb (nskb, rxrpc_skb_put_call_rx); + }else { +/* OOM - Drop the packet. */ +rxrpc_see_skb (skb, rxrpc_skb_see_unshare_nomem); + } + }else { +rxrpc_input_call_packet (call, skb); + }rxrpc_free_skb (skb, rxrpc_skb_put_call_rx); did_receive = true; }
net/rxrpc/io_thread.c +2 -22
@@ -192,13 +192,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)/* * Process packets received on the local endpoint */ -static bool rxrpc_input_packet (struct rxrpc_local *local,struct sk_buff **_skb) +static bool rxrpc_input_packet (struct rxrpc_local *local,struct sk_buff *skb) {struct rxrpc_connection *conn;struct sockaddr_rxrpc peer_srx;struct rxrpc_skb_priv *sp;struct rxrpc_peer *peer =NULL ; -struct sk_buff *skb = *_skb;bool ret = false;skb_pull (skb,sizeof (struct udphdr ));
@@ -244,25 +243,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)return rxrpc_bad_message (skb, rxrpc_badmsg_zero_call);if (sp->hdr.seq ==0 )return rxrpc_bad_message (skb, rxrpc_badmsg_zero_seq); - -/* Unshare the packet so that it can be modified for in-place -* decryption. -*/ -if (sp->hdr.securityIndex !=0 ) { - skb =skb_unshare (skb,GFP_ATOMIC ); -if (!skb) { -rxrpc_eaten_skb (*_skb, rxrpc_skb_eaten_by_unshare_nomem); - *_skb =NULL ; -return just_discard; - } - -if (skb != *_skb) { -rxrpc_eaten_skb (*_skb, rxrpc_skb_eaten_by_unshare); - *_skb = skb; -rxrpc_new_skb (skb, rxrpc_skb_new_unshared); - sp =rxrpc_skb (skb); - } - }break ;case RXRPC_PACKET_TYPE_CHALLENGE :
@@ -494,7 +474,7 @@ int rxrpc_io_thread(void *data)switch (skb->mark) {case RXRPC_SKB_MARK_PACKET : skb->priority =0 ; -if (!rxrpc_input_packet (local, &skb)) +if (!rxrpc_input_packet (local, skb))rxrpc_reject_packet (local, skb);trace_rxrpc_rx_done (skb->mark, skb->priority);rxrpc_free_skb (skb, rxrpc_skb_put_input);
net/rxrpc/skbuff.c +0 -9
@@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)skb_get (skb); } -/* -* Note the dropping of a ref on a socket buffer by the core. -*/ -void rxrpc_eaten_skb (struct sk_buff *skb,enum rxrpc_skb_trace why) -{ -int n =atomic_inc_return (&rxrpc_n_rx_skbs); -trace_rxrpc_skb (skb,0 , n, why); -} -/* * Note the destruction of a socket buffer. */
Sasha Levin
maintainerPATCH 1/1 rxrpc: Fix potential UAF after skb_unshare() failure
From: David Howells <[email protected]>
[ Upstream commit 1f2740150f904bfa60e4bad74d65add3ccb5e7f8 ]
If skb_unshare() fails to unshare a packet due to allocation failure in rxrpc_input_packet(), the skb pointer in the parent (rxrpc_io_thread()) will be NULL'd out. This will likely cause the call to trace_rxrpc_rx_done() to oops.
Fix this by moving the unsharing down to where rxrpc_input_call_event() calls rxrpc_input_call_packet(). There are a number of places prior to that where we ignore DATA packets for a variety of reasons (such as the call already being complete) for which an unshare is then avoided.
And with that, rxrpc_input_packet() doesn't need to take a pointer to the pointer to the packet, so change that to just a pointer.
--- include/trace/events/rxrpc.h | 3 +-- net/rxrpc/ar-internal.h | 1 - net/rxrpc/call_event.c | 23 +++++++++++++++++++++-- net/rxrpc/io_thread.c | 24 ++---------------------- net/rxrpc/skbuff.c | 9 --------- 5 files changed, 24 insertions(+), 36 deletions(-)
include/trace/events/rxrpc.h +1 -2
@@ -125,8 +125,6 @@ E_(rxrpc_call_poke_timer_now, "Timer-now")#define rxrpc_skb_traces \ - EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \ - EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \ EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \ EM(rxrpc_skb_get_conn_work, "GET conn-work") \ EM(rxrpc_skb_get_last_nack, "GET last-nack") \
@@ -151,6 +149,7 @@ EM(rxrpc_skb_see_recvmsg, "SEE recvmsg ") \ EM(rxrpc_skb_see_reject, "SEE reject ") \ EM(rxrpc_skb_see_rotate, "SEE rotate ") \ + EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \ E_(rxrpc_skb_see_version, "SEE version ")#define rxrpc_local_traces \
net/rxrpc/ar-internal.h +0 -1
@@ -1269,7 +1269,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);void rxrpc_kernel_data_consumed (struct rxrpc_call *,struct sk_buff *);void rxrpc_new_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_see_skb (struct sk_buff *,enum rxrpc_skb_trace ); -void rxrpc_eaten_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_get_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_free_skb (struct sk_buff *,enum rxrpc_skb_trace );void rxrpc_purge_queue (struct sk_buff_head *);
net/rxrpc/call_event.c +21 -2
@@ -456,8 +456,27 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) resend = true; } -if (skb) -rxrpc_input_call_packet (call, skb); +if (skb) { +struct rxrpc_skb_priv *sp =rxrpc_skb (skb); + +if (sp->hdr.securityIndex !=0 &&skb_cloned (skb)) { +/* Unshare the packet so that it can be modified by +* in-place decryption. +*/ +struct sk_buff *nskb =skb_copy (skb,GFP_ATOMIC ); + +if (nskb) { +rxrpc_new_skb (nskb, rxrpc_skb_new_unshared); +rxrpc_input_call_packet (call, nskb); +rxrpc_free_skb (nskb, rxrpc_skb_put_input); + }else { +/* OOM - Drop the packet. */ +rxrpc_see_skb (skb, rxrpc_skb_see_unshare_nomem); + } + }else { +rxrpc_input_call_packet (call, skb); + } + }rxrpc_transmit_some_data (call);
net/rxrpc/io_thread.c +2 -22
@@ -167,13 +167,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)/* * Process packets received on the local endpoint */ -static bool rxrpc_input_packet (struct rxrpc_local *local,struct sk_buff **_skb) +static bool rxrpc_input_packet (struct rxrpc_local *local,struct sk_buff *skb) {struct rxrpc_connection *conn;struct sockaddr_rxrpc peer_srx;struct rxrpc_skb_priv *sp;struct rxrpc_peer *peer =NULL ; -struct sk_buff *skb = *_skb;bool ret = false;skb_pull (skb,sizeof (struct udphdr ));
@@ -219,25 +218,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)return rxrpc_bad_message (skb, rxrpc_badmsg_zero_call);if (sp->hdr.seq ==0 )return rxrpc_bad_message (skb, rxrpc_badmsg_zero_seq); - -/* Unshare the packet so that it can be modified for in-place -* decryption. -*/ -if (sp->hdr.securityIndex !=0 ) { - skb =skb_unshare (skb,GFP_ATOMIC ); -if (!skb) { -rxrpc_eaten_skb (*_skb, rxrpc_skb_eaten_by_unshare_nomem); - *_skb =NULL ; -return just_discard; - } - -if (skb != *_skb) { -rxrpc_eaten_skb (*_skb, rxrpc_skb_eaten_by_unshare); - *_skb = skb; -rxrpc_new_skb (skb, rxrpc_skb_new_unshared); - sp =rxrpc_skb (skb); - } - }break ;case RXRPC_PACKET_TYPE_CHALLENGE :
@@ -479,7 +459,7 @@ int rxrpc_io_thread(void *data)switch (skb->mark) {case RXRPC_SKB_MARK_PACKET : skb->priority =0 ; -if (!rxrpc_input_packet (local, &skb)) +if (!rxrpc_input_packet (local, skb))rxrpc_reject_packet (local, skb);trace_rxrpc_rx_done (skb->mark, skb->priority);rxrpc_free_skb (skb, rxrpc_skb_put_input);
net/rxrpc/skbuff.c +0 -9
@@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)skb_get (skb); } -/* -* Note the dropping of a ref on a socket buffer by the core. -*/ -void rxrpc_eaten_skb (struct sk_buff *skb,enum rxrpc_skb_trace why) -{ -int n =atomic_inc_return (&rxrpc_n_rx_skbs); -trace_rxrpc_skb (skb,0 , n, why); -} -/* * Note the destruction of a socket buffer. */
Signature · 1 line
2.53.0