From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D2BCE4334D2 for ; Wed, 22 Jul 2026 17:30:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784741412; cv=none; b=cD67G0KaoVjtVXG7ZsqwvYfw3bDTOjhQPtm9EGar00K8+LuE74FwJQwxM6kxrRWEfxj2EgBjJFce3Ewe/C7rAoMh/2ywdaFfPwY4aymiJnH8jq1feiBS46LnpFjz5NElVuE4ow+nam6nGa+dZFsu0nog7TVrjgA81W+Mpb/0IZw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784741412; c=relaxed/simple; bh=yv+sn5pEiDPv1RutTMfVhndpcD2WucN0nSVQqweun+A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BEbGUskT49afI/aKatMzyAHVznOOCsLIzSLDiqioT07Els6EFYF2Gwu/C+DkX6ZJFsZf3e1N7rgunLun6+QdcStTgH6G2P7GLoGVYbWPqiyZOOm055MLyjRLcXRChKclK5f3aPi8m/zpBXVMKAst8uHDZcPY8ZPfu/IlT84D+vk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Dq73q85d; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Dq73q85d" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B08F11F00A3E; Wed, 22 Jul 2026 17:30:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784741410; bh=NO78uiTrTbmPsqEgJXcTPcHpbm6NU9kGxIMeK9eiXWI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Dq73q85dLZDyp7X3+34MTJRBzw+gLOc9acq7yaW/6bYmCu7AvDM93i1f3i0ZU1nrC zNWtFW4h7tTVktV4xBgMBp1GmbOY+t2aCX2/Ae4TZzOWhZBUgjIk1RMNtTCXoVwi/j 9VN7L0cc22bZBXOISHAXrukn7+b5ztGiHKQOTgIQsFiBXMvZovxqPQ+EWOUKP16bxh j4V3H7GaayHe5ewh23cmvN0OqnpeEKgEoY2BfdcIroaZ055MoyoOesZEOyzM+cVtQL dXU0BvPe4WmKwjgEznenJIQI6cm0EQFR8rwhtETzNfRCQeqLrdr37UU60B7dHhAEoW 9FYrb0DRbT3jQ== From: Sasha Levin To: stable@vger.kernel.org Cc: David Howells , Jeffrey Altman , Marc Dionne , "Junvyyang, Tencent Zhuque Lab" , LePremierHomme , Simon Horman , linux-afs@lists.infradead.org, Jakub Kicinski , Sasha Levin Subject: [PATCH 6.6.y 3/4] rxrpc: Fix notification vs call-release vs recvmsg Date: Wed, 22 Jul 2026 13:30:05 -0400 Message-ID: <20260722173006.2069029-3-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260722173006.2069029-1-sashal@kernel.org> References: <2026072024-devalue-womanly-8b22@gregkh> <20260722173006.2069029-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: David Howells [ Upstream commit 2fd895842d49c23137ae48252dd211e5d6d8a3ed ] When a call is released, rxrpc takes the spinlock and removes it from ->recvmsg_q in an effort to prevent racing recvmsg() invocations from seeing the same call. Now, rxrpc_recvmsg() only takes the spinlock when actually removing a call from the queue; it doesn't, however, take it in the lead up to that when it checks to see if the queue is empty. It *does* hold the socket lock, which prevents a recvmsg/recvmsg race - but this doesn't prevent sendmsg from ending the call because sendmsg() drops the socket lock and relies on the call->user_mutex. Fix this by firstly removing the bit in rxrpc_release_call() that dequeues the released call and, instead, rely on recvmsg() to simply discard released calls (done in a preceding fix). Secondly, rxrpc_notify_socket() is abandoned if the call is already marked as released rather than trying to be clever by setting both pointers in call->recvmsg_link to NULL to trick list_empty(). This isn't perfect and can still race, resulting in a released call on the queue, but recvmsg() will now clean that up. Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") Signed-off-by: David Howells Reviewed-by: Jeffrey Altman cc: Marc Dionne cc: Junvyyang, Tencent Zhuque Lab cc: LePremierHomme cc: Simon Horman cc: linux-afs@lists.infradead.org Link: https://patch.msgid.link/20250717074350.3767366-4-dhowells@redhat.com Signed-off-by: Jakub Kicinski Stable-dep-of: e66f8f32f501 ("rxrpc: Fix socket notification race") Signed-off-by: Sasha Levin --- include/trace/events/rxrpc.h | 3 ++- net/rxrpc/call_object.c | 28 ++++++++++++---------------- net/rxrpc/recvmsg.c | 4 ++++ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index f0560087637ede..8cbec303cb5057 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -271,10 +271,10 @@ EM(rxrpc_call_put_poke, "PUT poke ") \ EM(rxrpc_call_put_recvmsg, "PUT recvmsg ") \ EM(rxrpc_call_put_recvmsg_peek_nowait, "PUT peek-nwt") \ + 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 ") \ @@ -287,6 +287,7 @@ 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_recvmsg_requeue, "SEE recv-rqu") \ EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \ diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 0be153133cb085..b9b48050c22d19 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -550,7 +550,7 @@ static void rxrpc_cleanup_ring(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)); @@ -562,23 +562,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); @@ -627,6 +617,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(""); } diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index dccfa6cae71502..3ff5a9b78ba083 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -29,6 +29,10 @@ void rxrpc_notify_socket(struct rxrpc_call *call) if (!list_empty(&call->recvmsg_link)) return; + if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) { + rxrpc_see_call(call, rxrpc_call_see_notify_released); + return; + } rcu_read_lock(); -- 2.53.0