Commit f0295678 authored by David Howells's avatar David Howells Committed by Jakub Kicinski
Browse files

rxrpc: Fix to use conn aborts for conn-wide failures



Fix rxrpc to use connection-level aborts for things that affect the whole
connection, such as the service ID not matching a local service.

Fixes: 57af281e ("rxrpc: Tidy up abort generation infrastructure")
Reported-by: default avatarJeffrey Altman <jaltman@auristor.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
Link: https://patch.msgid.link/20250717074350.3767366-6-dhowells@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e9c0b96e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ enum rxrpc_skb_mark {
	RXRPC_SKB_MARK_SERVICE_CONN_SECURED, /* Service connection response has been verified */
	RXRPC_SKB_MARK_REJECT_BUSY,	/* Reject with BUSY */
	RXRPC_SKB_MARK_REJECT_ABORT,	/* Reject with ABORT (code in skb->priority) */
	RXRPC_SKB_MARK_REJECT_CONN_ABORT, /* Reject with connection ABORT (code in skb->priority) */
};

/*
@@ -1253,6 +1254,8 @@ int rxrpc_encap_rcv(struct sock *, struct sk_buff *);
void rxrpc_error_report(struct sock *);
bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
			s32 abort_code, int err);
bool rxrpc_direct_conn_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
			     s32 abort_code, int err);
int rxrpc_io_thread(void *data);
void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb);
static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local)
+6 −6
Original line number Diff line number Diff line
@@ -374,7 +374,7 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
	spin_lock(&rx->incoming_lock);
	if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
	    rx->sk.sk_state == RXRPC_CLOSE) {
		rxrpc_direct_abort(skb, rxrpc_abort_shut_down,
		rxrpc_direct_conn_abort(skb, rxrpc_abort_shut_down,
					RX_INVALID_OPERATION, -ESHUTDOWN);
		goto no_call;
	}
@@ -422,11 +422,11 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,

unsupported_service:
	read_unlock_irq(&local->services_lock);
	return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
	return rxrpc_direct_conn_abort(skb, rxrpc_abort_service_not_offered,
				       RX_INVALID_OPERATION, -EOPNOTSUPP);
unsupported_security:
	read_unlock_irq(&local->services_lock);
	return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
	return rxrpc_direct_conn_abort(skb, rxrpc_abort_service_not_offered,
				       RX_INVALID_OPERATION, -EKEYREJECTED);
no_call:
	spin_unlock(&rx->incoming_lock);
+14 −0
Original line number Diff line number Diff line
@@ -97,6 +97,20 @@ bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
	return false;
}

/*
 * Directly produce a connection abort from a packet.
 */
bool rxrpc_direct_conn_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
			     s32 abort_code, int err)
{
	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

	trace_rxrpc_abort(0, why, sp->hdr.cid, 0, sp->hdr.seq, abort_code, err);
	skb->mark = RXRPC_SKB_MARK_REJECT_CONN_ABORT;
	skb->priority = abort_code;
	return false;
}

static bool rxrpc_bad_message(struct sk_buff *skb, enum rxrpc_abort_reason why)
{
	return rxrpc_direct_abort(skb, why, RX_PROTOCOL_ERROR, -EBADMSG);
+10 −9
Original line number Diff line number Diff line
@@ -829,7 +829,13 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	memset(&whdr, 0, sizeof(whdr));
	whdr = (struct rxrpc_wire_header) {
		.epoch		= htonl(sp->hdr.epoch),
		.cid		= htonl(sp->hdr.cid),
		.callNumber	= htonl(sp->hdr.callNumber),
		.serviceId	= htons(sp->hdr.serviceId),
		.flags		= ~sp->hdr.flags & RXRPC_CLIENT_INITIATED,
	};

	switch (skb->mark) {
	case RXRPC_SKB_MARK_REJECT_BUSY:
@@ -837,6 +843,9 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
		size = sizeof(whdr);
		ioc = 1;
		break;
	case RXRPC_SKB_MARK_REJECT_CONN_ABORT:
		whdr.callNumber	= 0;
		fallthrough;
	case RXRPC_SKB_MARK_REJECT_ABORT:
		whdr.type = RXRPC_PACKET_TYPE_ABORT;
		code = htonl(skb->priority);
@@ -850,14 +859,6 @@ void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
	if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
		msg.msg_namelen = srx.transport_len;

		whdr.epoch	= htonl(sp->hdr.epoch);
		whdr.cid	= htonl(sp->hdr.cid);
		whdr.callNumber	= htonl(sp->hdr.callNumber);
		whdr.serviceId	= htons(sp->hdr.serviceId);
		whdr.flags	= sp->hdr.flags;
		whdr.flags	^= RXRPC_CLIENT_INITIATED;
		whdr.flags	&= RXRPC_CLIENT_INITIATED;

		iov_iter_kvec(&msg.msg_iter, WRITE, iov, ioc, size);
		ret = do_udp_sendmsg(local->socket, &msg, size);
		if (ret < 0)
+4 −4
Original line number Diff line number Diff line
@@ -140,14 +140,14 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,

	sec = rxrpc_security_lookup(sp->hdr.securityIndex);
	if (!sec) {
		rxrpc_direct_abort(skb, rxrpc_abort_unsupported_security,
		rxrpc_direct_conn_abort(skb, rxrpc_abort_unsupported_security,
					RX_INVALID_OPERATION, -EKEYREJECTED);
		return NULL;
	}

	if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
	    !rx->securities) {
		rxrpc_direct_abort(skb, rxrpc_abort_no_service_key,
		rxrpc_direct_conn_abort(skb, rxrpc_abort_no_service_key,
					sec->no_key_abort, -EKEYREJECTED);
		return NULL;
	}