Commit 27ae4bcf authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'rxrpc-miscellaneous-fixes'

David Howells says:

====================
rxrpc: Miscellaneous fixes

Here are some fixes for rxrpc, as found by Sashiko[1]:

 (1) Fix leaks in rxkad_verify_response().

 (2) Fix handling of rxkad-encrypted packets with crypto-misaligned
     lengths.

 (3) Fix problem with unsharing DATA packets potentially causing a crash in
     the caller.

 (4) Fix lack of unsharing of RESPONSE packets.

 (5) Fix integer overflow in RxGK ticket length check.

 (6) Fix missing length check in RxKAD tickets.
====================

Link: https://patch.msgid.link/20260422161438.2593376-1-dhowells@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 8141a2dc ac33733b
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
	EM(rxkad_abort_1_short_encdata,		"rxkad1-short-encdata")	\
	EM(rxkad_abort_1_short_header,		"rxkad1-short-hdr")	\
	EM(rxkad_abort_2_short_check,		"rxkad2-short-check")	\
	EM(rxkad_abort_2_crypto_unaligned,	"rxkad2-crypto-unaligned") \
	EM(rxkad_abort_2_short_data,		"rxkad2-short-data")	\
	EM(rxkad_abort_2_short_header,		"rxkad2-short-hdr")	\
	EM(rxkad_abort_2_short_len,		"rxkad2-short-len")	\
@@ -161,8 +162,6 @@
	E_(rxrpc_call_poke_timer_now,		"Timer-now")

#define rxrpc_skb_traces \
	EM(rxrpc_skb_eaten_by_unshare,		"ETN unshare  ") \
	EM(rxrpc_skb_eaten_by_unshare_nomem,	"ETN unshar-nm") \
	EM(rxrpc_skb_get_call_rx,		"GET call-rx  ") \
	EM(rxrpc_skb_get_conn_secured,		"GET conn-secd") \
	EM(rxrpc_skb_get_conn_work,		"GET conn-work") \
@@ -189,6 +188,7 @@
	EM(rxrpc_skb_put_purge,			"PUT purge    ") \
	EM(rxrpc_skb_put_purge_oob,		"PUT purge-oob") \
	EM(rxrpc_skb_put_response,		"PUT response ") \
	EM(rxrpc_skb_put_response_copy,		"PUT resp-cpy ") \
	EM(rxrpc_skb_put_rotate,		"PUT rotate   ") \
	EM(rxrpc_skb_put_unknown,		"PUT unknown  ") \
	EM(rxrpc_skb_see_conn_work,		"SEE conn-work") \
@@ -197,6 +197,7 @@
	EM(rxrpc_skb_see_recvmsg_oob,		"SEE recvm-oob") \
	EM(rxrpc_skb_see_reject,		"SEE reject   ") \
	EM(rxrpc_skb_see_rotate,		"SEE rotate   ") \
	EM(rxrpc_skb_see_unshare_nomem,		"SEE unshar-nm") \
	E_(rxrpc_skb_see_version,		"SEE version  ")

#define rxrpc_local_traces \
+0 −1
Original line number Diff line number Diff line
@@ -1486,7 +1486,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);
void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_purge_queue(struct sk_buff_head *);
+18 −1
Original line number Diff line number Diff line
@@ -332,7 +332,24 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)

			saw_ack |= sp->hdr.type == RXRPC_PACKET_TYPE_ACK;

			if (sp->hdr.securityIndex != 0 &&
			    skb_cloned(skb)) {
				/* Unshare the packet so that it can be
				 * modified by in-place decryption.
				 */
				struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);

				if (nskb) {
					rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
					rxrpc_input_call_packet(call, nskb);
					rxrpc_free_skb(nskb, rxrpc_skb_put_call_rx);
				} else {
					/* OOM - Drop the packet. */
					rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
				}
			} else {
				rxrpc_input_call_packet(call, skb);
			}
			rxrpc_free_skb(skb, rxrpc_skb_put_call_rx);
			did_receive = true;
		}
+28 −1
Original line number Diff line number Diff line
@@ -240,6 +240,33 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
		rxrpc_notify_socket(call);
}

static int rxrpc_verify_response(struct rxrpc_connection *conn,
				 struct sk_buff *skb)
{
	int ret;

	if (skb_cloned(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);
	}

	return ret;
}

/*
 * connection-level Rx packet processor
 */
@@ -270,7 +297,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
		}
		spin_unlock_irq(&conn->state_lock);

		ret = conn->security->verify_response(conn, skb);
		ret = rxrpc_verify_response(conn, skb);
		if (ret < 0)
			return ret;

+2 −22
Original line number Diff line number Diff line
@@ -192,13 +192,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)
/*
 * Process packets received on the local endpoint
 */
static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb)
{
	struct rxrpc_connection *conn;
	struct sockaddr_rxrpc peer_srx;
	struct rxrpc_skb_priv *sp;
	struct rxrpc_peer *peer = NULL;
	struct sk_buff *skb = *_skb;
	bool ret = false;

	skb_pull(skb, sizeof(struct udphdr));
@@ -244,25 +243,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
			return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
		if (sp->hdr.seq == 0)
			return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq);

		/* Unshare the packet so that it can be modified for in-place
		 * decryption.
		 */
		if (sp->hdr.securityIndex != 0) {
			skb = skb_unshare(skb, GFP_ATOMIC);
			if (!skb) {
				rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
				*_skb = NULL;
				return just_discard;
			}

			if (skb != *_skb) {
				rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare);
				*_skb = skb;
				rxrpc_new_skb(skb, rxrpc_skb_new_unshared);
				sp = rxrpc_skb(skb);
			}
		}
		break;

	case RXRPC_PACKET_TYPE_CHALLENGE:
@@ -494,7 +474,7 @@ int rxrpc_io_thread(void *data)
			switch (skb->mark) {
			case RXRPC_SKB_MARK_PACKET:
				skb->priority = 0;
				if (!rxrpc_input_packet(local, &skb))
				if (!rxrpc_input_packet(local, skb))
					rxrpc_reject_packet(local, skb);
				trace_rxrpc_rx_done(skb->mark, skb->priority);
				rxrpc_free_skb(skb, rxrpc_skb_put_input);
Loading