Skip to contentSkip to conversation

rxrpc: Miscellaneous fixes

PATCH Applied David Howells 2 participants 23 messages Apr 8 – Apr 9

Subsystems (4)

v5 of 12 Applied 21/21 Latest is v12 →

lore
Share & tools
lore

David Howells

author maintainer
#0 lore raw

v5 cover rxrpc: Miscellaneous fixes

Here are some fixes for rxrpc:

(1) Fix key quota calculation.

(2) Fix a memory leak.

(3) Fix rxrpc_new_client_call_for_sendmsg() to substitute NULL for an empty key.

Might want to remove this substitution entirely or handle it in rxrpc_init_client_call_security() instead.

(4) Fix deletion of call->link to be RCU safe.

(5) Fix missing bounds checks when parsing RxGK tickets.

(6) Fix use of wrong skbuff to get challenge serial number. Also actually substitute the newer response skbuff and release the older one.

(7) Fix unexpected RACK timer warning to report old mode.

(8) Fix call key refcount leak.

(9) Fix the interaction of jumbograms with Tx window space, setting the request-ack flag when the window space is getting low, typically because each jumbogram take a big bite out of the window and fewer UDP packets get traded.

(10) Don't call rxrpc_put_call() with a NULL pointer.

(11) Reject undecryptable rxkad response tickets by checking result of decryption.

(12) Fix buffer bounds calculation in the RESPONSE authenticator parser.

(13) Fix oversized response length check.

(14) Fix refcount leak on multiple setting of server keyring.

(15) Fix checks made by RXRPC_SECURITY_KEY and RXRPC_SECURITY_KEYRING (both should be allowed).

(16) Fix lack of result checking on calls to crypto_skcipher_en/decrypt().

(17) Fix token_len limit check in rxgk_verify_response().

(18) Fix rxgk context leak in rxgk_verify_response().

(19) Fix read beyond end of buffer in rxgk_do_verify_authenticator().

(20) Fix parsing of RESPONSE packet on a connection that has already been set from a prior response.

(21) Fix size of buffers used for rendering addresses into for procfiles.

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 #5)
- AI review[2]:
- Dropped patch to check rx->securities in rxrpc_setsockopt().
- Changed patch to check rx->securities in rxrpc_server_keyring() to return error -EINVAL.
- Added patch to check rx->key and rx->securities correctly.
- Added patch to check return of crypto_skcipher_en/decrypt().
- Added patch to check buf len in rxgk_do_verify_authenticator().
- Imported a patch to fix parsing of RESPONSE packet in wrong state.
- Imported a patch to fix size of address buffers in procfiles.

ver #4)
- Got rid of the on_list()/on_list_rcu() patch.
- Removed the list_del_init from rxrpc_destroy_all_calls().
- Made the list_del_rcu() in rxrpc_put_call() unconditional.
- Added four new patches.

ver #3)
- Rename the dwc2's on_list() to dwc2_on_list() to free up the name.
- Added a patch to fix the interaction of jumbograms with window space.

ver #2)
- AI review[1]:
- Added a patch to fix key quota calculation.
- Added a patch to fix a memory leak.
- Added a patch to use NULL instead of an empty key in rxrpc_sengmsg().
- Added a patch to use RCU-safe deletion on call->link.
- Modified the response packet selection patch to select the newer response when there's an older response - and to release the older response skbuff.
- Move on_list_rcu() and add on_list().

Alok Tiwari (2):
rxrpc: Fix use of wrong skb when comparing queued RESP challenge
serial
rxrpc: Fix rack timer warning to report unexpected mode

Anderson Nascimento (1):
rxrpc: Fix key reference count leak from call->key

David Howells (9):
rxrpc: Fix key quota calculation for multitoken keys
rxrpc: Fix key parsing memleak
rxrpc: Fix anonymous key handling
rxrpc: Fix call removal to use RCU safe deletion
rxrpc: Fix key/keyring checks in
setsockopt(RXRPC_SECURITY_KEY/KEYRING)
rxrpc: Fix missing error checks for rxkad encryption/decryption
failure
rxrpc: Fix integer overflow in rxgk_verify_response()
rxrpc: Fix leak of rxgk context in rxgk_verify_response()
rxrpc: Fix buffer overread in rxgk_do_verify_authenticator()

Douya Le (1):
rxrpc: Only put the call ref if one was acquired

Keenan Dong (2):
rxrpc: fix RESPONSE authenticator parser OOB read
rxrpc: fix oversized RESPONSE authenticator length check

Luxiao Xu (1):
rxrpc: fix reference count leak in rxrpc_server_keyring()

Marc Dionne (1):
rxrpc: Fix to request an ack if window is limited

Oleh Konko (1):
rxrpc: Fix RxGK token loading to check bounds

Pengpeng Hou (1):
rxrpc: proc: size address buffers for %pISpc output

Wang Jie (1):
rxrpc: only handle RESPONSE during service challenge

Yuqi Xu (1):
rxrpc: reject undecryptable rxkad response tickets

 include/trace/events/rxrpc.h |  4 ++-
 net/rxrpc/af_rxrpc.c         |  6 ----
 net/rxrpc/ar-internal.h      |  2 +-
 net/rxrpc/call_object.c      | 25 ++++++--------
 net/rxrpc/conn_event.c       | 19 ++++++++---
 net/rxrpc/input_rack.c       |  2 +-
 net/rxrpc/io_thread.c        |  3 +-
 net/rxrpc/key.c              | 40 +++++++++++++----------
 net/rxrpc/output.c           |  2 ++
 net/rxrpc/proc.c             | 37 ++++++++++++---------
 net/rxrpc/rxgk.c             | 19 +++++++----
 net/rxrpc/rxkad.c            | 63 ++++++++++++++++++++++++------------
 net/rxrpc/sendmsg.c          |  2 +-
 net/rxrpc/server_key.c       |  3 ++
 14 files changed, 138 insertions(+), 89 deletions(-)
author maintainer
#1 lore raw

PATCH v5 1/21 rxrpc: Fix key quota calculation for multitoken keys

In the rxrpc key preparsing, every token extracted sets the proposed quota value, but for multitoken keys, this will overwrite the previous proposed quota, losing it.

Fix this by adding to the proposed quota instead.

Fixes 8a7a3eb4ddbe ("KEYS: RxRPC: Use key preparsing")
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]>
---
 net/rxrpc/key.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
net/rxrpc/key.c +4 -3
index 85078114b2dd..af403f0ccab5 100644
@@ -72,7 +72,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
 		return -EKEYREJECTED;
 
 	plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
-	prep->quotalen = datalen + plen;
+	prep->quotalen += datalen + plen;
 
 	plen -= sizeof(*token);
 	token = kzalloc_obj(*token);
@@ -199,7 +199,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	}
 
 	plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
-	prep->quotalen = datalen + plen;
+	prep->quotalen += datalen + plen;
 
 	plen -= sizeof(*token);
 	token = kzalloc_obj(*token);
@@ -460,6 +460,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
 	memcpy(&kver, prep->data, sizeof(kver));
 	prep->data += sizeof(kver);
 	prep->datalen -= sizeof(kver);
+	prep->quotalen = 0;
 
 	_debug("KEY I/F VERSION: %u", kver);
 
@@ -497,7 +498,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
 		goto error;
 
 	plen = sizeof(*token->kad) + v1->ticket_length;
-	prep->quotalen = plen + sizeof(*token);
+	prep->quotalen += plen + sizeof(*token);
 
 	ret = -ENOMEM;
 	token = kzalloc_obj(*token);
author maintainer
#2 lore raw

PATCH v5 2/21 rxrpc: Fix key parsing memleak

In reply to David Howells

In rxrpc_preparse_xdr_yfs_rxgk(), the memory attached to token->rxgk can be leaked in a few error paths after it's allocated.

Fix this by freeing it in the "reject_token:" case.

Fixes 0ca100ff4df6 ("rxrpc: Add YFS RxGK (GSSAPI) security class")
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]>
---
 net/rxrpc/key.c | 1 +
 1 file changed, 1 insertion(+)
net/rxrpc/key.c +1 -0
index af403f0ccab5..26d4336a4a02 100644
@@ -274,6 +274,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 nomem:
 	return -ENOMEM;
 reject_token:
+	kfree(token->rxgk);
 	kfree(token);
 reject:
 	return -EKEYREJECTED;
author maintainer
#3 lore raw

PATCH v5 3/21 rxrpc: Fix anonymous key handling

In reply to David Howells

In rxrpc_new_client_call_for_sendmsg(), a key with no payload is meant to be substituted for a NULL key pointer, but the variable this is done with is subsequently not used.

Fix this by using "key" rather than "rx->key" when filling in the connection parameters.

Note that this only affects direct use of AF_RXRPC; the kAFS filesystem doesn't use sendmsg() directly and so bypasses the issue. Further, AF_RXRPC passes a NULL key in if no key is set, so using an anonymous key in that manner works. Since this hasn't been noticed to this point, it might be better just to remove the "key" variable and the code that sets it
- and, arguably, rxrpc_init_client_call_security() would be a better place to handle it.

Fixes 19ffa01c9c45 ("rxrpc: Use structs to hold connection params and protocol info")
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]>
---
 net/rxrpc/sendmsg.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/rxrpc/sendmsg.c +1 -1
index 04f9c5f2dc24..c35de4fd75e3 100644
@@ -637,7 +637,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 	memset(&cp, 0, sizeof(cp));
 	cp.local		= rx->local;
 	cp.peer			= peer;
-	cp.key			= rx->key;
+	cp.key			= key;
 	cp.security_level	= rx->min_sec_level;
 	cp.exclusive		= rx->exclusive | p->exclusive;
 	cp.upgrade		= p->upgrade;
author maintainer
#4 lore raw

PATCH v5 4/21 rxrpc: Fix call removal to use RCU safe deletion

In reply to David Howells

Fix rxrpc call removal from the rxnet->calls list to use list_del_rcu() rather than list_del_init() to prevent stuffing up reading /proc/net/rxrpc/calls from potentially getting into an infinite loop.

This, however, means that list_empty() no longer works on an entry that's been deleted from the list, making it harder to detect prior deletion. Fix this by:

Firstly, make rxrpc_destroy_all_calls() only dump the first ten calls that are unexpectedly still on the list. Limiting the number of steps means there's no need to call cond_resched() or to remove calls from the list here, thereby eliminating the need for rxrpc_put_call() to check for that.

rxrpc_put_call() can then be fixed to unconditionally delete the call from the list as it is the only place that the deletion occurs.

Fixes 2baec2c3f854 ("rxrpc: Support network namespacing")
cc Marc Dionne <[email protected]>
cc Jeffrey Altman <[email protected]>
cc Linus Torvalds <[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]>
---
 include/trace/events/rxrpc.h |  2 +-
 net/rxrpc/call_object.c      | 24 +++++++++---------------
 2 files changed, 10 insertions(+), 16 deletions(-)
include/trace/events/rxrpc.h +1 -1
index 869f97c9bf73..a826cd80007b 100644
@@ -347,7 +347,7 @@
 	EM(rxrpc_call_see_release,		"SEE release ") \
 	EM(rxrpc_call_see_userid_exists,	"SEE u-exists") \
 	EM(rxrpc_call_see_waiting_call,		"SEE q-conn  ") \
-	E_(rxrpc_call_see_zap,			"SEE zap     ")
+	E_(rxrpc_call_see_still_live,		"SEE !still-l")
 
 #define rxrpc_txqueue_traces \
 	EM(rxrpc_txqueue_await_reply,		"AWR") \
net/rxrpc/call_object.c +9 -15
index 918f41d97a2f..59329cfe1532 100644
@@ -654,11 +654,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
 	if (dead) {
 		ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
 
-		if (!list_empty(&call->link)) {
-			spin_lock(&rxnet->call_lock);
-			list_del_init(&call->link);
-			spin_unlock(&rxnet->call_lock);
-		}
+		spin_lock(&rxnet->call_lock);
+		list_del_rcu(&call->link);
+		spin_unlock(&rxnet->call_lock);
 
 		rxrpc_cleanup_call(call);
 	}
@@ -730,24 +728,20 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
 	_enter("");
 
 	if (!list_empty(&rxnet->calls)) {
-		spin_lock(&rxnet->call_lock);
+		int shown = 0;
 
-		while (!list_empty(&rxnet->calls)) {
-			call = list_entry(rxnet->calls.next,
-					  struct rxrpc_call, link);
-			_debug("Zapping call %p", call);
+		spin_lock(&rxnet->call_lock);
 
-			rxrpc_see_call(call, rxrpc_call_see_zap);
-			list_del_init(&call->link);
+		list_for_each_entry(call, &rxnet->calls, link) {
+			rxrpc_see_call(call, rxrpc_call_see_still_live);
 
 			pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
 			       call, refcount_read(&call->ref),
 			       rxrpc_call_states[__rxrpc_call_state(call)],
 			       call->flags, call->events);
 
-			spin_unlock(&rxnet->call_lock);
-			cond_resched();
-			spin_lock(&rxnet->call_lock);
+			if (++shown >= 10)
+				break;
 		}
 
 		spin_unlock(&rxnet->call_lock);
author maintainer
#5 lore raw

PATCH v5 5/21 rxrpc: Fix RxGK token loading to check bounds

In reply to David Howells

From: Oleh Konko <[email protected]>

rxrpc_preparse_xdr_yfs_rxgk() reads the raw key length and ticket length from the XDR token as u32 values and passes each through round_up(x, 4) before using the rounded value for validation and allocation. When the raw length is >= 0xfffffffd, round_up() wraps to 0, so the bounds check and kzalloc both use 0 while the subsequent memcpy still copies the original ~4 GiB value, producing a heap buffer overflow reachable from an unprivileged add_key() call.

Fix this by:

(1) Rejecting raw key lengths above AFSTOKEN_GK_KEY_MAX and raw ticket lengths above AFSTOKEN_GK_TOKEN_MAX before rounding, consistent with the caps that the RxKAD path already enforces via AFSTOKEN_RK_TIX_MAX.

(2) Sizing the flexible-array allocation from the validated raw key length via struct_size_t() instead of the rounded value.

(3) Caching the raw lengths so that the later field assignments and memcpy calls do not re-read from the token, eliminating a class of TOCTOU re-parse.

The control path (valid token with lengths within bounds) is unaffected.

Fixes 0ca100ff4df6 ("rxrpc: Add YFS RxGK (GSSAPI) security class")
cc Marc Dionne <[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]>
---
 net/rxrpc/key.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)
net/rxrpc/key.c +17 -13
index 26d4336a4a02..77237a82be3b 100644
@@ -13,6 +13,7 @@
 #include <crypto/skcipher.h>
 #include <linux/module.h>
 #include <linux/net.h>
+#include <linux/overflow.h>
 #include <linux/skbuff.h>
 #include <linux/key-type.h>
 #include <linux/ctype.h>
@@ -171,7 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	size_t plen;
 	const __be32 *ticket, *key;
 	s64 tmp;
-	u32 tktlen, keylen;
+	size_t raw_keylen, raw_tktlen, keylen, tktlen;
 
 	_enter(",{%x,%x,%x,%x},%x",
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -181,18 +182,22 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 		goto reject;
 
 	key = xdr + (6 * 2 + 1);
-	keylen = ntohl(key[-1]);
-	_debug("keylen: %x", keylen);
-	keylen = round_up(keylen, 4);
+	raw_keylen = ntohl(key[-1]);
+	_debug("keylen: %zx", raw_keylen);
+	if (raw_keylen > AFSTOKEN_GK_KEY_MAX)
+		goto reject;
+	keylen = round_up(raw_keylen, 4);
 	if ((6 * 2 + 2) * 4 + keylen > toklen)
 		goto reject;
 
 	ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
-	tktlen = ntohl(ticket[-1]);
-	_debug("tktlen: %x", tktlen);
-	tktlen = round_up(tktlen, 4);
+	raw_tktlen = ntohl(ticket[-1]);
+	_debug("tktlen: %zx", raw_tktlen);
+	if (raw_tktlen > AFSTOKEN_GK_TOKEN_MAX)
+		goto reject;
+	tktlen = round_up(raw_tktlen, 4);
 	if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
-		kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
+		kleave(" = -EKEYREJECTED [%zx!=%x, %zx,%zx]",
 		       (6 * 2 + 2) * 4 + keylen + tktlen, toklen,
 		       keylen, tktlen);
 		goto reject;
@@ -206,7 +211,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	if (!token)
 		goto nomem;
 
-	token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL);
+	token->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
 	if (!token->rxgk)
 		goto nomem_token;
 
@@ -221,9 +226,9 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	token->rxgk->enctype	= tmp = xdr_dec64(xdr + 5 * 2);
 	if (tmp < 0 || tmp > UINT_MAX)
 		goto reject_token;
-	token->rxgk->key.len	= ntohl(key[-1]);
+	token->rxgk->key.len	= raw_keylen;
 	token->rxgk->key.data	= token->rxgk->_key;
-	token->rxgk->ticket.len = ntohl(ticket[-1]);
+	token->rxgk->ticket.len = raw_tktlen;
 
 	if (token->rxgk->endtime != 0) {
 		expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
@@ -236,8 +241,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
 
 	/* Pad the ticket so that we can use it directly in XDR */
-	token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4),
-					   GFP_KERNEL);
+	token->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
 	if (!token->rxgk->ticket.data)
 		goto nomem_yrxgk;
 	memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
author maintainer
#6 lore raw

PATCH v5 6/21 rxrpc: Fix use of wrong skb when comparing queued RESP challenge serial

In reply to David Howells

From: Alok Tiwari <[email protected]>

In rxrpc_post_response(), the code should be comparing the challenge serial number from the cached response before deciding to switch to a newer response, but looks at the newer packet private data instead, rendering the comparison always false.

Fix this by switching to look at the older packet.

Fix further[1] to substitute the new packet in place of the old one if newer and also to release whichever we don't use.

Fixes 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE")
cc Marc Dionne <[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]>
---
 include/trace/events/rxrpc.h | 1 +
 net/rxrpc/conn_event.c       | 5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)
include/trace/events/rxrpc.h +1 -0
index a826cd80007b..f7f559204b87 100644
@@ -185,6 +185,7 @@
 	EM(rxrpc_skb_put_input,			"PUT input    ") \
 	EM(rxrpc_skb_put_jumbo_subpacket,	"PUT jumbo-sub") \
 	EM(rxrpc_skb_put_oob,			"PUT oob      ") \
+	EM(rxrpc_skb_put_old_response,		"PUT old-resp ") \
 	EM(rxrpc_skb_put_purge,			"PUT purge    ") \
 	EM(rxrpc_skb_put_purge_oob,		"PUT purge-oob") \
 	EM(rxrpc_skb_put_response,		"PUT response ") \
net/rxrpc/conn_event.c +3 -2
index 98ad9b51ca2c..c50cbfc5a313 100644
@@ -557,11 +557,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
 	spin_lock_irq(&local->lock);
 	old = conn->tx_response;
 	if (old) {
-		struct rxrpc_skb_priv *osp = rxrpc_skb(skb);
+		struct rxrpc_skb_priv *osp = rxrpc_skb(old);
 
 		/* Always go with the response to the most recent challenge. */
 		if (after(sp->resp.challenge_serial, osp->resp.challenge_serial))
-			conn->tx_response = old;
+			conn->tx_response = skb;
 		else
 			old = skb;
 	} else {
@@ -569,4 +569,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
 	}
 	spin_unlock_irq(&local->lock);
 	rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response);
+	rxrpc_free_skb(old, rxrpc_skb_put_old_response);
 }
author maintainer
#7 lore raw

PATCH v5 7/21 rxrpc: Fix rack timer warning to report unexpected mode

In reply to David Howells

From: Alok Tiwari <[email protected]>

rxrpc_rack_timer_expired() clears call->rack_timer_mode to OFF before the switch. The default case warning therefore always prints OFF and doesn't identify the unexpected timer mode.

Log the saved mode value instead so the warning reports the actual unexpected rack timer mode.

Fixes 7c482665931b ("rxrpc: Implement RACK/TLP to deal with transmission stalls [RFC8985]")
cc Marc Dionne <[email protected]>
cc Eric Dumazet <[email protected]>
cc "David S. Miller" <[email protected]>
cc Jakub Kicinski <[email protected]>
cc Paolo Abeni <[email protected]>
---
 net/rxrpc/input_rack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/rxrpc/input_rack.c +1 -1
index 13c371261e0a..9eb109ffba56 100644
@@ -413,6 +413,6 @@ void rxrpc_rack_timer_expired(struct rxrpc_call *call, ktime_t overran_by)
 		break;
 	//case RXRPC_CALL_RACKTIMER_ZEROWIN:
 	default:
-		pr_warn("Unexpected rack timer %u", call->rack_timer_mode);
+		pr_warn("Unexpected rack timer %u", mode);
 	}
 }
author maintainer
#8 lore raw

PATCH v5 8/21 rxrpc: Fix key reference count leak from call->key

In reply to David Howells

From: Anderson Nascimento <[email protected]>

When creating a client call in rxrpc_alloc_client_call(), the code obtains a reference to the key. This is never cleaned up and gets leaked when the call is destroyed.

Fix this by freeing call->key in rxrpc_destroy_call().

Before the patch, it shows the key reference counter elevated:

$ cat /proc/keys | grep afs@54321
1bffe9cd I--Q--i 8053480 4169w 3b010000  1000  1000 rxrpc     afs@54321: ka
$

After the patch, the invalidated key is removed when the code exits:

$ cat /proc/keys | grep afs@54321
$
Fixes f3441d4125fc ("rxrpc: Copy client call parameters into rxrpc_call earlier")
cc Marc Dionne <[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]>
---
 net/rxrpc/call_object.c | 1 +
 1 file changed, 1 insertion(+)
net/rxrpc/call_object.c +1 -0
index 59329cfe1532..f035f486c139 100644
@@ -692,6 +692,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
 	rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
 	rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
 	rxrpc_put_local(call->local, rxrpc_local_put_call);
+	key_put(call->key);
 	call_rcu(&call->rcu, rxrpc_rcu_free_call);
 }
 
author maintainer
#9 lore raw

PATCH v5 9/21 rxrpc: Fix to request an ack if window is limited

In reply to David Howells

From: Marc Dionne <[email protected]>

Peers may only send immediate acks for every 2 UDP packets received. When sending a jumbogram, it is important to check that there is sufficient window space to send another same sized jumbogram following the current one, and request an ack if there isn't. Failure to do so may cause the call to stall waiting for an ack until the resend timer fires.

Where jumbograms are in use this causes a very significant drop in performance.

Fixes fe24a5494390 ("rxrpc: Send jumbo DATA packets")
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]>
---
 include/trace/events/rxrpc.h | 1 +
 net/rxrpc/ar-internal.h      | 2 +-
 net/rxrpc/output.c           | 2 ++
 net/rxrpc/proc.c             | 5 +++--
 4 files changed, 7 insertions(+), 3 deletions(-)
include/trace/events/rxrpc.h +1 -0
index f7f559204b87..578b8038b211 100644
@@ -521,6 +521,7 @@
 #define rxrpc_req_ack_traces \
 	EM(rxrpc_reqack_ack_lost,		"ACK-LOST  ")	\
 	EM(rxrpc_reqack_app_stall,		"APP-STALL ")	\
+	EM(rxrpc_reqack_jumbo_win,		"JUMBO-WIN ")	\
 	EM(rxrpc_reqack_more_rtt,		"MORE-RTT  ")	\
 	EM(rxrpc_reqack_no_srv_last,		"NO-SRVLAST")	\
 	EM(rxrpc_reqack_old_rtt,		"OLD-RTT   ")	\
net/rxrpc/ar-internal.h +1 -1
index 36d6ca0d1089..96ecb83c9071 100644
@@ -117,7 +117,7 @@ struct rxrpc_net {
 	atomic_t		stat_tx_jumbo[10];
 	atomic_t		stat_rx_jumbo[10];
 
-	atomic_t		stat_why_req_ack[8];
+	atomic_t		stat_why_req_ack[9];
 
 	atomic_t		stat_io_loop;
 };
net/rxrpc/output.c +2 -0
index d70db367e358..870e59bf06af 100644
@@ -479,6 +479,8 @@ static size_t rxrpc_prepare_data_subpacket(struct rxrpc_call *call,
 		why = rxrpc_reqack_old_rtt;
 	else if (!last && !after(READ_ONCE(call->send_top), txb->seq))
 		why = rxrpc_reqack_app_stall;
+	else if (call->tx_winsize <= (2 * req->n) || call->cong_cwnd <= (2 * req->n))
+		why = rxrpc_reqack_jumbo_win;
 	else
 		goto dont_set_request_ack;
 
net/rxrpc/proc.c +3 -2
index 59292f7f9205..7755fca5beb8 100644
@@ -518,11 +518,12 @@ int rxrpc_stats_show(struct seq_file *seq, void *v)
 		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]),
 		   atomic_read(&rxnet->stat_rx_acks[0]));
 	seq_printf(seq,
-		   "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u\n",
+		   "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u jwin=%u\n",
 		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
 		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
 		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]),
-		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]));
+		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]),
+		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_jumbo_win]));
 	seq_printf(seq,
 		   "Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
 		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),
author maintainer
#10 lore raw

PATCH v5 10/21 rxrpc: Only put the call ref if one was acquired

In reply to David Howells

From: Douya Le <[email protected]>

rxrpc_input_packet_on_conn() can process a to-client packet after the current client call on the channel has already been torn down. In that case chan->call is NULL, rxrpc_try_get_call() returns NULL and there is no reference to drop.

The client-side implicit-end error path does not account for that and unconditionally calls rxrpc_put_call(). This turns a protocol error path into a kernel crash instead of rejecting the packet.

Only drop the call reference if one was actually acquired. Keep the existing protocol error handling unchanged.

Fixes 5e6ef4f1017c ("rxrpc: Make the I/O thread take over the call and local processor work")
cc Marc Dionne <[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]>
---
 net/rxrpc/io_thread.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/rxrpc/io_thread.c +2 -1
index e939ecf417c4..697956931925 100644
@@ -419,7 +419,8 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
 
 	if (sp->hdr.callNumber > chan->call_id) {
 		if (rxrpc_to_client(sp)) {
-			rxrpc_put_call(call, rxrpc_call_put_input);
+			if (call)
+				rxrpc_put_call(call, rxrpc_call_put_input);
 			return rxrpc_protocol_error(skb,
 						    rxrpc_eproto_unexpected_implicit_end);
 		}
author maintainer
#11 lore raw

PATCH v5 11/21 rxrpc: reject undecryptable rxkad response tickets

In reply to David Howells

From: Yuqi Xu <[email protected]>

rxkad_decrypt_ticket() decrypts the RXKAD response ticket and then parses the buffer as plaintext without checking whether crypto_skcipher_decrypt() succeeded.

A malformed RESPONSE can therefore use a non-block-aligned ticket length, make the decrypt operation fail, and still drive the ticket parser with attacker-controlled bytes.

Check the decrypt result and abort the connection with RXKADBADTICKET when ticket decryption fails.

Fixes 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
cc Marc Dionne <[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]>
---
 net/rxrpc/rxkad.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
net/rxrpc/rxkad.c +5 -1
index e923d6829008..0f79d694cb08 100644
@@ -958,6 +958,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 	struct in_addr addr;
 	unsigned int life;
 	time64_t issue, now;
+	int ret;
 	bool little_endian;
 	u8 *p, *q, *name, *end;
 
@@ -977,8 +978,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 	sg_init_one(&sg[0], ticket, ticket_len);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
-	crypto_skcipher_decrypt(req);
+	ret = crypto_skcipher_decrypt(req);
 	skcipher_request_free(req);
+	if (ret < 0)
+		return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
+					rxkad_abort_resp_tkt_short);
 
 	p = ticket;
 	end = p + ticket_len;
author maintainer
#12 lore raw

PATCH v5 12/21 rxrpc: fix RESPONSE authenticator parser OOB read

In reply to David Howells

From: Keenan Dong <[email protected]>

rxgk_verify_authenticator() copies auth_len bytes into a temporary buffer and then passes p + auth_len as the parser limit to rxgk_do_verify_authenticator(). Since p is a __be32 *, that inflates the parser end pointer by a factor of four and lets malformed RESPONSE authenticators read past the kmalloc() buffer.

Decoded from the original latest-net reproduction logs with scripts/decode_stacktrace.sh:

BUG: KASAN: slab-out-of-bounds in rxgk_verify_response()
Call Trace:
 dump_stack_lvl() [lib/dump_stack.c:123]
 print_report() [mm/kasan/report.c:379 mm/kasan/report.c:482]
 kasan_report() [mm/kasan/report.c:597]
 rxgk_verify_response()
   [net/rxrpc/rxgk.c:1103 net/rxrpc/rxgk.c:1167
    net/rxrpc/rxgk.c:1274]
 rxrpc_process_connection()
   [net/rxrpc/conn_event.c:266 net/rxrpc/conn_event.c:364
    net/rxrpc/conn_event.c:386]
 process_one_work() [kernel/workqueue.c:3281]
 worker_thread()
   [kernel/workqueue.c:3353 kernel/workqueue.c:3440]
 kthread() [kernel/kthread.c:436]
 ret_from_fork() [arch/x86/kernel/process.c:164]

Allocated by task 54:
 rxgk_verify_response()
   [include/linux/slab.h:954 net/rxrpc/rxgk.c:1155
    net/rxrpc/rxgk.c:1274]
 rxrpc_process_connection()
   [net/rxrpc/conn_event.c:266 net/rxrpc/conn_event.c:364
    net/rxrpc/conn_event.c:386]

Convert the byte count to __be32 units before constructing the parser limit.

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
cc Marc Dionne <[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 Willy Tarreau <[email protected]>
---
 net/rxrpc/rxgk.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/rxrpc/rxgk.c +2 -1
index f9f5a2dc62ed..01dbdf0b5cf2 100644
@@ -1164,7 +1164,8 @@ static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
 	}
 
 	p = auth;
-	ret = rxgk_do_verify_authenticator(conn, krb5, skb, p, p + auth_len);
+	ret = rxgk_do_verify_authenticator(conn, krb5, skb, p,
+					   p + auth_len / sizeof(*p));
 error:
 	kfree(auth);
 	return ret;
author maintainer
#13 lore raw

PATCH v5 13/21 rxrpc: fix oversized RESPONSE authenticator length check

In reply to David Howells

From: Keenan Dong <[email protected]>

rxgk_verify_response() decodes auth_len from the packet and is supposed to verify that it fits in the remaining bytes. The existing check is inverted, so oversized RESPONSE authenticators are accepted and passed to rxgk_decrypt_skb(), which can later reach skb_to_sgvec() with an impossible length and hit BUG_ON(len).

Decoded from the original latest-net reproduction logs with scripts/decode_stacktrace.sh:

RIP: __skb_to_sgvec()
  [net/core/skbuff.c:5285 (discriminator 1)]
Call Trace:
 skb_to_sgvec() [net/core/skbuff.c:5305]
 rxgk_decrypt_skb() [net/rxrpc/rxgk_common.h:81]
 rxgk_verify_response() [net/rxrpc/rxgk.c:1268]
 rxrpc_process_connection()
   [net/rxrpc/conn_event.c:266 net/rxrpc/conn_event.c:364
    net/rxrpc/conn_event.c:386]
 process_one_work() [kernel/workqueue.c:3281]
 worker_thread()
   [kernel/workqueue.c:3353 kernel/workqueue.c:3440]
 kthread() [kernel/kthread.c:436]
 ret_from_fork() [arch/x86/kernel/process.c:164]

Reject authenticator lengths that exceed the remaining packet payload.

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
cc Marc Dionne <[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 Willy Tarreau <[email protected]>
---
 net/rxrpc/rxgk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/rxrpc/rxgk.c +1 -1
index 01dbdf0b5cf2..9e4a4ff28913 100644
@@ -1224,7 +1224,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
 
 	auth_offset	= offset;
 	auth_len	= ntohl(xauth_len);
-	if (auth_len < len)
+	if (auth_len > len)
 		goto short_packet;
 	if (auth_len & 3)
 		goto inconsistent;
author maintainer
#14 lore raw

PATCH v5 14/21 rxrpc: fix reference count leak in rxrpc_server_keyring()

In reply to David Howells

From: Luxiao Xu <[email protected]>

This patch fixes a reference count leak in rxrpc_server_keyring() by checking if rx->securities is already set.

Fixes 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
cc Marc Dionne <[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]>
---
 net/rxrpc/server_key.c | 3 +++
 1 file changed, 3 insertions(+)
net/rxrpc/server_key.c +3 -0
index 36b05fd842a7..27491f1e1273 100644
@@ -125,6 +125,9 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
 
 	_enter("");
 
+	if (rx->securities)
+		return -EINVAL;
+
 	if (optlen <= 0 || optlen > PAGE_SIZE - 1)
 		return -EINVAL;
 
author maintainer
#15 lore raw

PATCH v5 15/21 rxrpc: Fix key/keyring checks in setsockopt(RXRPC_SECURITY_KEY/KEYRING)

In reply to David Howells

An AF_RXRPC socket can be both client and server at the same time. When sending new calls (ie. it's acting as a client), it uses rx->key to set the security, and when accepting incoming calls (ie. it's acting as a server), it uses rx->securities.

setsockopt(RXRPC_SECURITY_KEY) sets rx->key to point to an rxrpc-type key and setsockopt(RXRPC_SECURITY_KEYRING) sets rx->securities to point to a keyring of rxrpc_s-type keys.

Now, it should be possible to use both rx->key and rx->securities on the same socket - but for userspace AF_RXRPC sockets rxrpc_setsockopt() prevents that.

Fix this by:

(1) Remove the incorrect check rxrpc_setsockopt(RXRPC_SECURITY_KEYRING)

     makes on rx->key.

(2) Move the check that rxrpc_setsockopt(RXRPC_SECURITY_KEY) makes on

     rx->key down into rxrpc_request_key().

(3) Remove rxrpc_request_key()'s check on rx->securities.

This (in combination with a previous patch) pushes the checks down into the functions that set those pointers and removes the cross-checks that prevent both key and keyring being set.

Fixes 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
cc Marc Dionne <[email protected]>
cc Anderson Nascimento <[email protected]>
cc Luxiao Xu <[email protected]>
cc Yuan Tan <[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]>
---
 net/rxrpc/af_rxrpc.c | 6 ------
 net/rxrpc/key.c      | 2 +-
 2 files changed, 1 insertion(+), 7 deletions(-)
net/rxrpc/af_rxrpc.c +0 -6
index 0f90272ac254..32ec91fa938f 100644
@@ -654,9 +654,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
 			goto success;
 
 		case RXRPC_SECURITY_KEY:
-			ret = -EINVAL;
-			if (rx->key)
-				goto error;
 			ret = -EISCONN;
 			if (rx->sk.sk_state != RXRPC_UNBOUND)
 				goto error;
@@ -664,9 +661,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
 			goto error;
 
 		case RXRPC_SECURITY_KEYRING:
-			ret = -EINVAL;
-			if (rx->key)
-				goto error;
 			ret = -EISCONN;
 			if (rx->sk.sk_state != RXRPC_UNBOUND)
 				goto error;
net/rxrpc/key.c +1 -1
index 77237a82be3b..6301d79ee35a 100644
@@ -622,7 +622,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
 
 	_enter("");
 
-	if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
+	if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
 		return -EINVAL;
 
 	description = memdup_sockptr_nul(optval, optlen);
author maintainer
#16 lore raw

PATCH v5 16/21 rxrpc: Fix missing error checks for rxkad encryption/decryption failure

In reply to David Howells

Add error checking for failure of crypto_skcipher_en/decrypt() to various rxkad function as the crypto functions can fail with ENOMEM at least.

Fixes 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
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]>
---
 net/rxrpc/rxkad.c | 57 +++++++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 19 deletions(-)
net/rxrpc/rxkad.c +38 -19
index 0f79d694cb08..eb7f2769d2b1 100644
@@ -197,6 +197,7 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
 	struct rxrpc_crypt iv;
 	__be32 *tmpbuf;
 	size_t tmpsize = 4 * sizeof(__be32);
+	int ret;
 
 	_enter("");
 
@@ -225,13 +226,13 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
 	skcipher_request_set_sync_tfm(req, ci);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
-	crypto_skcipher_encrypt(req);
+	ret = crypto_skcipher_encrypt(req);
 	skcipher_request_free(req);
 
 	memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
 	kfree(tmpbuf);
-	_leave(" = 0");
-	return 0;
+	_leave(" = %d", ret);
+	return ret;
 }
 
 /*
@@ -264,6 +265,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
 	struct scatterlist sg;
 	size_t pad;
 	u16 check;
+	int ret;
 
 	_enter("");
 
@@ -286,11 +288,11 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
 	skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-	crypto_skcipher_encrypt(req);
+	ret = crypto_skcipher_encrypt(req);
 	skcipher_request_zero(req);
 
-	_leave(" = 0");
-	return 0;
+	_leave(" = %d", ret);
+	return ret;
 }
 
 /*
@@ -345,7 +347,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
 	union {
 		__be32 buf[2];
 	} crypto __aligned(8);
-	u32 x, y;
+	u32 x, y = 0;
 	int ret;
 
 	_enter("{%d{%x}},{#%u},%u,",
@@ -376,8 +378,10 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
 	skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-	crypto_skcipher_encrypt(req);
+	ret = crypto_skcipher_encrypt(req);
 	skcipher_request_zero(req);
+	if (ret < 0)
+		goto out;
 
 	y = ntohl(crypto.buf[1]);
 	y = (y >> 16) & 0xffff;
@@ -413,6 +417,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
 		memset(p + txb->pkt_len, 0, gap);
 	}
 
+out:
 	skcipher_request_free(req);
 	_leave(" = %d [set %x]", ret, y);
 	return ret;
@@ -453,8 +458,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
 	skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
-	crypto_skcipher_decrypt(req);
+	ret = crypto_skcipher_decrypt(req);
 	skcipher_request_zero(req);
+	if (ret < 0)
+		return ret;
 
 	/* Extract the decrypted packet length */
 	if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -531,10 +538,14 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
 	skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg, sg, sp->len, iv.x);
-	crypto_skcipher_decrypt(req);
+	ret = crypto_skcipher_decrypt(req);
 	skcipher_request_zero(req);
 	if (sg != _sg)
 		kfree(sg);
+	if (ret < 0) {
+		WARN_ON_ONCE(ret != -ENOMEM);
+		return ret;
+	}
 
 	/* Extract the decrypted packet length */
 	if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -602,8 +613,10 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
 	skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-	crypto_skcipher_encrypt(req);
+	ret = crypto_skcipher_encrypt(req);
 	skcipher_request_zero(req);
+	if (ret < 0)
+		goto out;
 
 	y = ntohl(crypto.buf[1]);
 	cksum = (y >> 16) & 0xffff;
@@ -1077,21 +1090,23 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 /*
  * decrypt the response packet
  */
-static void rxkad_decrypt_response(struct rxrpc_connection *conn,
-				   struct rxkad_response *resp,
-				   const struct rxrpc_crypt *session_key)
+static int rxkad_decrypt_response(struct rxrpc_connection *conn,
+				  struct rxkad_response *resp,
+				  const struct rxrpc_crypt *session_key)
 {
 	struct skcipher_request *req = rxkad_ci_req;
 	struct scatterlist sg[1];
 	struct rxrpc_crypt iv;
+	int ret;
 
 	_enter(",,%08x%08x",
 	       ntohl(session_key->n[0]), ntohl(session_key->n[1]));
 
 	mutex_lock(&rxkad_ci_mutex);
-	if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
-					sizeof(*session_key)) < 0)
-		BUG();
+	ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
+					  sizeof(*session_key));
+	if (ret < 0)
+		goto unlock;
 
 	memcpy(&iv, session_key, sizeof(iv));
 
@@ -1100,12 +1115,14 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
 	skcipher_request_set_sync_tfm(req, rxkad_ci);
 	skcipher_request_set_callback(req, 0, NULL, NULL);
 	skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
-	crypto_skcipher_decrypt(req);
+	ret = crypto_skcipher_decrypt(req);
 	skcipher_request_zero(req);
 
+unlock:
 	mutex_unlock(&rxkad_ci_mutex);
 
 	_leave("");
+	return ret;
 }
 
 /*
@@ -1198,7 +1215,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
 
 	/* use the session key from inside the ticket to decrypt the
 	 * response */
-	rxkad_decrypt_response(conn, response, &session_key);
+	ret = rxkad_decrypt_response(conn, response, &session_key);
+	if (ret < 0)
+		goto temporary_error_free_ticket;
 
 	if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
 	    ntohl(response->encrypted.cid) != conn->proto.cid ||
author maintainer
#17 lore raw

PATCH v5 17/21 rxrpc: Fix integer overflow in rxgk_verify_response()

In reply to David Howells

In rxgk_verify_response(), there's a potential integer overflow due to rounding up token_len before checking it, thereby allowing the length check to be bypassed.

Fix this by checking the unrounded value against len too (len is limited as the response must fit in a single UDP packet).

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
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]>
---
 net/rxrpc/rxgk.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/rxrpc/rxgk.c +2 -1
index 9e4a4ff28913..064c1531fc99 100644
@@ -1209,7 +1209,8 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
 
 	token_offset	= offset;
 	token_len	= ntohl(rhdr.token_len);
-	if (xdr_round_up(token_len) + sizeof(__be32) > len)
+	if (token_len > len ||
+	    xdr_round_up(token_len) + sizeof(__be32) > len)
 		goto short_packet;
 
 	trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_len);
author maintainer
#18 lore raw

PATCH v5 18/21 rxrpc: Fix leak of rxgk context in rxgk_verify_response()

In reply to David Howells

Fix rxgk_verify_response() to clean up the rxgk context it creates.

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
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]>
---
 net/rxrpc/rxgk.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
net/rxrpc/rxgk.c +4 -2
index 064c1531fc99..c67e3c2ca871 100644
@@ -1270,16 +1270,18 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
 	if (ret < 0) {
 		rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret,
 				 rxgk_abort_resp_auth_dec);
-		goto out;
+		goto out_gk;
 	}
 
 	ret = rxgk_verify_authenticator(conn, krb5, skb, auth_offset, auth_len);
 	if (ret < 0)
-		goto out;
+		goto out_gk;
 
 	conn->key = key;
 	key = NULL;
 	ret = 0;
+out_gk:
+	rxgk_put(gk);
 out:
 	key_put(key);
 	_leave(" = %d", ret);
author maintainer
#19 lore raw

PATCH v5 19/21 rxrpc: Fix buffer overread in rxgk_do_verify_authenticator()

In reply to David Howells

Fix rxgk_do_verify_authenticator() to check the buffer size before checking the nonce.

Fixes 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
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]>
---
 net/rxrpc/rxgk.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
net/rxrpc/rxgk.c +4 -1
index c67e3c2ca871..0d5e654da918 100644
@@ -1085,6 +1085,9 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
 
 	_enter("");
 
+	if ((end - p) * sizeof(__be32) < 24)
+		return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
+					rxgk_abort_resp_short_auth);
 	if (memcmp(p, conn->rxgk.nonce, 20) != 0)
 		return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
 					rxgk_abort_resp_bad_nonce);
@@ -1098,7 +1101,7 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
 	p += xdr_round_up(app_len) / sizeof(__be32);
 	if (end - p < 4)
 		return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
-					rxgk_abort_resp_short_applen);
+					rxgk_abort_resp_short_auth);
 
 	level	= ntohl(*p++);
 	epoch	= ntohl(*p++);
author maintainer
#20 lore raw

PATCH v5 20/21 rxrpc: only handle RESPONSE during service challenge

In reply to David Howells

From: Wang Jie <[email protected]>

Only process RESPONSE packets while the service connection is still in RXRPC_CONN_SERVICE_CHALLENGING. Check that state under state_lock before running response verification and security initialization, then use a local secured flag to decide whether to queue the secured-connection work after the state transition. This keeps duplicate or late RESPONSE packets from re-running the setup path and removes the unlocked post-transition state test.

Fixes 17926a79320a ("net: AF_RXRPC: Provide secure RxRPC sockets for use by userspace and kernel both")
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]>
---
 net/rxrpc/conn_event.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
net/rxrpc/conn_event.c +12 -2
index c50cbfc5a313..9a41ec708aeb 100644
@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
 			       struct sk_buff *skb)
 {
 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	bool secured = false;
 	int ret;
 
 	if (conn->state == RXRPC_CONN_ABORTED)
@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
 		return ret;
 
 	case RXRPC_PACKET_TYPE_RESPONSE:
+		spin_lock_irq(&conn->state_lock);
+		if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
+			spin_unlock_irq(&conn->state_lock);
+			return 0;
+		}
+		spin_unlock_irq(&conn->state_lock);
+
 		ret = conn->security->verify_response(conn, skb);
 		if (ret < 0)
 			return ret;
@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
 			return ret;
 
 		spin_lock_irq(&conn->state_lock);
-		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
+		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
 			conn->state = RXRPC_CONN_SERVICE;
+			secured = true;
+		}
 		spin_unlock_irq(&conn->state_lock);
 
-		if (conn->state == RXRPC_CONN_SERVICE) {
+		if (secured) {
 			/* Offload call state flipping to the I/O thread.  As
 			 * we've already received the packet, put it on the
 			 * front of the queue.
author maintainer
#21 lore raw

PATCH v5 21/21 rxrpc: proc: size address buffers for %pISpc output

In reply to David Howells

From: Pengpeng Hou <[email protected]>

The AF_RXRPC procfs helpers format local and remote socket addresses into fixed 50-byte stack buffers with "%pISpc".

That is too small for the longest current-tree IPv6-with-port form the formatter can produce. In lib/vsprintf.c, the compressed IPv6 path uses a dotted-quad tail not only for v4mapped addresses, but also for ISATAP addresses via ipv6_addr_is_isatap().

As a result, a case such as

[ffff:ffff:ffff:ffff:0:5efe:255.255.255.255]:65535

is possible with the current formatter. That is 50 visible characters, so 51 bytes including the trailing NUL, which does not fit in the existing char[50] buffers used by net/rxrpc/proc.c.

Size the buffers from the formatter's maximum textual form and switch the call sites to scnprintf().

Changes since v1:
- correct the changelog to cite the actual maximum current-tree case explicitly
- frame the proof around the ISATAP formatting path instead of the earlier mapped-v4 example

Fixes 75b54cb57ca3 ("rxrpc: Add IPv6 support")
cc Marc Dionne <[email protected]>
cc Anderson Nascimento <[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]>
---
 net/rxrpc/proc.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)
net/rxrpc/proc.c +18 -14
index 7755fca5beb8..e9a27fa7b25d 100644
@@ -10,6 +10,10 @@
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+#define RXRPC_PROC_ADDRBUF_SIZE \
+	(sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + \
+	 sizeof(":12345"))
+
 static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
 	[RXRPC_CONN_UNUSED]			= "Unused  ",
 	[RXRPC_CONN_CLIENT_UNSECURED]		= "ClUnsec ",
@@ -53,7 +57,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 	enum rxrpc_call_state state;
 	rxrpc_seq_t tx_bottom;
-	char lbuff[50], rbuff[50];
+	char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
 	long timeout = 0;
 
 	if (v == &rxnet->calls) {
@@ -69,11 +73,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
 
 	local = call->local;
 	if (local)
-		sprintf(lbuff, "%pISpc", &local->srx.transport);
+		scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
 	else
 		strcpy(lbuff, "no_local");
 
-	sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
+	scnprintf(rbuff, sizeof(rbuff), "%pISpc", &call->dest_srx.transport);
 
 	state = rxrpc_call_state(call);
 	if (state != RXRPC_CALL_SERVER_PREALLOC)
@@ -142,7 +146,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
 	struct rxrpc_connection *conn;
 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 	const char *state;
-	char lbuff[50], rbuff[50];
+	char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
 
 	if (v == &rxnet->conn_proc_list) {
 		seq_puts(seq,
@@ -161,8 +165,8 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
 		goto print;
 	}
 
-	sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
-	sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
+	scnprintf(lbuff, sizeof(lbuff), "%pISpc", &conn->local->srx.transport);
+	scnprintf(rbuff, sizeof(rbuff), "%pISpc", &conn->peer->srx.transport);
 print:
 	state = rxrpc_is_conn_aborted(conn) ?
 		rxrpc_call_completions[conn->completion] :
@@ -228,7 +232,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
 {
 	struct rxrpc_bundle *bundle;
 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
-	char lbuff[50], rbuff[50];
+	char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
 
 	if (v == &rxnet->bundle_proc_list) {
 		seq_puts(seq,
@@ -242,8 +246,8 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
 
 	bundle = list_entry(v, struct rxrpc_bundle, proc_link);
 
-	sprintf(lbuff, "%pISpc", &bundle->local->srx.transport);
-	sprintf(rbuff, "%pISpc", &bundle->peer->srx.transport);
+	scnprintf(lbuff, sizeof(lbuff), "%pISpc", &bundle->local->srx.transport);
+	scnprintf(rbuff, sizeof(rbuff), "%pISpc", &bundle->peer->srx.transport);
 	seq_printf(seq,
 		   "UDP   %-47.47s %-47.47s %4x %3u %3d"
 		   " %c%c%c %08x | %08x %08x %08x %08x %08x\n",
@@ -279,7 +283,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
 {
 	struct rxrpc_peer *peer;
 	time64_t now;
-	char lbuff[50], rbuff[50];
+	char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
@@ -290,9 +294,9 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
 
 	peer = list_entry(v, struct rxrpc_peer, hash_link);
 
-	sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
+	scnprintf(lbuff, sizeof(lbuff), "%pISpc", &peer->local->srx.transport);
 
-	sprintf(rbuff, "%pISpc", &peer->srx.transport);
+	scnprintf(rbuff, sizeof(rbuff), "%pISpc", &peer->srx.transport);
 
 	now = ktime_get_seconds();
 	seq_printf(seq,
@@ -401,7 +405,7 @@ const struct seq_operations rxrpc_peer_seq_ops = {
 static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
 {
 	struct rxrpc_local *local;
-	char lbuff[50];
+	char lbuff[RXRPC_PROC_ADDRBUF_SIZE];
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
@@ -412,7 +416,7 @@ static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
 
 	local = hlist_entry(v, struct rxrpc_local, link);
 
-	sprintf(lbuff, "%pISpc", &local->srx.transport);
+	scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
 
 	seq_printf(seq,
 		   "UDP   %-47.47s %3u %3u %3u\n",
#22 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 10 lines · On Wed, 8 Apr 2026 13:12:28 +0100 you wrote:

Here are some fixes for rxrpc:

(1) Fix key quota calculation.

(2) Fix a memory leak.

(3) Fix rxrpc_new_client_call_for_sendmsg() to substitute NULL for an empty key.

[...]

Here is the summary with links:
- [net,v5,01/21] rxrpc: Fix key quota calculation for multitoken keys

    https://git.kernel.org/netdev/net/c/bdbfead6d389
  - [net,v5,02/21] rxrpc: Fix key parsing memleak
    https://git.kernel.org/netdev/net/c/b555912b9b21
  - [net,v5,03/21] rxrpc: Fix anonymous key handling
    https://git.kernel.org/netdev/net/c/6a59d84b4fc2
  - [net,v5,04/21] rxrpc: Fix call removal to use RCU safe deletion
    https://git.kernel.org/netdev/net/c/146d4ab94cf1
  - [net,v5,05/21] rxrpc: Fix RxGK token loading to check bounds
    https://git.kernel.org/netdev/net/c/d179a868dd75
  - [net,v5,06/21] rxrpc: Fix use of wrong skb when comparing queued RESP challenge serial
    https://git.kernel.org/netdev/net/c/b33f5741bb18
  - [net,v5,07/21] rxrpc: Fix rack timer warning to report unexpected mode
    https://git.kernel.org/netdev/net/c/65b3ffe0972e
  - [net,v5,08/21] rxrpc: Fix key reference count leak from call->key
    https://git.kernel.org/netdev/net/c/d666540d217e
  - [net,v5,09/21] rxrpc: Fix to request an ack if window is limited
    https://git.kernel.org/netdev/net/c/0cd3e3f3f2ec
  - [net,v5,10/21] rxrpc: Only put the call ref if one was acquired
    https://git.kernel.org/netdev/net/c/6331f1b24a3e
  - [net,v5,11/21] rxrpc: reject undecryptable rxkad response tickets
    https://git.kernel.org/netdev/net/c/fe4447cd9562
  - [net,v5,12/21] rxrpc: fix RESPONSE authenticator parser OOB read
    https://git.kernel.org/netdev/net/c/3e3138007887
  - [net,v5,13/21] rxrpc: fix oversized RESPONSE authenticator length check
    https://git.kernel.org/netdev/net/c/a2567217ade9
  - [net,v5,14/21] rxrpc: fix reference count leak in rxrpc_server_keyring()
    https://git.kernel.org/netdev/net/c/f125846ee79f
  - [net,v5,15/21] rxrpc: Fix key/keyring checks in setsockopt(RXRPC_SECURITY_KEY/KEYRING)
    https://git.kernel.org/netdev/net/c/2afd86ccbb20
  - [net,v5,16/21] rxrpc: Fix missing error checks for rxkad encryption/decryption failure
    https://git.kernel.org/netdev/net/c/f93af41b9f5f
  - [net,v5,17/21] rxrpc: Fix integer overflow in rxgk_verify_response()
    https://git.kernel.org/netdev/net/c/699e52180f42
  - [net,v5,18/21] rxrpc: Fix leak of rxgk context in rxgk_verify_response()
    https://git.kernel.org/netdev/net/c/7e1876caa836
  - [net,v5,19/21] rxrpc: Fix buffer overread in rxgk_do_verify_authenticator()
    https://git.kernel.org/netdev/net/c/f564af387c8c
  - [net,v5,20/21] rxrpc: only handle RESPONSE during service challenge
    https://git.kernel.org/netdev/net/c/c43ffdcfdbb5
  - [net,v5,21/21] rxrpc: proc: size address buffers for %pISpc output
    https://git.kernel.org/netdev/net/c/a44ce6aa2efb

You are awesome, thank you!

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