Skip to contentSkip to conversation

rxrpc: Better fix for DATA/RESPONSE decrypt vs splice()

PATCH Applied David Howells 4 participants 7 messages May 15 – May 21

Subsystems (9)
lore
Share & tools
lore

David Howells

author maintainer
#0 lore raw

v4 cover rxrpc: Better fix for DATA/RESPONSE decrypt vs splice()

Here are two patches containing better fixes for the in-place decryption of DATA and RESPONSE packets that can corrupt pagecache spliced into UDP packets and sent to an AF_RXRPC server [CVE-2026-43500], plus a patch to precheck the length of rxgk-secured DATA packets.

Of the main patches, one patch fixes DATA decryption by having recvmsg unconditionally extract the data into a flat bounce buffer and, if need be, decrypt it there. It doesn't seem to cause a performance problem to do this even on unencrypted packets; for encrypted packets it makes sure the content is correctly aligned for crypto which seems to get a small performance gain.

Further, it means that DATA packets are no longer copied in the I/O thread, avoiding a slowdown of the protocol engine that runs there.

The other main patch fixes RESPONSE decryption by having the connection event handler worker copy the data to a flat buffer and, again, decrypt it there. This simplifies RESPONSE handling.

With these two fixes, the data content of the received sk_buff no longer gets altered.

David

The patches can be found here also:

http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-fixes

Changes
=======
ver #4)
- Updated to current net/next, dropping Hyunwoo Kim's patch.
- Don't allocate more than 65535 bytes of buffer so that ->rx_dec_bsize won't overflow.
- Fixed Sashiko review comments[3]:
- Fix incorrect ticket length limit.
- Don't need the MSG_PEEK limitation; can avoid this by checking seq of skbuff being recmvsg'd against the one on record for the content of the decryption buffer and (re-)decrypting if it doesn't match.

ver #3)
- Fixed Sashiko review comments[2]:
- Fix wrong abort codes.
- Fix skipped rxgk_put.
- Fix some mis-sizeofs.
- Fix flipped length check comparison.

ver #2)
- In rxrpc_verify_data():
- Flipped the order of the buffer size comparison.
- Used max() not umin() to calculate the minimum buffer size.
- In rxrpc_verify_response(), returned -ENOMEM rather than uninitialised ret.
- Removed the xdr wrappers that were added to make backporting easier.
- Fixed Sashiko review comments[1]:
- Added length prechecking of received packets secured with RxGK, thereby avoiding looking at an unallocated buffer.
- Added missing crypto free.

[1] https://sashiko.dev/#/patchset/20260511160753.607296-1-dhowells%40redhat.com
[2] https://sashiko.dev/#/patchset/20260513131941.1439155-1-dhowells%40redhat.com
[3] https://sashiko.dev/#/patchset/20260514155304.2249591-1-dhowells%40redhat.com

David Howells (3):
crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks
rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in
recvmsg
rxrpc: Fix RESPONSE packet verification to extract skb to a linear
buffer

 Documentation/crypto/krb5.rst |  17 +++-
 crypto/krb5/krb5_api.c        |  54 ++++++++++--
 include/crypto/krb5.h         |   9 +-
 include/trace/events/rxrpc.h  |   1 +
 net/rxrpc/ar-internal.h       |  14 +--
 net/rxrpc/call_event.c        |  22 +----
 net/rxrpc/call_object.c       |   2 +
 net/rxrpc/conn_event.c        |  32 +++----
 net/rxrpc/insecure.c          |   8 +-
 net/rxrpc/recvmsg.c           |  68 ++++++++++++---
 net/rxrpc/rxgk.c              | 160 ++++++++++++++--------------------
 net/rxrpc/rxgk_app.c          |  46 ++++------
 net/rxrpc/rxgk_common.h       |  66 +++++++-------
 net/rxrpc/rxkad.c             | 115 +++++++++---------------
 14 files changed, 309 insertions(+), 305 deletions(-)
author maintainer
#1 lore raw

PATCH v4 1/3 crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks

Change the krb5 crypto library to provide facilities to precheck the length of the message about to be decrypted or verified.

Fix AF_RXRPC to make use of this to validate DATA packets secured with RxGK.

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
cc Marc Dionne <[email protected]>
cc Jeffrey Altman <[email protected]>
cc Herbert Xu <[email protected]>
cc "David S. Miller" <[email protected]>
cc Eric Dumazet <[email protected]>
cc Jakub Kicinski <[email protected]>
cc Paolo Abeni <[email protected]>
cc Simon Horman <[email protected]>
cc Chuck Lever <[email protected]>
---
 Documentation/crypto/krb5.rst | 17 ++++++++---
 crypto/krb5/krb5_api.c        | 54 +++++++++++++++++++++++++++++++----
 include/crypto/krb5.h         |  9 ++++--
 include/trace/events/rxrpc.h  |  1 +
 net/rxrpc/rxgk.c              | 15 ++++++++--
 5 files changed, 81 insertions(+), 15 deletions(-)
Documentation/crypto/krb5.rst +13 -4
index beffa0133446..f62e07ac6811 100644
@@ -158,13 +158,22 @@ returned.
 When a message has been received, the location and size of the data with the
 message can be determined by calling::
 
-	void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
-					   enum krb5_crypto_mode mode,
-					   size_t *_offset, size_t *_len);
+	int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
+					  enum krb5_crypto_mode mode,
+					  size_t *_offset, size_t *_len);
 
 The caller provides the offset and length of the message to the function, which
 then alters those values to indicate the region containing the data (plus any
-padding).  It is up to the caller to determine how much padding there is.
+padding).  It is up to the caller to determine how much padding there is.  The
+function returns an error if the length is too small or if the mode is
+unsupported.  An additional function::
+
+	int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
+				       enum krb5_crypto_mode mode,
+				       size_t len, size_t min_content);
+
+is provided to just do a basic check that the decrypted/verified message would
+have a sufficient minimum payload.
 
 Preparation Functions
 ---------------------
crypto/krb5/krb5_api.c +48 -6

75 lines not on this page · raw message

include/crypto/krb5.h +6 -3
index 71dd38f59be1..aac3ecf88467 100644
@@ -121,9 +121,12 @@ size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
 size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
 				 enum krb5_crypto_mode mode,
 				 size_t *_buffer_size, size_t *_offset);
-void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
-				   enum krb5_crypto_mode mode,
-				   size_t *_offset, size_t *_len);
+int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
+				  enum krb5_crypto_mode mode,
+				  size_t *_offset, size_t *_len);
+int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
+			       enum krb5_crypto_mode mode,
+			       size_t len, size_t min_content);
 struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
 						   const struct krb5_buffer *TK,
 						   u32 usage, gfp_t gfp);
include/trace/events/rxrpc.h +1 -0
index 573f2df3a2c9..704a10de6670 100644
@@ -71,6 +71,7 @@
 	EM(rxkad_abort_resp_unknown_tkt,	"rxkad-resp-unknown-tkt") \
 	EM(rxkad_abort_resp_version,		"rxkad-resp-version")	\
 	/* RxGK security errors */					\
+	EM(rxgk_abort_1_short_header,		"rxgk1-short-hdr")	\
 	EM(rxgk_abort_1_verify_mic_eproto,	"rxgk1-vfy-mic-eproto")	\
 	EM(rxgk_abort_2_decrypt_eproto,		"rxgk2-dec-eproto")	\
 	EM(rxgk_abort_2_short_data,		"rxgk2-short-data")	\
net/rxrpc/rxgk.c +13 -2
index 0d5e654da918..26e723052a37 100644
@@ -480,8 +480,12 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call,
 
 	_enter("");
 
-	crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
-				      &data_offset, &data_len);
+	if (crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
+					  &data_offset, &data_len) < 0) {
+		ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
+					 rxgk_abort_1_short_header);
+		goto put_gk;
+	}
 
 	hdr = kzalloc_obj(*hdr, GFP_NOFS);
 	if (!hdr)
@@ -529,6 +533,13 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call,
 
 	_enter("");
 
+	if (crypto_krb5_check_data_len(gk->krb5, KRB5_ENCRYPT_MODE,
+				       len, sizeof(hdr)) < 0) {
+		ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT,
+					 rxgk_abort_2_short_header);
+		goto error;
+	}
+
 	ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac);
 	if (ret < 0) {
 		if (ret != -ENOMEM)
author maintainer
#2 lore raw

PATCH v4 2/3 rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg

In reply to David Howells

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.

Fixes d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()")
cc Marc Dionne <[email protected]>
cc Jeffrey Altman <[email protected]>
cc "David S. Miller" <[email protected]>
cc Eric Dumazet <[email protected]>
cc Jakub Kicinski <[email protected]>
cc Paolo Abeni <[email protected]>
cc Simon Horman <[email protected]>
cc Jiayuan Chen <[email protected]>
---
 net/rxrpc/ar-internal.h |  7 +++-
 net/rxrpc/call_event.c  | 22 +----------
 net/rxrpc/call_object.c |  2 +
 net/rxrpc/insecure.c    |  3 --
 net/rxrpc/recvmsg.c     | 68 +++++++++++++++++++++++++-------
 net/rxrpc/rxgk.c        | 51 ++++++++++++------------
 net/rxrpc/rxgk_common.h | 82 +++++++++++++++++++++++++++++++++++++++
 net/rxrpc/rxkad.c       | 86 +++++++++++++++--------------------------
 8 files changed, 201 insertions(+), 120 deletions(-)
net/rxrpc/ar-internal.h +5 -2
index 27c2aa2dd023..783367eea798 100644
@@ -213,8 +213,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 */
@@ -774,6 +772,11 @@ struct rxrpc_call {
 	struct sk_buff_head	recvmsg_queue;	/* Queue of packets ready for recvmsg() */
 	struct sk_buff_head	rx_queue;	/* Queue of packets for this call to receive */
 	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 +1 -21
index 2b19b252225e..fec59d9338b9 100644
@@ -332,27 +332,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)
 
 			saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK;
 
-			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_call_rx);
-				} else {
-					/* OOM - Drop the packet. */
-					rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
-				}
-			} else {
-				rxrpc_input_call_packet(call, skb);
-			}
+			rxrpc_input_call_packet(call, skb);
 			rxrpc_free_skb(skb, rxrpc_skb_put_call_rx);
 			did_receive = true;
 		}
net/rxrpc/call_object.c +2 -0
index f035f486c139..fcb9d38bb521 100644
@@ -152,6 +152,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
 	spin_lock_init(&call->notify_lock);
 	refcount_set(&call->ref, 1);
 	call->debug_id		= debug_id;
+	call->rx_pkt_offset	= USHRT_MAX;
 	call->tx_total_len	= -1;
 	call->tx_jumbo_max	= 1;
 	call->next_rx_timo	= 20 * HZ;
@@ -553,6 +554,7 @@ static void rxrpc_cleanup_rx_buffers(struct rxrpc_call *call)
 	rxrpc_purge_queue(&call->recvmsg_queue);
 	rxrpc_purge_queue(&call->rx_queue);
 	rxrpc_purge_queue(&call->rx_oos_queue);
+	kfree(call->rx_dec_buffer);
 }
 
 /*
net/rxrpc/insecure.c +0 -3
index 0a260df45d25..7a26c6097d03 100644
@@ -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

103 lines not on this page · raw message

net/rxrpc/rxgk.c +24 -27

104 lines not on this page · raw message

net/rxrpc/rxgk_common.h +82 -0

91 lines not on this page · raw message

net/rxrpc/rxkad.c +32 -54

166 lines not on this page · raw message

author maintainer
#3 lore raw

PATCH v4 3/3 rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer

In reply to David Howells

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).

Fixes 24481a7f5733 ("rxrpc: Fix conn-level packet handling to unshare RESPONSE packets")
cc Marc Dionne <[email protected]>
cc Jeffrey Altman <[email protected]>
cc Eric Dumazet <[email protected]>
cc "David S. Miller" <[email protected]>
cc Jakub Kicinski <[email protected]>
cc Paolo Abeni <[email protected]>
cc Simon Horman <[email protected]>
cc Jiayuan Chen <[email protected]>
---
 net/rxrpc/ar-internal.h |  7 +--
 net/rxrpc/conn_event.c  | 32 ++++++--------
 net/rxrpc/insecure.c    |  5 ++-
 net/rxrpc/rxgk.c        | 96 +++++++++++++----------------------------
 net/rxrpc/rxgk_app.c    | 46 ++++++++------------
 net/rxrpc/rxgk_common.h | 92 +--------------------------------------
 net/rxrpc/rxkad.c       | 29 +++++--------
 7 files changed, 82 insertions(+), 225 deletions(-)
net/rxrpc/ar-internal.h +4 -3
index 783367eea798..98f2165159d7 100644
@@ -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 +13 -19
index 442414d90ba1..c96ca615b787 100644
@@ -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);
-
-		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
index 7a26c6097d03..0b39046bdc61 100644
@@ -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 +31 -65

160 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
index 075936337836..6fbd883401ac 100644
@@ -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 @@ 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;
@@ -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;
Reviewed-by on the v4 series
#4 lore raw
In reply to David Howells
Quoted 70 lines · David Howells

Here are two patches containing better fixes for the in-place decryption of DATA and RESPONSE packets that can corrupt pagecache spliced into UDP packets and sent to an AF_RXRPC server [CVE-2026-43500], plus a patch to precheck the length of rxgk-secured DATA packets.

Of the main patches, one patch fixes DATA decryption by having recvmsg unconditionally extract the data into a flat bounce buffer and, if need be, decrypt it there. It doesn't seem to cause a performance problem to do this even on unencrypted packets; for encrypted packets it makes sure the content is correctly aligned for crypto which seems to get a small performance gain.

Further, it means that DATA packets are no longer copied in the I/O thread, avoiding a slowdown of the protocol engine that runs there.

The other main patch fixes RESPONSE decryption by having the connection event handler worker copy the data to a flat buffer and, again, decrypt it there. This simplifies RESPONSE handling.

With these two fixes, the data content of the received sk_buff no longer gets altered.

David

The patches can be found here also:

http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-fixes

Changes
=======
ver #4)
- Updated to current net/next, dropping Hyunwoo Kim's patch.
- Don't allocate more than 65535 bytes of buffer so that ->rx_dec_bsize won't overflow.
- Fixed Sashiko review comments[3]:
- Fix incorrect ticket length limit.
- Don't need the MSG_PEEK limitation; can avoid this by checking seq of skbuff being recmvsg'd against the one on record for the content of the decryption buffer and (re-)decrypting if it doesn't match.

ver #3)
- Fixed Sashiko review comments[2]:
- Fix wrong abort codes.
- Fix skipped rxgk_put.
- Fix some mis-sizeofs.
- Fix flipped length check comparison.

ver #2)
- In rxrpc_verify_data():
- Flipped the order of the buffer size comparison.
- Used max() not umin() to calculate the minimum buffer size.
- In rxrpc_verify_response(), returned -ENOMEM rather than uninitialised ret.
- Removed the xdr wrappers that were added to make backporting easier.
- Fixed Sashiko review comments[1]:
- Added length prechecking of received packets secured with RxGK, thereby avoiding looking at an unallocated buffer.
- Added missing crypto free.

[1] https://sashiko.dev/#/patchset/20260511160753.607296-1-dhowells%40redhat.com
[2] https://sashiko.dev/#/patchset/20260513131941.1439155-1-dhowells%40redhat.com
[3] https://sashiko.dev/#/patchset/20260514155304.2249591-1-dhowells%40redhat.com

David Howells (3):
crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks
rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in
recvmsg
rxrpc: Fix RESPONSE packet verification to extract skb to a linear
buffer

Quoted 16 lines
  Documentation/crypto/krb5.rst |  17 +++-
  crypto/krb5/krb5_api.c        |  54 ++++++++++--
  include/crypto/krb5.h         |   9 +-
  include/trace/events/rxrpc.h  |   1 +
  net/rxrpc/ar-internal.h       |  14 +--
  net/rxrpc/call_event.c        |  22 +----
  net/rxrpc/call_object.c       |   2 +
  net/rxrpc/conn_event.c        |  32 +++----
  net/rxrpc/insecure.c          |   8 +-
  net/rxrpc/recvmsg.c           |  68 ++++++++++++---
  net/rxrpc/rxgk.c              | 160 ++++++++++++++--------------------
  net/rxrpc/rxgk_app.c          |  46 ++++------
  net/rxrpc/rxgk_common.h       |  66 +++++++-------
  net/rxrpc/rxkad.c             | 115 +++++++++---------------
  14 files changed, 309 insertions(+), 305 deletions(-)
Tested-by on the v4 series
#5 lore raw
In reply to David Howells
Quoted 71 lines · David Howells

Here are two patches containing better fixes for the in-place decryption of DATA and RESPONSE packets that can corrupt pagecache spliced into UDP packets and sent to an AF_RXRPC server [CVE-2026-43500], plus a patch to precheck the length of rxgk-secured DATA packets.

Of the main patches, one patch fixes DATA decryption by having recvmsg unconditionally extract the data into a flat bounce buffer and, if need be, decrypt it there. It doesn't seem to cause a performance problem to do this even on unencrypted packets; for encrypted packets it makes sure the content is correctly aligned for crypto which seems to get a small performance gain.

Further, it means that DATA packets are no longer copied in the I/O thread, avoiding a slowdown of the protocol engine that runs there.

The other main patch fixes RESPONSE decryption by having the connection event handler worker copy the data to a flat buffer and, again, decrypt it there. This simplifies RESPONSE handling.

With these two fixes, the data content of the received sk_buff no longer gets altered.

David

The patches can be found here also:

http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-fixes

Changes
=======
ver #4)
- Updated to current net/next, dropping Hyunwoo Kim's patch.
- Don't allocate more than 65535 bytes of buffer so that ->rx_dec_bsize won't overflow.
- Fixed Sashiko review comments[3]:
- Fix incorrect ticket length limit.
- Don't need the MSG_PEEK limitation; can avoid this by checking seq of skbuff being recmvsg'd against the one on record for the content of the decryption buffer and (re-)decrypting if it doesn't match.

ver #3)
- Fixed Sashiko review comments[2]:
- Fix wrong abort codes.
- Fix skipped rxgk_put.
- Fix some mis-sizeofs.
- Fix flipped length check comparison.

ver #2)
- In rxrpc_verify_data():
- Flipped the order of the buffer size comparison.
- Used max() not umin() to calculate the minimum buffer size.
- In rxrpc_verify_response(), returned -ENOMEM rather than uninitialised ret.
- Removed the xdr wrappers that were added to make backporting easier.
- Fixed Sashiko review comments[1]:
- Added length prechecking of received packets secured with RxGK, thereby avoiding looking at an unallocated buffer.
- Added missing crypto free.

[1] https://sashiko.dev/#/patchset/20260511160753.607296-1-dhowells%40redhat.com
[2] https://sashiko.dev/#/patchset/20260513131941.1439155-1-dhowells%40redhat.com
[3] https://sashiko.dev/#/patchset/20260514155304.2249591-1-dhowells%40redhat.com

David Howells (3):
crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks
rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in
recvmsg
rxrpc: Fix RESPONSE packet verification to extract skb to a linear
buffer

Quoted 15 lines
 Documentation/crypto/krb5.rst |  17 +++-
 crypto/krb5/krb5_api.c        |  54 ++++++++++--
 include/crypto/krb5.h         |   9 +-
 include/trace/events/rxrpc.h  |   1 +
 net/rxrpc/ar-internal.h       |  14 +--
 net/rxrpc/call_event.c        |  22 +----
 net/rxrpc/call_object.c       |   2 +
 net/rxrpc/conn_event.c        |  32 +++----
 net/rxrpc/insecure.c          |   8 +-
 net/rxrpc/recvmsg.c           |  68 ++++++++++++---
 net/rxrpc/rxgk.c              | 160 ++++++++++++++--------------------
 net/rxrpc/rxgk_app.c          |  46 ++++------
 net/rxrpc/rxgk_common.h       |  66 +++++++-------
 net/rxrpc/rxkad.c             | 115 +++++++++---------------
 14 files changed, 309 insertions(+), 305 deletions(-)

Looks good in testing.

#6 lore raw
In reply to David Howells
This series was applied to netdev/net.git (main) by Jakub Kicinski <[email protected]>:

Hello:

This series was applied to netdev/net.git (main)
by Jakub Kicinski <[email protected]>:

Quoted 5 lines · On Sat, 16 May 2026 00:05:12 +0100 you wrote:

Here are two patches containing better fixes for the in-place decryption of DATA and RESPONSE packets that can corrupt pagecache spliced into UDP packets and sent to an AF_RXRPC server [CVE-2026-43500], plus a patch to precheck the length of rxgk-secured DATA packets.

Quoted 8 lines

Of the main patches, one patch fixes DATA decryption by having recvmsg unconditionally extract the data into a flat bounce buffer and, if need be, decrypt it there. It doesn't seem to cause a performance problem to do this even on unencrypted packets; for encrypted packets it makes sure the content is correctly aligned for crypto which seems to get a small performance gain.

[...]

Here is the summary with links:
- [net,v4,1/3] crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks

    https://git.kernel.org/netdev/net/c/2b50aceafe66
  - [net,v4,2/3] rxrpc: Fix DATA decrypt vs splice() by copying data to buffer in recvmsg
    https://git.kernel.org/netdev/net/c/d2bc90cf6c75
  - [net,v4,3/3] rxrpc: Fix RESPONSE packet verification to extract skb to a linear buffer
    https://git.kernel.org/netdev/net/c/8bfab4b6ffc2

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html