Patch "rxrpc: Fix update of call->tx_pending without holding lock" has been added to the 7.3-stable tree
gregkh at linuxfoundation.org
gregkh at linuxfoundation.org
Wed Nov 4 11:16:07 PST 2026
This is a note to let you know that I've just added the patch titled
rxrpc: Fix update of call->tx_pending without holding lock
to the 7.3-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
rxrpc-fix-update-of-call-tx_pending-without-holding-lock.patch
and it can be found in the queue-7.3 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <stable at vger.kernel.org> know about it.
>From 7801c42c3bb737cfb06194a383873fcad8daacf5 Mon Sep 17 00:00:00 2001
From: David Howells <dhowells at redhat.com>
Date: Tue, 6 Oct 2026 14:29:55 +0100
Subject: rxrpc: Fix update of call->tx_pending without holding lock
From: David Howells <dhowells at redhat.com>
commit 7801c42c3bb737cfb06194a383873fcad8daacf5 upstream.
Currently, rxrpc_send_data() updates call->tx_pending just before it
returns - but it won't be holding the call->user_mutex when it does this if
a wait was interrupted by a signal. This would allow a parallel sendmsg()
to race.
Further, both the callers of rxrpc_send_data() call it with the lock held,
and then it returns an indication through the parameter list to say whether
it has dropped the lock or not - after which the callers both just drop the
lock if it's still held.
Fix this by:
(1) Moving the release of call->user_mutex down into rxrpc_send_data() and
get rid of the indicator parameter. This makes it easier to see where
the lock is held.
(2) After waiting, if the attempt to reacquire the mutex is interrupted,
just return directly there rather than going to out_unlock
(3) Restricting the txb variable to inside the buffering loop and leaving
->tx_pending set until we've queued the buffer.
Note that there's a slight change in behaviour in that wait_for_space
failure now doesn't check for completion because it doesn't hold the call
user_mutex. The caller, however, should re-issue the send and pick up any
error at a second attempt.
Fixes: b0f571ecd794 ("rxrpc: Fix locking in rxrpc's sendmsg")
Closes: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells at redhat.com>
cc: Marc Dionne <marc.dionne at auristor.com>
cc: Eric Dumazet <edumazet at google.com>
cc: "David S. Miller" <davem at davemloft.net>
cc: Jakub Kicinski <kuba at kernel.org>
cc: Paolo Abeni <pabeni at redhat.com>
cc: Simon Horman <horms at kernel.org>
cc: linux-afs at lists.infradead.org
cc: stable at vger.kernel.org
Link: https://patch.msgid.link/20261006133011.531806-4-dhowells@redhat.com
Signed-off-by: Paolo Abeni <pabeni at redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
net/rxrpc/sendmsg.c | 63 +++++++++++++++++++++++-----------------------------
1 file changed, 29 insertions(+), 34 deletions(-)
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,10 +320,9 @@ static int rxrpc_alloc_txqueue(struct so
static int rxrpc_send_data(struct rxrpc_sock *rx,
struct rxrpc_call *call,
struct msghdr *msg, size_t len,
- rxrpc_notify_end_tx_t notify_end_tx,
- bool *_dropped_lock)
+ rxrpc_notify_end_tx_t notify_end_tx)
+ __releases(&call->user_mutex)
{
- struct rxrpc_txbuf *txb;
struct sock *sk = &rx->sk;
enum rxrpc_call_state state;
long timeo;
@@ -334,30 +333,26 @@ static int rxrpc_send_data(struct rxrpc_
trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
call->cid, call->call_id, call->rx_consumed,
0, -EPROTO);
- return -EPROTO;
+ ret = -EPROTO;
+ goto out_unlock;
}
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ret = rxrpc_wait_to_be_connected(call, &timeo);
if (ret < 0)
- return ret;
+ goto out_unlock;
if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
ret = rxrpc_init_client_conn_security(call->conn);
if (ret < 0)
- return ret;
+ goto out_unlock;
}
/* this should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
reload:
- txb = call->tx_pending;
- call->tx_pending = NULL;
- if (txb)
- rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
-
ret = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN)
goto maybe_error;
@@ -386,6 +381,8 @@ reload:
}
do {
+ struct rxrpc_txbuf *txb = call->tx_pending;
+
if (!txb) {
size_t remain;
@@ -411,6 +408,9 @@ reload:
ret = -ENOMEM;
goto maybe_error;
}
+ call->tx_pending = txb;
+ } else {
+ rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
}
_debug("append");
@@ -445,9 +445,9 @@ reload:
ret = call->security->secure_packet(call, txb);
if (ret < 0)
- goto out;
+ goto out_unlock;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
- txb = NULL;
+ call->tx_pending = NULL;
}
} while (msg_data_left(msg) > 0);
@@ -456,45 +456,46 @@ success:
if (rxrpc_call_is_complete(call) &&
call->error < 0)
ret = call->error;
-out:
- call->tx_pending = txb;
+out_unlock:
+ mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
call_terminated:
- rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
- _leave(" = %d", call->error);
- return call->error;
+ ret = call->error;
+ goto out_unlock;
maybe_error:
if (copied)
goto success;
- goto out;
+ goto out_unlock;
efault:
ret = -EFAULT;
- goto out;
+ goto out_unlock;
wait_for_space:
ret = -EAGAIN;
if (msg->msg_flags & MSG_DONTWAIT)
goto maybe_error;
mutex_unlock(&call->user_mutex);
- *_dropped_lock = true;
+
ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
msg->msg_flags & MSG_WAITALL);
if (ret < 0)
- goto maybe_error;
+ goto out_nolock;
if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
ret = sock_intr_errno(timeo);
- goto maybe_error;
+ goto out_nolock;
}
} else {
mutex_lock(&call->user_mutex);
}
- *_dropped_lock = false;
goto reload;
+out_nolock:
+ _leave(" = %d [intr]", ret);
+ return copied ?: ret;
}
/*
@@ -660,7 +661,6 @@ rxrpc_new_client_call_for_sendmsg(struct
int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
{
struct rxrpc_call *call;
- bool dropped_lock = false;
int ret;
struct rxrpc_send_params p = {
@@ -769,16 +769,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *
ret = 0;
break;
case RXRPC_CMD_SEND_DATA:
- ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
- break;
+ ret = rxrpc_send_data(rx, call, msg, len, NULL);
+ goto error_put;
default:
ret = -EINVAL;
break;
}
out_put_unlock:
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
+ mutex_unlock(&call->user_mutex);
error_put:
rxrpc_put_call(call, rxrpc_call_put_sendmsg);
_leave(" = %d", ret);
@@ -808,7 +807,6 @@ int rxrpc_kernel_send_data(struct socket
struct msghdr *msg, size_t len,
rxrpc_notify_end_tx_t notify_end_tx)
{
- bool dropped_lock = false;
int ret;
_enter("{%d},", call->debug_id);
@@ -819,12 +817,9 @@ int rxrpc_kernel_send_data(struct socket
mutex_lock(&call->user_mutex);
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
- notify_end_tx, &dropped_lock);
+ notify_end_tx);
if (ret == -ESHUTDOWN)
ret = call->error;
-
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
}
Patches currently in stable-queue which might be from dhowells at redhat.com are
queue-7.3/smb-client-reject-short-or-out-of-range-find-response-parameters.patch
queue-7.3/smb-client-require-stable-pages-for-smb-compression.patch
queue-7.3/rxrpc-fix-double-irq-enablement.patch
queue-7.3/rxrpc-fix-return-in-rxrpc_recvmsg_data-for-service-calls.patch
queue-7.3/smb-client-fix-use-after-free-infoleak-via-the-readdir-resume-name.patch
queue-7.3/smb-client-reclaim-credits-for-decrypted-reads-with-no-matching-mid.patch
queue-7.3/smb-client-reject-find-data-areas-that-run-past-the-received-response.patch
queue-7.3/smb-client-fix-oob-last_entry-pointer-from-unbounded-lastnameoffset.patch
queue-7.3/smb-client-do-not-pass-a-null-buf-to-is_oplock_break.patch
queue-7.3/smb-client-don-t-resurrect-an-exiting-tcon-from-cached-dir-workers.patch
queue-7.3/afs-fix-afs-to-abort-the-rxrpc-call-on-send-error.patch
queue-7.3/smb-client-fix-oob-read-in-the-smb_find_file_unix-name-scan.patch
queue-7.3/rxrpc-fix-update-of-call-tx_pending-without-holding-lock.patch
queue-7.3/rxrpc-fix-lack-of-short-send-handling-in-rxrpc_kernel_send_data.patch
queue-7.3/smb-client-fix-use-after-free-in-cifs_ses_add_channel.patch
queue-7.3/smb-client-fix-oob-read-of-the-resume-name-sent-in-trans2_find_next2.patch
More information about the linux-afs
mailing list