Commit 32247444 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:

 (1) Fix the calling of IP routing code with IRQs disabled.

 (2) Fix a recvmsg/recvmsg race when the first completes a call.

 (3) Fix a race between notification, recvmsg and sendmsg releasing a call.

 (4) Fix abort of abort.

 (5) Fix call-level aborts that should be connection-level aborts.
====================

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


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 88b06e4f f0295678
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -322,20 +322,24 @@
	EM(rxrpc_call_put_kernel,		"PUT kernel  ") \
	EM(rxrpc_call_put_poke,			"PUT poke    ") \
	EM(rxrpc_call_put_recvmsg,		"PUT recvmsg ") \
	EM(rxrpc_call_put_release_recvmsg_q,	"PUT rls-rcmq") \
	EM(rxrpc_call_put_release_sock,		"PUT rls-sock") \
	EM(rxrpc_call_put_release_sock_tba,	"PUT rls-sk-a") \
	EM(rxrpc_call_put_sendmsg,		"PUT sendmsg ") \
	EM(rxrpc_call_put_unnotify,		"PUT unnotify") \
	EM(rxrpc_call_put_userid_exists,	"PUT u-exists") \
	EM(rxrpc_call_put_userid,		"PUT user-id ") \
	EM(rxrpc_call_see_accept,		"SEE accept  ") \
	EM(rxrpc_call_see_activate_client,	"SEE act-clnt") \
	EM(rxrpc_call_see_already_released,	"SEE alrdy-rl") \
	EM(rxrpc_call_see_connect_failed,	"SEE con-fail") \
	EM(rxrpc_call_see_connected,		"SEE connect ") \
	EM(rxrpc_call_see_conn_abort,		"SEE conn-abt") \
	EM(rxrpc_call_see_discard,		"SEE discard ") \
	EM(rxrpc_call_see_disconnected,		"SEE disconn ") \
	EM(rxrpc_call_see_distribute_error,	"SEE dist-err") \
	EM(rxrpc_call_see_input,		"SEE input   ") \
	EM(rxrpc_call_see_notify_released,	"SEE nfy-rlsd") \
	EM(rxrpc_call_see_recvmsg,		"SEE recvmsg ") \
	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  ") \
+4 −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)
@@ -1383,6 +1386,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *,
					 const struct sockaddr_rxrpc *);
struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
				     struct sockaddr_rxrpc *srx, gfp_t gfp);
void rxrpc_assess_MTU_size(struct rxrpc_local *local, struct rxrpc_peer *peer);
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t,
				    enum rxrpc_peer_trace);
void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer);
+8 −6
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
	tail = b->call_backlog_tail;
	while (CIRC_CNT(head, tail, size) > 0) {
		struct rxrpc_call *call = b->call_backlog[tail];
		rxrpc_see_call(call, rxrpc_call_see_discard);
		rcu_assign_pointer(call->socket, rx);
		if (rx->app_ops &&
		    rx->app_ops->discard_new_call) {
@@ -373,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;
	}
@@ -406,6 +407,7 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,

	spin_unlock(&rx->incoming_lock);
	read_unlock_irq(&local->services_lock);
	rxrpc_assess_MTU_size(local, call->peer);

	if (hlist_unhashed(&call->error_link)) {
		spin_lock_irq(&call->peer->lock);
@@ -420,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);
+12 −16
Original line number Diff line number Diff line
@@ -561,7 +561,7 @@ static void rxrpc_cleanup_rx_buffers(struct rxrpc_call *call)
void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
{
	struct rxrpc_connection *conn = call->conn;
	bool put = false, putu = false;
	bool putu = false;

	_enter("{%d,%d}", call->debug_id, refcount_read(&call->ref));

@@ -573,23 +573,13 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)

	rxrpc_put_call_slot(call);

	/* Make sure we don't get any more notifications */
	/* Note that at this point, the call may still be on or may have been
	 * added back on to the socket receive queue.  recvmsg() must discard
	 * released calls.  The CALL_RELEASED flag should prevent further
	 * notifications.
	 */
	spin_lock_irq(&rx->recvmsg_lock);

	if (!list_empty(&call->recvmsg_link)) {
		_debug("unlinking once-pending call %p { e=%lx f=%lx }",
		       call, call->events, call->flags);
		list_del(&call->recvmsg_link);
		put = true;
	}

	/* list_empty() must return false in rxrpc_notify_socket() */
	call->recvmsg_link.next = NULL;
	call->recvmsg_link.prev = NULL;

	spin_unlock_irq(&rx->recvmsg_lock);
	if (put)
		rxrpc_put_call(call, rxrpc_call_put_unnotify);

	write_lock(&rx->call_lock);

@@ -638,6 +628,12 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
		rxrpc_put_call(call, rxrpc_call_put_release_sock);
	}

	while ((call = list_first_entry_or_null(&rx->recvmsg_q,
						struct rxrpc_call, recvmsg_link))) {
		list_del_init(&call->recvmsg_link);
		rxrpc_put_call(call, rxrpc_call_put_release_recvmsg_q);
	}

	_leave("");
}

+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);
Loading