FAILED: patch "[PATCH] rxrpc: Fix RESPONSE packet verification to extract skb to a" failed to apply to 6.6-stable tree
Subsystems (3)
[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 8bfab4b6ffc2fe92da86300728fc8c3c7ebffb56
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026052809-espresso-heftiness-bdb0@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 8bfab4b6ffc2fe92da86300728fc8c3c7ebffb56 Mon Sep 17 00:00:00 2001
From: David Howells <[email protected]>
Date: Sat, 16 May 2026 00:05:15 +0100
Subject: [PATCH] rxrpc: Fix RESPONSE packet verification to extract skb to a
linear buffer
This improves the fix for CVE-2026-43500.
Fix the verification of RESPONSE packets to avoid the problem of overwriting a RESPONSE packet sent via splice to a local address by extracting the contents of the UDP packet into a kmalloc'd linear buffer rather than decrypting the data in place in the sk_buff (which may corrupt the original buffer).
net/rxrpc/ar-internal.h +4 -3
@@ -307,15 +307,16 @@ struct rxrpc_security { struct sk_buff *challenge);/* verify a response */ -int (*verify_response)(struct rxrpc_connection *, -struct sk_buff *); +int (*verify_response)(struct rxrpc_connection *conn, +struct sk_buff *response_skb, +void *response,unsigned int len);/* clear connection security */ void (*clear)(struct rxrpc_connection *);/* Default ticket -> key decoder */ int (*default_decode_ticket)(struct rxrpc_connection *conn,struct sk_buff *skb, -unsigned int ticket_offset,unsigned int ticket_len, +void *ticket,unsigned int ticket_len,struct key **_key); };
net/rxrpc/conn_event.c +12 -18
@@ -243,28 +243,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)static int rxrpc_verify_response (struct rxrpc_connection *conn,struct sk_buff *skb) { +unsigned int len = skb->len -sizeof (struct rxrpc_wire_header ); +void *buffer;int ret; -if (skb_cloned (skb) ||skb_has_frag_list (skb) || -skb_has_shared_frag (skb)) { -/* Copy the packet if shared so that we can do in-place -* decryption. -*/ -struct sk_buff *nskb =skb_copy (skb,GFP_NOFS ); + buffer =kmalloc (len,GFP_NOFS ); +if (!buffer) +return -ENOMEM ; -if (nskb) { -rxrpc_new_skb (nskb, rxrpc_skb_new_unshared); - ret = conn->security->verify_response (conn, nskb); -rxrpc_free_skb (nskb, rxrpc_skb_put_response_copy); - }else { -/* OOM - Drop the packet. */ -rxrpc_see_skb (skb, rxrpc_skb_see_unshare_nomem); - ret = -ENOMEM ; - } - }else { - ret = conn->security->verify_response (conn, skb); - } + ret =skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ), buffer, len); +if (ret <0 ) + goto out; + ret = conn->security->verify_response (conn, skb, buffer, len); + +out: +kfree (buffer);return ret; }
net/rxrpc/insecure.c +3 -2
@@ -54,9 +54,10 @@ static int none_sendmsg_respond_to_challenge(struct sk_buff *challenge, }static int none_verify_response (struct rxrpc_connection *conn, -struct sk_buff *skb) +struct sk_buff *response_skb, +void *response,unsigned int len) { -return rxrpc_abort_conn (conn, skb,RX_PROTOCOL_ERROR , -EPROTO , +return rxrpc_abort_conn (conn, response_skb,RX_PROTOCOL_ERROR , -EPROTO , rxrpc_eproto_rxnull_response); }
net/rxrpc/rxgk.c +32 -66
161 lines not on this page · raw message
net/rxrpc/rxgk_app.c +19 -27
115 lines not on this page · raw message
net/rxrpc/rxgk_common.h +2 -90
112 lines not on this page · raw message
net/rxrpc/rxkad.c +10 -19
@@ -963,7 +963,6 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, *_expiry =0 ;ASSERT (server_key->payload.data[0 ] !=NULL ); - ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);memcpy (&iv, &server_key->payload.data[2 ],sizeof (iv));
@@ -1112,14 +1111,15 @@ unlock:* verify a response */ static int rxkad_verify_response (struct rxrpc_connection *conn, -struct sk_buff *skb) +struct sk_buff *skb, +void *buffer,unsigned int len) {struct rxkad_response *response;struct rxrpc_skb_priv *sp =rxrpc_skb (skb);struct rxrpc_crypt session_key;struct key *server_key;time64_t expiry; -void *ticket =NULL ; +void *ticket;u32 version, kvno, ticket_len, level;__be32 csum;int ret, i;
@@ -1142,13 +1142,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, } } - ret = -ENOMEM ; - response = kzalloc_obj(struct rxkad_response, GFP_NOFS); -if (!response) - goto error; - -if (skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ), - response,sizeof (*response)) <0 ) { + response = buffer; +if (len <sizeof (*response)) { ret =rxrpc_abort_conn (conn, skb,RXKADPACKETSHORT , -EPROTO , rxkad_abort_resp_short); goto error;
@@ -1160,6 +1155,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,trace_rxrpc_rx_response (conn, sp->hdr.serial, version, kvno, ticket_len); + buffer +=sizeof (*response); + len -=sizeof (*response); +if (version !=RXKAD_VERSION ) { ret =rxrpc_abort_conn (conn, skb,RXKADINCONSISTENCY , -EPROTO , rxkad_abort_resp_version);
@@ -1179,13 +1177,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, }/* extract the kerberos ticket and decrypt and decode it */ - ret = -ENOMEM ; - ticket =kmalloc (ticket_len,GFP_NOFS ); -if (!ticket) - goto error; - -if (skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ) +sizeof (*response), - ticket, ticket_len) <0 ) { + ticket = buffer; +if (ticket_len > len) { ret =rxrpc_abort_conn (conn, skb,RXKADPACKETSHORT , -EPROTO , rxkad_abort_resp_short_tkt); goto error;
@@ -1265,8 +1258,6 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, ret =rxrpc_get_server_data_key (conn, &session_key, expiry, kvno); error: -kfree (ticket); -kfree (response);key_put (server_key);_leave (" = %d" , ret);return ret;
Sasha Levin
maintainerPATCH 1/2 rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg
From: David Howells <[email protected]>
[ Upstream commit d2bc90cf6c75cb96d2ce549be6c35efa3099d25b ]
This improves the fix for CVE-2026-43500.
Fix the pagecache corruption from in-place decryption of a DATA packet transmitted locally by splice() by getting rid of the packet sharing in the I/O thread and unconditionally extracting the packet content into a bounce buffer in which the buffer is decrypted. recvmsg() (or the kernel equivalent) then copies the data from the bounce buffer to the destination buffer. The sk_buff then remains unmodified.
This has an additional advantage in that the packet is then arranged in the buffer with the correct alignment required for the crypto algorithms to process directly. The performance of the crypto does seem to be a little faster and, surprisingly, the unencrypted performance doesn't seem to change much - possibly due to removing complexity from the I/O thread.
Yet another advantage is that the I/O thread doesn't have to copy packets which would slow down packet distribution, ACK generation, etc..
The buffer belongs to the call and is allocated initially at 2K, sufficiently large to hold a whole jumbo subpacket, but the buffer will be increased in size if needed. However, to take this work, MSG_PEEK may cause a later packet to be decrypted into the buffer, in which case the earlier one will need re-decrypting for a subsequent recvmsg().
Note that rx_pkt_offset may legitimately see 0 as a valid offset now, so switch to using USHRT_MAX to indicate an invalid offset.
Note also that I would generally prefer to replace the buffers of the current sk_buff with a new kmalloc'd buffer of the right size, ditching the old data and frags as this makes the handling of MSG_PEEK easier and removes the re-decryption issue, but this looks like quite a complicated thing to achieve. skb_morph() looks half way to what I want, but I don't want to have to allocate a new sk_buff.
Stable-dep-of: 8bfab4b6ffc2 ("rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer")
--- net/rxrpc/ar-internal.h | 7 +++- net/rxrpc/call_event.c | 27 +------------ net/rxrpc/call_object.c | 2 + net/rxrpc/insecure.c | 3 -- net/rxrpc/recvmsg.c | 68 +++++++++++++++++++++++++------- net/rxrpc/rxkad.c | 86 +++++++++++++++-------------------------- 6 files changed, 96 insertions(+), 97 deletions(-)
net/rxrpc/ar-internal.h +5 -2
@@ -202,8 +202,6 @@ struct rxrpc_skb_priv {struct {u16 offset;/* Offset of data */ u16 len;/* Length of data */ -u8 flags; -#define RXRPC_RX_VERIFIED 0x01 };struct {rxrpc_seq_t first_ack;/* First packet in acks table */
@@ -677,6 +675,11 @@ struct rxrpc_call {/* Received data tracking */ struct sk_buff_head recvmsg_queue;/* Queue of packets ready for recvmsg() */ struct sk_buff_head rx_oos_queue;/* Queue of out of sequence packets */ +void *rx_dec_buffer;/* Decryption buffer */ +unsigned short rx_dec_bsize;/* rx_dec_buffer size */ +unsigned short rx_dec_offset;/* Decrypted packet data offset */ +unsigned short rx_dec_len;/* Decrypted packet data len */ +rxrpc_seq_t rx_dec_seq;/* Packet in decryption buffer */ rxrpc_seq_t rx_highest_seq;/* Higest sequence number received */ rxrpc_seq_t rx_consumed;/* Highest packet consumed */
net/rxrpc/call_event.c +2 -25
@@ -456,31 +456,8 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) resend = true; } -if (skb) { -struct rxrpc_skb_priv *sp =rxrpc_skb (skb); - -if (sp->hdr.type ==RXRPC_PACKET_TYPE_DATA && - sp->hdr.securityIndex !=0 && - (skb_cloned (skb) || -skb_has_frag_list (skb) || -skb_has_shared_frag (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); - } - } +if (skb) +rxrpc_input_call_packet (call, skb);rxrpc_transmit_some_data (call);
net/rxrpc/call_object.c +2 -0
@@ -163,6 +163,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,spin_lock_init (&call->tx_lock);refcount_set (&call->ref,1 ); call->debug_id = debug_id; + call->rx_pkt_offset =USHRT_MAX ; call->tx_total_len =-1 ; call->next_rx_timo =20 *HZ ; call->next_req_timo =1 *HZ ;
@@ -540,6 +541,7 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call) {rxrpc_purge_queue (&call->recvmsg_queue);rxrpc_purge_queue (&call->rx_oos_queue); +kfree (call->rx_dec_buffer); }/*
net/rxrpc/insecure.c +0 -3
@@ -32,9 +32,6 @@ static int none_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)static int none_verify_packet (struct rxrpc_call *call,struct sk_buff *skb) { -struct rxrpc_skb_priv *sp =rxrpc_skb (skb); - - sp->flags |=RXRPC_RX_VERIFIED ;return 0 ; }
net/rxrpc/recvmsg.c +55 -13
104 lines not on this page · raw message
net/rxrpc/rxkad.c +32 -54
166 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer
From: David Howells <[email protected]>
[ Upstream commit 8bfab4b6ffc2fe92da86300728fc8c3c7ebffb56 ]
This improves the fix for CVE-2026-43500.
Fix the verification of RESPONSE packets to avoid the problem of overwriting a RESPONSE packet sent via splice to a local address by extracting the contents of the UDP packet into a kmalloc'd linear buffer rather than decrypting the data in place in the sk_buff (which may corrupt the original buffer).
--- net/rxrpc/ar-internal.h | 5 +++-- net/rxrpc/conn_event.c | 32 +++++++++++++------------------- net/rxrpc/insecure.c | 5 +++-- net/rxrpc/rxkad.c | 29 ++++++++++------------------- 4 files changed, 29 insertions(+), 42 deletions(-)
net/rxrpc/ar-internal.h +3 -2
@@ -267,8 +267,9 @@ struct rxrpc_security { struct sk_buff *);/* verify a response */ -int (*verify_response)(struct rxrpc_connection *, -struct sk_buff *); +int (*verify_response)(struct rxrpc_connection *conn, +struct sk_buff *response_skb, +void *response,unsigned int len);/* clear connection security */ void (*clear)(struct rxrpc_connection *);
net/rxrpc/conn_event.c +13 -19
@@ -229,28 +229,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)static int rxrpc_verify_response (struct rxrpc_connection *conn,struct sk_buff *skb) { +unsigned int len = skb->len -sizeof (struct rxrpc_wire_header ); +void *buffer;int ret; -if (skb_cloned (skb) ||skb_has_frag_list (skb) || -skb_has_shared_frag (skb)) { -/* Copy the packet if shared so that we can do in-place -* decryption. -*/ -struct sk_buff *nskb =skb_copy (skb,GFP_NOFS ); - -if (nskb) { -rxrpc_new_skb (nskb, rxrpc_skb_new_unshared); - ret = conn->security->verify_response (conn, nskb); -rxrpc_free_skb (nskb, rxrpc_skb_put_response_copy); - }else { -/* OOM - Drop the packet. */ -rxrpc_see_skb (skb, rxrpc_skb_see_unshare_nomem); - ret = -ENOMEM ; - } - }else { - ret = conn->security->verify_response (conn, skb); - } + buffer =kmalloc (len,GFP_NOFS ); +if (!buffer) +return -ENOMEM ; + + ret =skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ), buffer, len); +if (ret <0 ) + goto out; + + ret = conn->security->verify_response (conn, skb, buffer, len); +out: +kfree (buffer);return ret; }
net/rxrpc/insecure.c +3 -2
@@ -47,9 +47,10 @@ static int none_respond_to_challenge(struct rxrpc_connection *conn, }static int none_verify_response (struct rxrpc_connection *conn, -struct sk_buff *skb) +struct sk_buff *response_skb, +void *response,unsigned int len) { -return rxrpc_abort_conn (conn, skb,RX_PROTOCOL_ERROR , -EPROTO , +return rxrpc_abort_conn (conn, response_skb,RX_PROTOCOL_ERROR , -EPROTO , rxrpc_eproto_rxnull_response); }
net/rxrpc/rxkad.c +10 -19
@@ -874,7 +874,6 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, *_expiry =0 ;ASSERT (server_key->payload.data[0 ] !=NULL ); - ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);memcpy (&iv, &server_key->payload.data[2 ],sizeof (iv));
@@ -1023,14 +1022,15 @@ static int rxkad_decrypt_response(struct rxrpc_connection *conn,* verify a response */ static int rxkad_verify_response (struct rxrpc_connection *conn, -struct sk_buff *skb) +struct sk_buff *skb, +void *buffer,unsigned int len) {struct rxkad_response *response;struct rxrpc_skb_priv *sp =rxrpc_skb (skb);struct rxrpc_crypt session_key;struct key *server_key;time64_t expiry; -void *ticket =NULL ; +void *ticket;u32 version, kvno, ticket_len, level;__be32 csum;int ret, i;
@@ -1053,13 +1053,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, } } - ret = -ENOMEM ; - response =kzalloc (sizeof (struct rxkad_response ),GFP_NOFS ); -if (!response) - goto error; - -if (skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ), - response,sizeof (*response)) <0 ) { + response = buffer; +if (len <sizeof (*response)) { ret =rxrpc_abort_conn (conn, skb,RXKADPACKETSHORT , -EPROTO , rxkad_abort_resp_short); goto error;
@@ -1071,6 +1066,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,trace_rxrpc_rx_response (conn, sp->hdr.serial, version, kvno, ticket_len); + buffer +=sizeof (*response); + len -=sizeof (*response); +if (version !=RXKAD_VERSION ) { ret =rxrpc_abort_conn (conn, skb,RXKADINCONSISTENCY , -EPROTO , rxkad_abort_resp_version);
@@ -1090,13 +1088,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, }/* extract the kerberos ticket and decrypt and decode it */ - ret = -ENOMEM ; - ticket =kmalloc (ticket_len,GFP_NOFS ); -if (!ticket) - goto error; - -if (skb_copy_bits (skb,sizeof (struct rxrpc_wire_header ) +sizeof (*response), - ticket, ticket_len) <0 ) { + ticket = buffer; +if (ticket_len > len) { ret =rxrpc_abort_conn (conn, skb,RXKADPACKETSHORT , -EPROTO , rxkad_abort_resp_short_tkt); goto error;
@@ -1176,8 +1169,6 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, ret =rxrpc_get_server_data_key (conn, &session_key, expiry, kvno); error: -kfree (ticket); -kfree (response);key_put (server_key);_leave (" = %d" , ret);return ret;
Signature · 1 line
2.53.0