* [PATCH net v10 00/14] rxrpc: Miscellaneous fixes
@ 2026-09-14 15:13 David Howells
2026-09-14 15:13 ` [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data() David Howells
` (13 more replies)
0 siblings, 14 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel
(This has been split from "rxrpc: Fix CHALLENGE packet handling")
Here's a set of miscellaneous patches, mostly found by sashiko. Note that
a number of the patches have been reworked and reordered after the last
sashiko round[10].
(1) Fix rxrpc_kernel_send_data() to loop around on a short write.
(2) In AFS, fix various callers of rxrpc_kernel_send_data() to abort the
call on send error.
(3) As (2) but for the rxperf test server.
(4) Fix the use of len vs msg->msg_iter.count in rxrpc_send_data().
(5) Fix the update of call->tx_pending in rxrpc_send_data() in paths when
the call lock has been dropped.
(6) Fix the way rxrpc_send_data() and thus rxrpc_sendmsg() handles a
variety of error conditions:
- If it queued the last packet, then no error is returned, only how
much data is returned.
- Otherwise, if one of a number of errors occur that mean that going
on with a call is futile, just return that error. If the call was
terminated, -ESHUTDOWN is returned, no matter the reason, and
recvmsg() will fetch the reason.
- Otherwise, if some bytes were copied in, return that.
- Otherwise, return an error.
(7) Fix error handling in rxrpc_send_data() for if ->secure_packet()
returns an error.
(8) Fix double IRQ enablement in __rxrpc_notify_socket() when called
indirectly from rxrpc_end_rx_phase().
(9) Fix the generation of notifications from rxrpc after call completion.
(10) Fix the rxrpc key parser to check that the enctype is supported in an
RxGK key.
(11) Fix AFS to correctly size the YFS CM token.
(12) Fix AFS to set call->server when making a call, in particular
FS.InlineBulkStatus.
(13) Fix AFS to clear op->call after freeing the call to avoid further
access.
(14) Fix rxrpc_poke_conn() to only queue the conn if the refcount hasn't
yet hit 0.
David
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-fixes
Changes
=======
ver #10)
- Rebased on latest net/main.
- Implemented David Laight's suggestion to loop around inside
rxrpc_kernel_send_data() rather than in its callers.
- Changed rxrpc_kernel_send_data() to return 0 on success, not the amount
buffered.
- Fixes rxperf to not double-abort on ENOMEM.
- Fixed more Sashiko-reported bugs[10]:
- Removed extra blank line.
- Fixed potential infinite loop in rxperf.
- Rearranged the patches to deal with the sendmsg len vs msg_iov.count
potential discrepency first and then deal with the missing locking
around ->tx_pending - and then other rxrpc_send_data() changes.
- Changed rxrpc_send_data() to move the txb variable into the main loop
and otherwise always leave the current txbuf attached to
call->tx_pending.
- Described the return value from rxrpc_send_data() in various situations
in a comment and adjust the code to match, in particular:
- Always using -ESHUTDOWN to indicate that the call has been completed
already and that recvmsg() needs to be used to find the reason.
- Better handling of a sendmsg/sendmsg race where one side fills up the
buffer whilst the other side is waiting.
- Fixed afs and rxperf to check for -ESHUTDOWN and then receive the error
value.
- Fixed rxrpc_send_data() to rewind by the last amount copied rather than
trying to calculate this in case we waited and another thread copied
some data in.
- Added comment on why rxrpc_requeue_call() doesn't check RXRPC_CLOSE
(rxrpc_recvmsg() doesn't check it either).
- Fixed the RxGK key parsing stuff to be conditional on CONFIG_RXGK=y so
that checking the key type doesn't fail to compile.
- Added a key length check when parsing an RxGK key since the enctype
check makes the enctype description available.
- Added a patch to fix afs_wait_for_operation() to clear op->call before
rotation can happen.
- Drop the patch to fix a data race for the moment whilst I consider if
the barriering points brought up by sashiko affectit.
ver #9)
- Rebased on latest net/main.
- Fixed more Sashiko-reported bugs[9]:
- Changed Fixes line for "rxrpc: Fix sendmsg to not return an error if
last packet queued".
- Split the change to call rxrpc_kernel_send_data() in a loop in afs into
its own patch and put that first.
- In AFS, always abort a call if rxrpc_kernel_send_data() gives an error.
- Added a patch to make the rxperf server loop around when sending the
magic cookie.
- Fix rxrpc_send_data() to only return -EPROTO or -EIO only in the case
that no data was copied if TX_NO_MORE or TX_ERROR are set.
- Fix commit message to say call->user_mutex, not call->lock.
- Removed comment on rxrpc_notify_socket() about putting recvmsg_link on
a dummy queue.
- Added a patch to check that the RxGK enctype is supported in an rxrpc
key.
- Move the check for net->fs_cm_token_key being valid from
afs_create_yfs_rxgk_cm_appdata() to its caller and just return okay if
it is NULL (it should've been created during module load).
- Added a patch to fix the calculation of the RxGK CM token in AFS, even
though the code is then deleted by a later patch.
- Made rxrpc_kernel_query_key() pick the first token with a supported
security index, rather than just picking the first token.
- Fix the docs for RXRPC_RESPONSE_APPDATA.
- Split the setting of call->server in afs_make_op_call() out into its
own patch as a separate fix.
- Split the OOB-Challenge fixes out for the moment.
- Imported a patch to fix rxrpc_poke_con() to avoid queuing a dead conn.
- Imported a patch to fix a data race when initialising an RxGK conn.
ver #8)
- Rebased on latest net/main.
- Fixed more Sashiko-reported bugs[8]:
- Fixed the kerneldoc on rxrpc_kernel_send_data() as this returns the
number of bytes buffered on success.
- Fixed rxrpc_send_data() to break out of the loop if either len or
msg_iter's count becomes 0 and to limit the amount per copy to the
msg_iter count also.
- Fixed the docs for rxrpc_kernel_send_data()'s return value.
- In afs_make_call(), remove duplicate error check and make sure the
afs_sent_data tracepoint gets called on the error path.
- In rxrpc_send_data() remove setting of the already-NULL txb and
tx_pending to NULL.
- Added a patch to fix __rxrpc_notify_socket() to save the old IRQ state
when disabling it as the call chain may have it disabled.
- Removed comment on __rxrpc_notify_socket() about putting recvmsg_link
on a dummy queue.
- Moved rxrpc_notify_socket()'s declaration to the right file section in
ar-internal.h.
- Updated the comment on the user_key_payload struct.
- Updated the comment on put_user_key_payload().
- In afs_open_socket(), fixed a missing ref cleanup on error.
- Updated the docs for rxrpc_kernel_begin_call().
- Added docs for RXRPC_RESPONSE_APPDATA cmsg.
- Fixed rxrpc_sendmsg_cmsg() to require that the appdata key have its
description prefixed by "rxrpc-appdata:" to prevent the reading out of
arbitrary keys through a fake filemanager.
- Dropped the use of logon keys for appdata.
- Removed rxrpc_abort_response_sendmsg.
- Removed struct rxrpc_challenge and struct rxgk_challenge.
- Removed the RXRPC_MANAGE_RESPONSE constant and its rxrpc_setsockopt()
stub.
ver #7)
- Rebased on latest net/main.
- Added a patch to change rxrpc_send_data() to use len rather than msg_iter
count to be consistent about the amount to send so as to do the LAST flag
determination correctly.
- Fixed more Sashiko-reported bugs[7]:
- Made the loops in afs_make_call() that call rxrpc_kernel_send_data()
pass the amount left in the iterator rather than an unreducing size.
- Made the second loop in afs_make_call() check to see if
rxrpc_kernel_send_data() returned an error.
- Removed yet more OOB references, two in linux/af_rxrpc.h and one in
rxrpc.rst.
ver #6)
- Rebased on latest net/main.
- Fixed more Sashiko-reported bugs[6]:
- Fixed rxrpc_send_data() to redo the RXRPC_CALL_TX_ERROR and the
RXRPC_CALL_TX_NO_MORE checks after having dropped the call mutex.
- Altered rxrpc_send_data(), as discussed with Paulo Abeni, to rewind as
much as possible on retryable crypto error (e.g. ENOMEM) rather than
rewinding just one byte.
- Fixed afs_make_call() to keep trying rxrpc_kernel_send_data() until the
iterator is drained unless an error occurs.
- Fixed afs_create_yfs_rxgk_cm_appdata() to use kfree_sensitive().
- Removed remaining OOB trace constants.
ver #5)
- Rebased on latest net/main.
- Fixed more Sashiko-reported bugs[5]:
- Removed dropped_lock from rxrpc_do_sendmsg() as it's now always false.
- Fix rxrpc_send_data() to not leak a txbuf from the "maybe_error:" path
by reattaching it to call->tx_pending.
- Increased the size of the rxrpc_abort_reason enum value by removing the
__mode(byte) specifier.
ver #4)
- Rebased on latest net/main.
- Split out non-relevant AFS patches.
- Allow logon-type key as well as user-type key as they're basically the
same thing internally.
- Fixed more Sashiko-reported bugs[4]:
- Fixed rxrpc_send_data() to wind the transmitted data back by 1 byte if
ENOMEM is hit when encrypting the final packet so that the caller can
retry.
- Fixed afs_create_yfs_rxgk_cm_appdata() to add the 4 bytes for the level
into toksize.
- Changed bundle code to include the appdata key as part of the client
connection bundle lookup criteria (don't share connections with
different appdata keys).
- Fixed rxrpc_sendmsg_cmsg() to allow only, not disallow user-type keys
for RXRPC_RESPONSE_APPDATA.
- Reversed the removal of the rejection of MSG_OOB passed to
rxrpc_recvmsg().
- Fixed rxgk_construct_response() to use xdr_object_len() to calculate
the space needed for the appdata and also the space needed for the
token and the authenticator.
- Added a check into rxgk_respond_to_challenge() to make sure the key
type is user or login before we access its payload.
- Remove ->sendmsg_respond_to_challenge() too.
ver #3)
- Rebased on latest net/main.
- Removed two obsoleted patches.
ver #2)
- Split the CHALLENGE/RESPONSE fix into smaller patches.
- Fixed more Sashiko-reported bugs[2][3]:
- Added some more patches to fix some more bugs.
- Get rid of the AFS_SERVER_FL_APPDATA flag and check the pointer to the
appdata instead.
- Rename the appdata key pointer in the AFS_SERVER to reflect this one is
only for the YFS-RxGK security class.
- Use barriers when reading or writing the server appdata key pointer.
- Ignore the appdata for RxNULL, RxKAD and OpenAFS's RxGK for now.
- Check that sendmsg() with RXRPC_RESPONSE_APPDATA is passed a user key.
- Check that the appdata key's payload isn't NULL, for instance if it
gets revoked.
- Add some error path key_put()s in rxrpc_do_sendmsg().
[1] https://sashiko.dev/#/patchset/20260624163819.3017002-1-dhowells%40redhat.com
[2] https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
[3] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
[4] https://sashiko.dev/#/patchset/20260713081022.2186481-1-dhowells%40redhat.com
[5] https://sashiko.dev/#/patchset/20260723100309.530157-1-dhowells%40redhat.com
[6] https://sashiko.dev/#/patchset/20260729160108.2031453-1-dhowells%40redhat.com
[7] https://sashiko.dev/#/patchset/20260804172639.2844491-1-dhowells%40redhat.com
[8] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260812110129.979970-6-dhowells@redhat.com
[9] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
[10] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
David Howells (13):
rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data()
afs: Fix afs to abort the rxrpc call on send error
rxrpc: Fix aborting in rxperf test server
rxrpc: Fix sendmsg length
rxrpc: Fix update of call->tx_pending without holding lock
rxrpc: Fix error handling in rxrpc_send_data()
rxrpc: Fix packet encryption error handling
rxrpc: Fix double IRQ enablement
rxrpc: Fix generation of notifications after call completion
rxrpc: Fix RxGK key parser to check enctype is supported
afs: Fix creation of RxGK CM channel token to have right size
afs: Fix lack of setting call->server when doing FS.InlineBulkStatus
afs: Fix uncleared op->call pointer
Seungwon Bae (1):
rxrpc: fix use-after-free in rxrpc_poke_conn()
Documentation/networking/rxrpc.rst | 10 +-
fs/afs/cm_security.c | 2 +-
fs/afs/fs_operation.c | 1 +
fs/afs/internal.h | 33 ++---
fs/afs/rxrpc.c | 59 +++-----
include/net/af_rxrpc.h | 5 +-
include/trace/events/afs.h | 1 +
include/trace/events/rxrpc.h | 6 +-
net/rxrpc/ar-internal.h | 3 +-
net/rxrpc/call_state.c | 57 +++++++-
net/rxrpc/conn_object.c | 5 +-
net/rxrpc/key.c | 27 +++-
net/rxrpc/recvmsg.c | 44 +++---
net/rxrpc/rxperf.c | 51 ++++---
net/rxrpc/sendmsg.c | 221 ++++++++++++++++++++---------
15 files changed, 342 insertions(+), 183 deletions(-)
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data()
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 21:11 ` David Laight
2026-09-14 15:13 ` [PATCH net v10 02/14] afs: Fix afs to abort the rxrpc call on send error David Howells
` (12 subsequent siblings)
13 siblings, 1 reply; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
David Laight, stable
Fix rxrpc_kernel_send_data() to loop around if it detects a short send.
David Laight suggested doing it here rather than wrapping all the calls in
loops. Further, remove the len argument and use the iterator count instead
and return 0 on success, not the amount copied.
Note this is also a prerequisite for changing the way rxrpc_send_data()
works to return a short send rather than an error if some data was
buffered.
Fixes: 651350d10f93 ("[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Suggested-by: David Laight <david.laight.linux@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
Documentation/networking/rxrpc.rst | 6 ++++--
fs/afs/rxrpc.c | 28 ++++++++++----------------
include/net/af_rxrpc.h | 5 ++---
net/rxrpc/rxperf.c | 11 +++-------
net/rxrpc/sendmsg.c | 32 ++++++++++++++++++++----------
5 files changed, 42 insertions(+), 40 deletions(-)
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 8926dab8e2e6..01ad12fdf305 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -870,7 +870,6 @@ The kernel interface functions are as follows:
int rxrpc_kernel_send_data(struct socket *sock,
struct rxrpc_call *call,
struct msghdr *msg,
- size_t len,
rxrpc_notify_end_tx_t notify_end_rx);
This is used to supply either the request part of a client call or the
@@ -880,13 +879,16 @@ The kernel interface functions are as follows:
MSG_MORE if there will be subsequent data sends for this call.
The msg must not specify a destination address, control data or any flags
- other than MSG_MORE. len is the total amount of data to transmit.
+ other than MSG_MORE.
notify_end_rx can be NULL or it can be used to specify a function to be
called when the call changes state to end the Tx phase. This function is
called with a spinlock held to prevent the last DATA packet from being
transmitted until the function returns.
+ It returns 0 if all the data is queued and a negative error code on
+ failure.
+
(#) Receive data from a call::
int rxrpc_kernel_recv_data(struct socket *sock,
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index d82916657a3d..09d9da92a1be 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -412,8 +412,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
msg.msg_controllen = 0;
msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
- ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
- &msg, call->request_size,
+ ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg,
afs_notify_end_request_tx);
if (ret < 0)
goto error_do_abort;
@@ -425,7 +424,6 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
ret = rxrpc_kernel_send_data(call->net->socket,
call->rxcall, &msg,
- iov_iter_count(&msg.msg_iter),
afs_notify_end_request_tx);
*call->write_iter = msg.msg_iter;
@@ -871,7 +869,7 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
+ switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
afs_notify_end_reply_tx)) {
case 0:
_leave(" [replied]");
@@ -912,21 +910,17 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
+ n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
afs_notify_end_reply_tx);
- if (n >= 0) {
- /* Success */
- _leave(" [replied]");
- return;
- }
-
- if (n == -ENOMEM) {
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
+ if (n < 0) {
+ if (n == -ENOMEM) {
+ _debug("oom");
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, -ENOMEM,
+ afs_abort_oom);
+ }
+ _leave(" [error]");
}
- _leave(" [error]");
}
/*
diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
index 0fb4c41c9bbf..f3980348ed34 100644
--- a/include/net/af_rxrpc.h
+++ b/include/net/af_rxrpc.h
@@ -64,9 +64,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
bool upgrade,
enum rxrpc_interruptibility interruptibility,
unsigned int debug_id);
-int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
- struct msghdr *, size_t,
- rxrpc_notify_end_tx_t);
+int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
+ struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);
int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
struct iov_iter *, size_t *, bool, u32 *, u16 *);
bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index b8df6d22314d..dad04062213f 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -525,12 +525,10 @@ static int rxperf_process_call(struct rxperf_call *call)
iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, len);
msg.msg_flags = MSG_MORE;
n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
- len, rxperf_notify_end_reply_tx);
+ rxperf_notify_end_reply_tx);
if (n < 0)
return n;
- if (n == 0)
- return -EIO;
- reply_len -= n;
+ reply_len -= len;
}
len = sizeof(rxperf_magic_cookie);
@@ -538,11 +536,8 @@ static int rxperf_process_call(struct rxperf_call *call)
iov[0].iov_len = len;
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg, len,
+ n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
rxperf_notify_end_reply_tx);
- if (n >= 0)
- return 0; /* Success */
-
if (n == -ENOMEM)
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
RXGEN_SS_MARSHAL, -ENOMEM,
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005a..34aae8e789a4 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -794,7 +794,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
* @sock: The socket the call is on
* @call: The call to send data through
* @msg: The data to send
- * @len: The amount of data to send
* @notify_end_tx: Notification that the last packet is queued.
*
* Allow a kernel service to send data on a call. The call must be in an state
@@ -805,8 +804,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
* Return: %0 if successful and a negative error code otherwise.
*/
int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
- struct msghdr *msg, size_t len,
- rxrpc_notify_end_tx_t notify_end_tx)
+ struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)
{
bool dropped_lock = false;
int ret;
@@ -816,15 +814,29 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
ASSERTCMP(msg->msg_name, ==, NULL);
ASSERTCMP(msg->msg_control, ==, NULL);
- mutex_lock(&call->user_mutex);
+ for (;;) {
+ mutex_lock(&call->user_mutex);
- ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
- notify_end_tx, &dropped_lock);
- if (ret == -ESHUTDOWN)
- ret = call->error;
+ ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg,
+ msg_data_left(msg),
+ notify_end_tx, &dropped_lock);
+ if (ret == -ESHUTDOWN)
+ ret = call->error;
+
+ if (!dropped_lock)
+ mutex_unlock(&call->user_mutex);
+ if (ret < 0)
+ break;
+ if (msg_data_left(msg) == 0) {
+ ret = 0;
+ break;
+ }
+ if (ret == 0) {
+ ret = -EIO;
+ break;
+ }
+ }
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 02/14] afs: Fix afs to abort the rxrpc call on send error
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
2026-09-14 15:13 ` [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data() David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 03/14] rxrpc: Fix aborting in rxperf test server David Howells
` (11 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
Fix afs_send_empty_reply() and afs_send_simple_reply() to always try to
abort the rxrpc call rather than just aborting on -ENOMEM and otherwise
abandoning it. If the call is already complete due to network failure or a
received abort, this will do nothing.
Also make afs_make_call() always abort on send error; again, it does
nothing if the rxrpc call is already dead.
Fixes: 08e0e7c82eea ("[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC.")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
fs/afs/rxrpc.c | 36 +++++++++++-------------------------
include/trace/events/rxrpc.h | 2 +-
2 files changed, 12 insertions(+), 26 deletions(-)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 09d9da92a1be..2b241716dae7 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -441,10 +441,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
return;
error_do_abort:
- if (ret != -ECONNABORTED)
- rxrpc_kernel_abort_call(call->net->socket, rxcall,
- RX_USER_ABORT, ret,
- afs_abort_send_data_error);
+ rxrpc_kernel_abort_call(call->net->socket, rxcall,
+ RX_USER_ABORT, ret, afs_abort_send_data_error);
if (call->async) {
afs_see_call(call, afs_call_trace_async_abort);
return;
@@ -857,6 +855,7 @@ void afs_send_empty_reply(struct afs_call *call)
{
struct afs_net *net = call->net;
struct msghdr msg;
+ int ret;
_enter("");
@@ -869,22 +868,12 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
- afs_notify_end_reply_tx)) {
- case 0:
- _leave(" [replied]");
- return;
-
- case -ENOMEM:
- _debug("oom");
+ ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
+ afs_notify_end_reply_tx);
+ if (ret < 0)
rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- fallthrough;
- default:
- _leave(" [error]");
- return;
- }
+ RXGEN_SS_MARSHAL, ret,
+ afs_abort_send_error);
}
/*
@@ -913,12 +902,9 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
afs_notify_end_reply_tx);
if (n < 0) {
- if (n == -ENOMEM) {
- _debug("oom");
- rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- }
+ rxrpc_kernel_abort_call(net->socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n,
+ afs_abort_send_error);
_leave(" [error]");
}
}
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de6670..554dfb777b93 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,10 +20,10 @@
/* AFS errors */ \
EM(afs_abort_general_error, "afs-error") \
EM(afs_abort_interrupted, "afs-intr") \
- EM(afs_abort_oom, "afs-oom") \
EM(afs_abort_op_not_supported, "afs-op-notsupp") \
EM(afs_abort_probeuuid_negative, "afs-probeuuid-neg") \
EM(afs_abort_send_data_error, "afs-send-data") \
+ EM(afs_abort_send_error, "afs-send-error") \
EM(afs_abort_unmarshal_error, "afs-unmarshal") \
EM(afs_abort_unsupported_sec_class, "afs-unsup-sec-class") \
/* rxperf errors */ \
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 03/14] rxrpc: Fix aborting in rxperf test server
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
2026-09-14 15:13 ` [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data() David Howells
2026-09-14 15:13 ` [PATCH net v10 02/14] afs: Fix afs to abort the rxrpc call on send error David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 04/14] rxrpc: Fix sendmsg length David Howells
` (10 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel
Fix rxperf_process_call() to always abort if it gets a send error rather
than only aborting on ENOMEM.
Fixes: 75bfdbf2fca3 ("rxrpc: Implement an in-kernel rxperf server for testing purposes")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
---
include/trace/events/rxrpc.h | 2 +-
net/rxrpc/rxperf.c | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 554dfb777b93..56dc9b614071 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -28,8 +28,8 @@
EM(afs_abort_unsupported_sec_class, "afs-unsup-sec-class") \
/* rxperf errors */ \
EM(rxperf_abort_general_error, "rxperf-error") \
- EM(rxperf_abort_oom, "rxperf-oom") \
EM(rxperf_abort_op_not_supported, "rxperf-op-notsupp") \
+ EM(rxperf_abort_send_error, "rxperf-send-error") \
EM(rxperf_abort_unmarshal_error, "rxperf-unmarshal") \
/* RxKAD security errors */ \
EM(rxkad_abort_1_short_check, "rxkad1-short-check") \
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index dad04062213f..7e9a53615309 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -538,10 +538,10 @@ static int rxperf_process_call(struct rxperf_call *call)
msg.msg_flags = 0;
n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
rxperf_notify_end_reply_tx);
- if (n == -ENOMEM)
+ if (n < 0)
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- rxperf_abort_oom);
+ RXGEN_SS_MARSHAL, n,
+ rxperf_abort_send_error);
return n;
}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 04/14] rxrpc: Fix sendmsg length
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (2 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 03/14] rxrpc: Fix aborting in rxperf test server David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 05/14] rxrpc: Fix update of call->tx_pending without holding lock David Howells
` (9 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
Jeffrey Altman
rxrpc_send_data() is given two data lengths (len and msg->msg_iter.count)
and is inconsistent about how it uses them. Fix this by using len in
preference to msg->msg_iter.count. Also limit the amount copied to either
len or msg->msg_iter.count, whichever is smaller.
Note that, currently, all the callers have len and msg->msg_iter.count the
same and so the problem won't occur. This is a prerequisite for another
patch that fixes the handling of encryption errors.
Fixes: 382d7974de31 ("RxRPC: Use iov_iter_count() in rxrpc_send_data() instead of the len argument")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
---
net/rxrpc/sendmsg.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 34aae8e789a4..bbb39835ef9e 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -379,9 +379,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -EMSGSIZE;
if (call->tx_total_len != -1) {
- if (len - copied > call->tx_total_len)
+ if (len > call->tx_total_len)
goto maybe_error;
- if (!more && len - copied != call->tx_total_len)
+ if (!more && len != call->tx_total_len)
goto maybe_error;
}
@@ -405,7 +405,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
* the security header is going to be in the padded
* region (enc blocksize), but the trailer is not.
*/
- remain = more ? INT_MAX : msg_data_left(msg);
+ remain = more ? INT_MAX : len;
txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
if (!txb) {
ret = -ENOMEM;
@@ -416,8 +416,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
_debug("append");
/* append next segment of data to the current buffer */
- if (msg_data_left(msg) > 0) {
- size_t copy = umin(txb->space, msg_data_left(msg));
+ if (len > 0) {
+ size_t copy = min3(txb->space, len, msg_data_left(msg));
_debug("add %zu", copy);
if (!copy_from_iter_full(txb->data + txb->offset,
@@ -428,6 +428,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
txb->len += copy;
txb->offset += copy;
copied += copy;
+ len -= copy;
if (call->tx_total_len != -1)
call->tx_total_len -= copy;
}
@@ -439,8 +440,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
/* add the packet to the send queue if it's now full */
if (!txb->space ||
- (msg_data_left(msg) == 0 && !more)) {
- if (msg_data_left(msg) == 0 && !more)
+ (len == 0 && !more)) {
+ if (len == 0 && !more)
txb->flags |= RXRPC_LAST_PACKET;
ret = call->security->secure_packet(call, txb);
@@ -449,7 +450,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
txb = NULL;
}
- } while (msg_data_left(msg) > 0);
+ } while (len > 0 && msg_data_left(msg) > 0);
success:
ret = copied;
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 05/14] rxrpc: Fix update of call->tx_pending without holding lock
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (3 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 04/14] rxrpc: Fix sendmsg length David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 06/14] rxrpc: Fix error handling in rxrpc_send_data() David Howells
` (8 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
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@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
net/rxrpc/sendmsg.c | 61 ++++++++++++++++++++-------------------------
1 file changed, 27 insertions(+), 34 deletions(-)
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index bbb39835ef9e..b370e440e2fd 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,10 +320,9 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
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;
@@ -341,23 +340,18 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
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 +380,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
}
do {
+ struct rxrpc_txbuf *txb = call->tx_pending;
+
if (!txb) {
size_t remain;
@@ -411,6 +407,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -ENOMEM;
goto maybe_error;
}
+ call->tx_pending = txb;
+ } else {
+ rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
}
_debug("append");
@@ -446,9 +445,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
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 (len > 0 && msg_data_left(msg) > 0);
@@ -457,45 +456,46 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
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;
}
/*
@@ -661,7 +661,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
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 = {
@@ -770,16 +769,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
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);
@@ -807,7 +805,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)
{
- bool dropped_lock = false;
int ret;
_enter("{%d},", call->debug_id);
@@ -819,13 +816,9 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
mutex_lock(&call->user_mutex);
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg,
- msg_data_left(msg),
- notify_end_tx, &dropped_lock);
+ msg_data_left(msg), notify_end_tx);
if (ret == -ESHUTDOWN)
ret = call->error;
-
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
if (ret < 0)
break;
if (msg_data_left(msg) == 0) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 06/14] rxrpc: Fix error handling in rxrpc_send_data()
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (4 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 05/14] rxrpc: Fix update of call->tx_pending without holding lock David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 07/14] rxrpc: Fix packet encryption error handling David Howells
` (7 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
Jeffrey Altman, stable
Fix the error handling in rxrpc_send_data() so that it doesn't return an
error if it has successfully queued the last packet of a call, but the call
has seen to have completed after it did that. Rather, leave it to
recvmsg() to report the completion (which it will do anyway).
The problem with trying to report the error twice is that the caller may
try to clean up the dead call twice.
Further, if we haven't queued the final packet yet, return -ESHUTDOWN if
the call is now marked complete (e.g. it got aborted by the peer) as
there's no point sendmsg() continuing to try to add data to a call if it is
defunct. The application should abort the call and then call recvmsg() to
pick up the reason.
Fixes: 4ba68c519255 ("rxrpc: Return an error to sendmsg if call failed")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
fs/afs/rxrpc.c | 11 +++---
net/rxrpc/rxperf.c | 38 +++++++++++++-------
net/rxrpc/sendmsg.c | 86 +++++++++++++++++++++++++++++++++------------
3 files changed, 95 insertions(+), 40 deletions(-)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 2b241716dae7..4694a6fca9b4 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -448,13 +448,14 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
return;
}
- if (ret == -ECONNABORTED) {
+ if (ret == -ESHUTDOWN) {
len = 0;
iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
- rxrpc_kernel_recv_data(call->net->socket, rxcall,
- &msg.msg_iter, &len, false,
- &call->abort_code, &call->service_id);
- call->responded = true;
+ ret = rxrpc_kernel_recv_data(call->net->socket, rxcall,
+ &msg.msg_iter, &len, false,
+ &call->abort_code, &call->service_id);
+ if (ret == -ECONNABORTED)
+ call->responded = true;
}
call->error = ret;
trace_afs_call_done(call);
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index 7e9a53615309..83016830e696 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -74,7 +74,7 @@ static struct workqueue_struct *rxperf_workqueue;
static void rxperf_deliver_to_call(struct work_struct *work);
static int rxperf_deliver_param_block(struct rxperf_call *call);
static int rxperf_deliver_request(struct rxperf_call *call);
-static int rxperf_process_call(struct rxperf_call *call);
+static void rxperf_process_call(struct rxperf_call *call);
static void rxperf_charge_preallocation(struct work_struct *work);
static DECLARE_WORK(rxperf_charge_preallocation_work,
@@ -293,18 +293,28 @@ static void rxperf_deliver_to_call(struct work_struct *work)
state == RXPERF_CALL_SV_AWAIT_ACK
) {
if (state == RXPERF_CALL_SV_AWAIT_ACK) {
- if (!rxrpc_kernel_check_life(rxperf_socket, call->rxcall))
+ size_t len = 0;
+ iov_iter_kvec(&call->iter, ITER_DEST, NULL, 0, 0);
+ ret = rxrpc_kernel_recv_data(rxperf_socket,
+ call->rxcall, &call->iter,
+ &len, false, &remote_abort,
+ &call->service_id);
+
+ if (ret == -EINPROGRESS || ret == -EAGAIN)
+ return;
+ if (ret < 0 || ret == 1) {
+ if (ret == 1)
+ ret = 0;
goto call_complete;
+ }
return;
}
ret = call->deliver(call);
- if (ret == 0)
- ret = rxperf_process_call(call);
-
switch (ret) {
case 0:
- continue;
+ rxperf_process_call(call);
+ return;
case -EINPROGRESS:
case -EAGAIN:
return;
@@ -508,7 +518,7 @@ static int rxperf_deliver_request(struct rxperf_call *call)
/*
* Process a call for which we've received the request.
*/
-static int rxperf_process_call(struct rxperf_call *call)
+static void rxperf_process_call(struct rxperf_call *call)
{
struct msghdr msg = {};
struct bio_vec bv;
@@ -527,7 +537,7 @@ static int rxperf_process_call(struct rxperf_call *call)
n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
rxperf_notify_end_reply_tx);
if (n < 0)
- return n;
+ goto send_error;
reply_len -= len;
}
@@ -539,10 +549,13 @@ static int rxperf_process_call(struct rxperf_call *call)
n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
rxperf_notify_end_reply_tx);
if (n < 0)
- rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
- RXGEN_SS_MARSHAL, n,
- rxperf_abort_send_error);
- return n;
+ goto send_error;
+ return;
+
+send_error:
+ rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
+ RXGEN_SS_MARSHAL, n,
+ rxperf_abort_send_error);
}
/*
@@ -695,4 +708,3 @@ static void __exit rxperf_exit(void)
rcu_barrier();
}
module_exit(rxperf_exit);
-
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index b370e440e2fd..1012d2d337a5 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -329,13 +329,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
bool more = msg->msg_flags & MSG_MORE;
int ret, copied = 0;
- if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
- trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
- call->cid, call->call_id, call->rx_consumed,
- 0, -EPROTO);
- return -EPROTO;
- }
-
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ret = rxrpc_wait_to_be_connected(call, &timeo);
@@ -352,13 +345,20 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
reload:
+ if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EPROTO);
+ ret = -EPROTO;
+ goto out_unlock;
+ }
+
ret = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN)
- goto maybe_error;
+ goto out_unlock;
state = rxrpc_call_state(call);
- ret = -ESHUTDOWN;
if (state >= RXRPC_CALL_COMPLETE)
- goto maybe_error;
+ goto call_terminated;
ret = -EPROTO;
if (state != RXRPC_CALL_CLIENT_PRE_SEND &&
state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
@@ -368,7 +368,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
call->cid, call->call_id, call->rx_consumed,
0, -EPROTO);
- goto maybe_error;
+ goto out_unlock;
}
ret = -EMSGSIZE;
@@ -448,31 +448,73 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
goto out_unlock;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
call->tx_pending = NULL;
+
+ /* At this point, if that was the last packet, it may
+ * have been transmitted and the reply (client call) or
+ * final ACK (service call) may have been received,
+ * completing the call.
+ */
}
} while (len > 0 && msg_data_left(msg) > 0);
-success:
+ /* Don't check for call completeness here, but leave that to recvmsg or
+ * a further call to sendmsg().
+ */
ret = copied;
- if (rxrpc_call_is_complete(call) &&
- call->error < 0)
- ret = call->error;
out_unlock:
mutex_unlock(&call->user_mutex);
+out:
+
+ /* The return value is a bit complicated as we want to avoid returning
+ * an error if we have queued the final packet. In descending order of
+ * preference:
+ *
+ * (1) If we queue the last packet: the amount copied (which may be
+ * zero). recvmsg() should be used to collect the result.
+ *
+ * (2) If another sendmsg() has already queued the last packet: -EPROTO.
+ *
+ * (3) If the send side of the socket is shut down, -EPIPE.
+ *
+ * (4) If the call is in the wrong state to transmit: -EPROTO.
+ *
+ * (5) If the call has terminated early, likely due to an external
+ * event such as being remotely aborted: -ESHUTDOWN.
+ *
+ * (6) If some data has been copied by this call: the amount copied
+ * (which will be greater than zero).
+ *
+ * (7) Any other error.
+ *
+ * For (2)-(5), there's no point in continuing with the sendmsg(). The
+ * app should abort the call (just in case the error came from
+ * somewhere else) and then use recvmsg() to collect the final result
+ * of the call.
+ */
_leave(" = %d", ret);
return ret;
call_terminated:
- ret = call->error;
+ ret = -ESHUTDOWN;
goto out_unlock;
maybe_error:
- if (copied)
- goto success;
+ if (copied) {
+ if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
+ /* If we've get here, we must have slept waiting for space and .
+ */
+ ret = copied;
+ goto out_unlock;
+ }
+ if (rxrpc_call_is_complete(call))
+ goto call_terminated;
+ ret = copied;
+ }
goto out_unlock;
efault:
ret = -EFAULT;
- goto out_unlock;
+ goto maybe_error;
wait_for_space:
ret = -EAGAIN;
@@ -495,7 +537,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
goto reload;
out_nolock:
_leave(" = %d [intr]", ret);
- return copied ?: ret;
+ if (copied)
+ ret = copied;
+ goto out;
}
/*
@@ -817,8 +861,6 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg,
msg_data_left(msg), notify_end_tx);
- if (ret == -ESHUTDOWN)
- ret = call->error;
if (ret < 0)
break;
if (msg_data_left(msg) == 0) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 07/14] rxrpc: Fix packet encryption error handling
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (5 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 06/14] rxrpc: Fix error handling in rxrpc_send_data() David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 08/14] rxrpc: Fix double IRQ enablement David Howells
` (6 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
In rxrpc_send_data(), if ->secure_packet() returns an error, the code
currently just jumps to out: and returns the error to the app on the
assumption that any error returned by this is automatically fatal for the
call, and may even have corrupted the transmission queue - but leaving it
to userspace to deal with. Nothing stops the application from retrying the
sendmsg(), which will try to encrypt the buffer again, and might succeed
with a corrupt buffer.
Fix rxrpc_send_data() in the following ways:
(1) If -ENOMEM is returned, assume we never got as far as the encryption
and that the operation is retryable. In which case, jump to
maybe_error_rewind and, if we've copied all remaining data into the
last packet, remove some of the bytes from it that we just added so
that we don't tell the caller that we've completed the transmission
phase. The iterator is also correspondingly rewound.
(2) If any other error occurs, set the TX_ERROR flag on the call and
return that error directly; on all subsequent attempts to add data to
the call, return -EIO. The app must then abort the call to get rid of
it (this allows the app to choose the abort code to use).
Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
Closes: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
Documentation/networking/rxrpc.rst | 6 ++-
include/trace/events/rxrpc.h | 1 +
net/rxrpc/ar-internal.h | 1 +
net/rxrpc/sendmsg.c | 63 +++++++++++++++++++++++++-----
4 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 01ad12fdf305..9b7eeae84148 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -878,8 +878,10 @@ The kernel interface functions are as follows:
exclusively to in-kernel virtual addresses. msg.msg_flags may be given
MSG_MORE if there will be subsequent data sends for this call.
- The msg must not specify a destination address, control data or any flags
- other than MSG_MORE.
+ msg must not specify a destination address, control data or any flags
+ other than MSG_MORE. The last-packet flag will only be set on the
+ outgoing packet if MSG_MORE is not set and all the data in the iterator is
+ buffered.
notify_end_rx can be NULL or it can be used to specify a function to be
called when the call changes state to end the Tx phase. This function is
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 56dc9b614071..a5c92592d8f9 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -148,6 +148,7 @@
EM(rxrpc_eproto_wrong_security, "wrong-sec") \
EM(rxrpc_recvmsg_excess_data, "recvmsg-excess") \
EM(rxrpc_recvmsg_short_data, "recvmsg-short") \
+ EM(rxrpc_sendmsg_tx_error, "tx-error") \
E_(rxrpc_sendmsg_late_send, "sendmsg-late")
#define rxrpc_call_poke_traces \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab..a6f830c1621f 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -642,6 +642,7 @@ enum rxrpc_call_flag {
RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */
RXRPC_CALL_TX_ALL_ACKED, /* Last packet has been hard-acked */
RXRPC_CALL_TX_NO_MORE, /* No more data to transmit (MSG_MORE deasserted) */
+ RXRPC_CALL_TX_ERROR, /* Terminal error; call needs abort */
RXRPC_CALL_SEND_PING, /* A ping will need to be sent */
RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 1012d2d337a5..ed7ff32da184 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -325,6 +325,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
{
struct sock *sk = &rx->sk;
enum rxrpc_call_state state;
+ unsigned int rewind_by = 0;
long timeo;
bool more = msg->msg_flags & MSG_MORE;
int ret, copied = 0;
@@ -352,6 +353,13 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -EPROTO;
goto out_unlock;
}
+ if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+ trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+ call->cid, call->call_id, call->rx_consumed,
+ 0, -EIO);
+ ret = -EIO;
+ goto out_unlock;
+ }
ret = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN)
@@ -423,6 +431,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
copy, &msg->msg_iter))
goto efault;
_debug("added");
+ rewind_by = copy;
txb->space -= copy;
txb->len += copy;
txb->offset += copy;
@@ -440,14 +449,29 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
/* add the packet to the send queue if it's now full */
if (!txb->space ||
(len == 0 && !more)) {
+ /* Do any required crypto. If this fails, it could
+ * have corrupted the txbuf content with a partial
+ * encrypt. Assume that ENOMEM is retryable, but
+ * everything else is terminal.
+ */
+ ret = call->security->secure_packet(call, txb);
+ if (ret < 0) {
+ /* Assume that ENOMEM here means that the
+ * encryption hasn't happened yet. The data is
+ * aligned to avoid the need for slow buffering
+ * in the crypto walk.
+ */
+ if (ret == -ENOMEM)
+ goto maybe_error_rewind;
+ set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
+ goto out;
+ }
+
if (len == 0 && !more)
txb->flags |= RXRPC_LAST_PACKET;
-
- ret = call->security->secure_packet(call, txb);
- if (ret < 0)
- goto out_unlock;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
call->tx_pending = NULL;
+ rewind_by = 0;
/* At this point, if that was the last packet, it may
* have been transmitted and the reply (client call) or
@@ -474,19 +498,22 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
*
* (2) If another sendmsg() has already queued the last packet: -EPROTO.
*
- * (3) If the send side of the socket is shut down, -EPIPE.
+ * (3) If an error caused it to be impossible to continue with the
+ * call: -EIO.
*
- * (4) If the call is in the wrong state to transmit: -EPROTO.
+ * (4) If the send side of the socket is shut down, -EPIPE.
*
- * (5) If the call has terminated early, likely due to an external
+ * (5) If the call is in the wrong state to transmit: -EPROTO.
+ *
+ * (6) If the call has terminated early, likely due to an external
* event such as being remotely aborted: -ESHUTDOWN.
*
- * (6) If some data has been copied by this call: the amount copied
+ * (7) If some data has been copied by this call: the amount copied
* (which will be greater than zero).
*
- * (7) Any other error.
+ * (8) Any other error.
*
- * For (2)-(5), there's no point in continuing with the sendmsg(). The
+ * For (2)-(6), there's no point in continuing with the sendmsg(). The
* app should abort the call (just in case the error came from
* somewhere else) and then use recvmsg() to collect the final result
* of the call.
@@ -498,6 +525,22 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -ESHUTDOWN;
goto out_unlock;
+maybe_error_rewind:
+ /* If we got a retryable error after copying all the supplied data into
+ * the last packet, we need to rewind as much as we can so the caller
+ * knows they need to retry the sendmsg.
+ */
+ if (rewind_by && !more && !len) {
+ struct rxrpc_txbuf *txb = call->tx_pending;
+
+ txb->space += rewind_by;
+ txb->len -= rewind_by;
+ txb->offset -= rewind_by;
+ copied -= rewind_by;
+ if (call->tx_total_len != -1)
+ call->tx_total_len += rewind_by;
+ iov_iter_revert(&msg->msg_iter, rewind_by);
+ }
maybe_error:
if (copied) {
if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 08/14] rxrpc: Fix double IRQ enablement
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (6 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 07/14] rxrpc: Fix packet encryption error handling David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 09/14] rxrpc: Fix generation of notifications after call completion David Howells
` (5 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
rxrpc_notify_socket() explicitly disables and then re-enables IRQs, but one
of its call chains (rxrpc_input_queue_data() -> rxrpc_end_rx_phase() ->
rxrpc_call_completed() -> rxrpc_set_call_completion()) has IRQs disabled
around it.
Fix this by making rxrpc_notify_socket() use irqsave spinlocks.
Fixes: a2ea9a907260 ("rxrpc: Use irq-disabling spinlocks between app and I/O thread")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260812110129.979970-6-dhowells@redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
---
net/rxrpc/recvmsg.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f..56fa324d0962 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -24,6 +24,7 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
{
struct rxrpc_sock *rx;
struct sock *sk;
+ unsigned long flags;
_enter("%d", call->debug_id);
@@ -38,16 +39,16 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
sk = &rx->sk;
if (rx && sk->sk_state < RXRPC_CLOSE) {
if (call->notify_rx) {
- spin_lock_irq(&call->notify_lock);
+ spin_lock_irqsave(&call->notify_lock, flags);
call->notify_rx(sk, call, call->user_call_ID);
- spin_unlock_irq(&call->notify_lock);
+ spin_unlock_irqrestore(&call->notify_lock, flags);
} else {
- spin_lock_irq(&rx->recvmsg_lock);
+ spin_lock_irqsave(&rx->recvmsg_lock, flags);
if (list_empty(&call->recvmsg_link)) {
rxrpc_get_call(call, rxrpc_call_get_notify_socket);
list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
}
- spin_unlock_irq(&rx->recvmsg_lock);
+ spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
if (!sock_flag(sk, SOCK_DEAD)) {
_debug("call %ps", sk->sk_data_ready);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 09/14] rxrpc: Fix generation of notifications after call completion
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (7 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 08/14] rxrpc: Fix double IRQ enablement David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 10/14] rxrpc: Fix RxGK key parser to check enctype is supported David Howells
` (4 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
AF_RXRPC may generate a notification to the application after a call has
completed because it generates one notification when
rxrpc_input_split_jumbo() queues the final packet and completes the call
and then generates another when rxrpc_input_split_jumbo() does the
aggregated data receive notification at the end of the function.
This might cause the AFS filesystem to malfunction because it tries to
queue the afs_call for processing an extra time. Most of the time this
happens quickly enough that the second queue_work skips, but sometimes this
means that the call work may happen a second time with implications for
afs_call lifetime management.
Fix this by:
(1) Create a lighter version of rxrpc_notify_socket() that's just used to
requeue a call for rxrpc_recvmsg() without creating another
notification.
(2) Move rxrpc_notify_socket() to call_state.c and rename it to
__rxrpc_notify_socket().
(3) Create a wrapper called rxrpc_notify_socket() that skips the
notification if a call is completed.
(4) Make rxrpc_set_call_completion() call __rxrpc_notify_socket() to avoid
the skip-if-completed check.
Also remove the comment on rxrpc_notify_socket() that said it added the
call to a dummy queue to prevent further notification.
Fixes: 2d1faf7a0ca3 ("rxrpc: Simplify skbuff accounting in receive path")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
---
include/trace/events/rxrpc.h | 1 +
net/rxrpc/ar-internal.h | 2 +-
net/rxrpc/call_state.c | 57 +++++++++++++++++++++++++++++++++++-
net/rxrpc/recvmsg.c | 45 ++++++++++------------------
4 files changed, 74 insertions(+), 31 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index a5c92592d8f9..52f8718cf725 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -343,6 +343,7 @@
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_notify_skipped, "SEE nfy-skip") \
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/ar-internal.h b/net/rxrpc/ar-internal.h
index a6f830c1621f..cb36a709f540 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -1110,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
/*
* call_state.c
*/
+void rxrpc_notify_socket(struct rxrpc_call *call);
bool rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
@@ -1442,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;
/*
* recvmsg.c
*/
-void rxrpc_notify_socket(struct rxrpc_call *);
int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
/*
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebb..52465e88a044 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,61 @@
#include "ar-internal.h"
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ struct rxrpc_sock *rx;
+ struct sock *sk;
+ unsigned long flags;
+
+ if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_released);
+ return;
+ }
+
+ rcu_read_lock();
+
+ rx = rcu_dereference(call->socket);
+ sk = &rx->sk;
+ if (rx && sk->sk_state < RXRPC_CLOSE) {
+ if (call->notify_rx) {
+ spin_lock_irqsave(&call->notify_lock, flags);
+ call->notify_rx(sk, call, call->user_call_ID);
+ spin_unlock_irqrestore(&call->notify_lock, flags);
+ } else {
+ spin_lock_irqsave(&rx->recvmsg_lock, flags);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
+ }
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service if the call isn't
+ * already complete.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+ if (rxrpc_call_is_complete(call)) {
+ rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+ return;
+ }
+
+ __rxrpc_notify_socket(call);
+}
+
/*
* Transition a call to the complete state.
*/
@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
trace_rxrpc_call_complete(call);
wake_up(&call->waitq);
- rxrpc_notify_socket(call);
+ __rxrpc_notify_socket(call);
return true;
}
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index 56fa324d0962..22afc71ea474 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,14 +17,14 @@
#include "ar-internal.h"
/*
- * Post a call for attention by the socket or kernel service. Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up. We ignore RXRPC_CLOSE, allowing
+ * recvmsg() to continue picking up calls that are already on the queue if it
+ * wants to, but no new calls will get added.
*/
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
{
- struct rxrpc_sock *rx;
- struct sock *sk;
- unsigned long flags;
+ struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+ struct sock *sk = &rx->sk;
_enter("%d", call->debug_id);
@@ -33,31 +33,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
return;
}
- rcu_read_lock();
-
- rx = rcu_dereference(call->socket);
- sk = &rx->sk;
- if (rx && sk->sk_state < RXRPC_CLOSE) {
- if (call->notify_rx) {
- spin_lock_irqsave(&call->notify_lock, flags);
- call->notify_rx(sk, call, call->user_call_ID);
- spin_unlock_irqrestore(&call->notify_lock, flags);
- } else {
- spin_lock_irqsave(&rx->recvmsg_lock, flags);
- if (list_empty(&call->recvmsg_link)) {
- rxrpc_get_call(call, rxrpc_call_get_notify_socket);
- list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
- }
- spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+ spin_lock_irq(&rx->recvmsg_lock);
+ if (list_empty(&call->recvmsg_link)) {
+ rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ }
+ spin_unlock_irq(&rx->recvmsg_lock);
- if (!sock_flag(sk, SOCK_DEAD)) {
- _debug("call %ps", sk->sk_data_ready);
- sk->sk_data_ready(sk);
- }
- }
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ _debug("call %ps", sk->sk_data_ready);
+ sk->sk_data_ready(sk);
}
- rcu_read_unlock();
_leave("");
}
@@ -562,7 +549,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (!(flags & MSG_PEEK) &&
!skb_queue_empty(&call->recvmsg_queue))
- rxrpc_notify_socket(call);
+ rxrpc_requeue_call(sock, call);
goto not_yet_complete;
call_failed:
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 10/14] rxrpc: Fix RxGK key parser to check enctype is supported
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (8 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 09/14] rxrpc: Fix generation of notifications after call completion David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 11/14] afs: Fix creation of RxGK CM channel token to have right size David Howells
` (3 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
Fix the parser of RxGK keys supplied by userspace to check that the
specified encryption type is supported and check the key length. Further,
since the checking function isn't necessarily available in CONFIG_RXGK=n,
make the RxGK key wrangling bits conditional.
Fixes: 0ca100ff4df6 ("rxrpc: Add YFS RxGK (GSSAPI) security class")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
net/rxrpc/key.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d89289..dc1b3aa51bf3 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -129,6 +129,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
return 0;
}
+#ifdef CONFIG_RXGK
static u64 xdr_dec64(const __be32 *xdr)
{
return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]);
@@ -166,12 +167,14 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
size_t datalen,
const __be32 *xdr, unsigned int toklen)
{
+ const struct krb5_enctype *enc;
struct rxrpc_key_token *token, **pptoken;
time64_t expiry;
size_t plen;
const __be32 *ticket, *key;
s64 tmp;
size_t raw_keylen, raw_tktlen, keylen, tktlen;
+ int ret = -EKEYREJECTED;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -229,6 +232,17 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->key.data = token->rxgk->_key;
token->rxgk->ticket.len = raw_tktlen;
+ /* Check the enctype is supported. */
+ enc = crypto_krb5_find_enctype(token->rxgk->enctype);
+ if (!enc) {
+ ret = -ENOPKG;
+ goto reject_token;
+ }
+ if (raw_keylen != enc->key_len) {
+ ret = -EKEYREJECTED;
+ goto reject_token;
+ }
+
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
if (expiry < 0)
@@ -280,12 +294,13 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
kfree(token->rxgk);
kfree(token);
reject:
- return -EKEYREJECTED;
+ return ret;
expired:
kfree(token->rxgk);
kfree(token);
return -EKEYEXPIRED;
}
+#endif /* CONFIG_RXGK */
/*
* attempt to parse the data as the XDR format
@@ -386,9 +401,11 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
case RXRPC_SECURITY_RXKAD:
ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
break;
+#ifdef CONFIG_RXGK
case RXRPC_SECURITY_YFS_RXGK:
ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
break;
+#endif
default:
ret2 = -EPROTONOSUPPORT;
break;
@@ -556,10 +573,12 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
case RXRPC_SECURITY_RXKAD:
kfree(token->kad);
break;
+#ifdef CONFIG_RXGK
case RXRPC_SECURITY_YFS_RXGK:
kfree(token->rxgk->ticket.data);
kfree(token->rxgk);
break;
+#endif
default:
pr_err("Unknown token type %x on rxrpc key\n",
token->security_index);
@@ -603,9 +622,11 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
case RXRPC_SECURITY_RXKAD:
seq_puts(m, "ka");
break;
+#ifdef CONFIG_RXGK
case RXRPC_SECURITY_YFS_RXGK:
seq_puts(m, "ygk");
break;
+#endif
default: /* we have a ticket we can't encode */
seq_printf(m, "%u", token->security_index);
break;
@@ -770,12 +791,14 @@ static long rxrpc_read(const struct key *key,
toksize += RND(token->kad->ticket_len);
break;
+#ifdef CONFIG_RXGK
case RXRPC_SECURITY_YFS_RXGK:
toksize += 6 * 8 + 2 * 4;
if (!token->no_leak_key)
toksize += RND(token->rxgk->key.len);
toksize += RND(token->rxgk->ticket.len);
break;
+#endif
default: /* we have a ticket we can't encode */
pr_err("Unsupported key token type (%u)\n",
@@ -856,6 +879,7 @@ static long rxrpc_read(const struct key *key,
ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
break;
+#ifdef CONFIG_RXGK
case RXRPC_SECURITY_YFS_RXGK:
ENCODE64(token->rxgk->begintime);
ENCODE64(token->rxgk->endtime);
@@ -869,6 +893,7 @@ static long rxrpc_read(const struct key *key,
ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data);
ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data);
break;
+#endif
default:
pr_err("Unsupported key token type (%u)\n",
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 11/14] afs: Fix creation of RxGK CM channel token to have right size
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (9 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 10/14] rxrpc: Fix RxGK key parser to check enctype is supported David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 12/14] afs: Fix lack of setting call->server when doing FS.InlineBulkStatus David Howells
` (2 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
Fix afs_create_yfs_cm_token() so that it calculates the token size
correctly, remembering to add in the 4 bytes of the level.
As it happens, this bug has no effect because crypto_krb5_how_much_buffer()
rounds encsize up to a multiple of the crypto block size (16 or 32) before
adding on the checksum size - and so there's actually 8 bytes of unused
space allocated within the blob-to-be-encrypted and 4 bytes of that gets
used.
Fixes: d98c317fd9aa ("afs: Use rxgk RESPONSE to pass token for callback channel")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
fs/afs/cm_security.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4..5eeeef761cf3 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
* struct RXGK_AuthName identities<>;
* };
*/
- toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+ toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
offset = 0;
encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 12/14] afs: Fix lack of setting call->server when doing FS.InlineBulkStatus
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (10 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 11/14] afs: Fix creation of RxGK CM channel token to have right size David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 13/14] afs: Fix uncleared op->call pointer David Howells
2026-09-14 15:13 ` [PATCH net v10 14/14] rxrpc: fix use-after-free in rxrpc_poke_conn() David Howells
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
Jeffrey Altman, Jarkko Sakkinen, keyrings, stable
Fix afs_make_op_call to set call->server. This will prevent
afs_done_fs_inline_bulk_status() from oopsing if the server does not
support the FS.InlineBulkStatus RPC due to call->server not being set.
Note that this requires afs_make_op_call() to be moved so that it can use
afs_use_server(); the server is un-used by afs_free_call().
Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: Jarkko Sakkinen <jarkko@kernel.org>
cc: linux-afs@lists.infradead.org
cc: keyrings@vger.kernel.org
cc: stable@kernel.org
---
fs/afs/internal.h | 33 +++++++++++++++++----------------
include/trace/events/afs.h | 1 +
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 290873bac89b..65a0866cd8b8 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1416,22 +1416,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
__builtin_return_address(0));
}
-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
- gfp_t gfp)
-{
- struct afs_addr_list *alist = op->estate->addresses;
-
- op->call = afs_get_call(call, afs_call_trace_get);
- op->type = call->type;
- call->op = op;
- call->key = op->key;
- call->intr = !(op->flags & AFS_OPERATION_UNINTR);
- call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
- call->service_id = op->server->service_id;
- afs_make_call(call, gfp);
- afs_put_call(call);
-}
-
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
{
call->iov_len = size;
@@ -1763,6 +1747,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
return &vnode->netfs.inode;
}
+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
+ gfp_t gfp)
+{
+ struct afs_addr_list *alist = op->estate->addresses;
+
+ op->call = afs_get_call(call, afs_call_trace_get);
+ op->type = call->type;
+ call->op = op;
+ call->server = afs_use_server(op->server, false, afs_server_trace_use_call);
+ call->key = op->key;
+ call->intr = !(op->flags & AFS_OPERATION_UNINTR);
+ call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
+ call->service_id = op->server->service_id;
+ afs_make_call(call, gfp);
+ afs_put_call(call);
+}
+
/*
* Note that a dentry got changed. We need to set d_fsdata to the data version
* number derived from the result of the operation. It doesn't matter if
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591d..04b0bb682b81 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -148,6 +148,7 @@ enum yfs_cm_operation {
EM(afs_server_trace_unuse_slist_isort, "UNU isort") \
EM(afs_server_trace_update, "UPDATE ") \
EM(afs_server_trace_use_by_uuid, "USE uuid ") \
+ EM(afs_server_trace_use_call, "USE call ") \
EM(afs_server_trace_use_cm_call, "USE cm-cl") \
EM(afs_server_trace_use_get_caps, "USE gcaps") \
EM(afs_server_trace_use_give_up_cb, "USE gvupc") \
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 13/14] afs: Fix uncleared op->call pointer
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (11 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 12/14] afs: Fix lack of setting call->server when doing FS.InlineBulkStatus David Howells
@ 2026-09-14 15:13 ` David Howells
2026-09-14 15:13 ` [PATCH net v10 14/14] rxrpc: fix use-after-free in rxrpc_poke_conn() David Howells
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel
Fix uncleared op->call pointer in afs_wait_for_operation() lest server
rotation occur and try to reuse the call. Note that afs_read_receive()
already does this. Note that this was spotted by AI code inspection rather
than by hitting an issue.
Fixes: 6f2ff7e89bd0 ("afs: Don't put afs_call in afs_wait_for_call_to_complete()")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260907113743.1453210-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
---
fs/afs/fs_operation.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c
index 20801b29521d..94fa65548d71 100644
--- a/fs/afs/fs_operation.c
+++ b/fs/afs/fs_operation.c
@@ -297,6 +297,7 @@ void afs_wait_for_operation(struct afs_operation *op)
op->call_error = op->call->error;
op->call_responded = op->call->responded;
afs_put_call(op->call);
+ op->call = NULL;
}
}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH net v10 14/14] rxrpc: fix use-after-free in rxrpc_poke_conn()
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
` (12 preceding siblings ...)
2026-09-14 15:13 ` [PATCH net v10 13/14] afs: Fix uncleared op->call pointer David Howells
@ 2026-09-14 15:13 ` David Howells
13 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-09-14 15:13 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
Seungwon Bae, stable
From: Seungwon Bae <qotmddnjs@ajou.ac.kr>
rxrpc_poke_conn() takes a reference on the connection with no liveness
check, unlike its sibling rxrpc_queue_conn() which gates on
atomic_read(&conn->active) >= 0. The per-connection timer is armed with
no reference held for it, and rxrpc_put_connection() cancels it with a
non-synchronous timer_delete() only after the refcount reaches 0.
refcount_t saturates rather than resurrecting, so the connection can be
kfree()d while still linked in local->conn_attend_q (nothing in teardown
unlinks attend_link). The rxrpc I/O thread then performs a UAF write
(list_del_init) plus UAF reads and indirect calls through conn->security.
Reproduced on a KASAN + PREEMPT kernel: 56 "refcount_t: addition on 0"
saturations at load, escalating to
BUG: KASAN: slab-use-after-free in rxrpc_io_thread Write of size 8
AF_RXRPC socket creation (rxrpc_create) has no capability check, so this
is reachable by an unprivileged user.
Guard rxrpc_poke_conn() with the same liveness/refcount check the sibling
rxrpc_queue_conn() uses before taking the poke reference, so a connection
past its last-active point is not poked/requeued after teardown began.
Verified before/after on KASAN+PREEMPT at equal timer volume: 56
saturations + 15 KASAN reports unpatched vs 0 and 0 patched.
Fixes: f2cce89a074e ("rxrpc: Implement a mechanism to send an event notification to a connection")
Signed-off-by: Seungwon Bae <qotmddnjs@ajou.ac.kr>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
---
net/rxrpc/conn_object.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f8..1be50e0c9cee 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
spin_lock_irq(&local->lock);
busy = !list_empty(&conn->attend_link);
if (!busy) {
- rxrpc_get_connection(conn, why);
+ if (!rxrpc_get_connection_maybe(conn, why)) {
+ spin_unlock_irq(&local->lock);
+ return;
+ }
list_add_tail(&conn->attend_link, &local->conn_attend_q);
}
spin_unlock_irq(&local->lock);
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data()
2026-09-14 15:13 ` [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data() David Howells
@ 2026-09-14 21:11 ` David Laight
0 siblings, 0 replies; 16+ messages in thread
From: David Laight @ 2026-09-14 21:11 UTC (permalink / raw)
To: David Howells
Cc: netdev, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
stable
On Mon, 14 Sep 2026 16:13:25 +0100
David Howells <dhowells@redhat.com> wrote:
> Fix rxrpc_kernel_send_data() to loop around if it detects a short send.
> David Laight suggested doing it here rather than wrapping all the calls in
> loops. Further, remove the len argument and use the iterator count instead
> and return 0 on success, not the amount copied.
>
> Note this is also a prerequisite for changing the way rxrpc_send_data()
> works to return a short send rather than an error if some data was
> buffered.
>
> Fixes: 651350d10f93 ("[AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use")
> Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
> Suggested-by: David Laight <david.laight.linux@gmail.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: Eric Dumazet <edumazet@google.com>
> cc: "David S. Miller" <davem@davemloft.net>
> cc: Jakub Kicinski <kuba@kernel.org>
> cc: Paolo Abeni <pabeni@redhat.com>
> cc: Simon Horman <horms@kernel.org>
> cc: linux-afs@lists.infradead.org
> cc: stable@vger.kernel.org
> ---
> Documentation/networking/rxrpc.rst | 6 ++++--
> fs/afs/rxrpc.c | 28 ++++++++++----------------
> include/net/af_rxrpc.h | 5 ++---
> net/rxrpc/rxperf.c | 11 +++-------
> net/rxrpc/sendmsg.c | 32 ++++++++++++++++++++----------
> 5 files changed, 42 insertions(+), 40 deletions(-)
>
...
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index d82916657a3d..09d9da92a1be 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
...
> @@ -912,21 +910,17 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
> msg.msg_controllen = 0;
> msg.msg_flags = 0;
>
> - n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
> + n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
> afs_notify_end_reply_tx);
Probably needs s/n/ret/
...
> diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
> index 0fb4c41c9bbf..f3980348ed34 100644
> --- a/include/net/af_rxrpc.h
> +++ b/include/net/af_rxrpc.h
> @@ -64,9 +64,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
> bool upgrade,
> enum rxrpc_interruptibility interruptibility,
> unsigned int debug_id);
> -int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
> - struct msghdr *, size_t,
> - rxrpc_notify_end_tx_t);
> +int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
> + struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);
> int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
> struct iov_iter *, size_t *, bool, u32 *, u16 *);
> bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
> diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
> index b8df6d22314d..dad04062213f 100644
> --- a/net/rxrpc/rxperf.c
> +++ b/net/rxrpc/rxperf.c
> @@ -525,12 +525,10 @@ static int rxperf_process_call(struct rxperf_call *call)
> iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, len);
> msg.msg_flags = MSG_MORE;
> n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
> - len, rxperf_notify_end_reply_tx);
> + rxperf_notify_end_reply_tx);
Ditto
David
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-09-14 21:11 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14 15:13 [PATCH net v10 00/14] rxrpc: Miscellaneous fixes David Howells
2026-09-14 15:13 ` [PATCH net v10 01/14] rxrpc: Fix lack of short-send handling in rxrpc_kernel_send_data() David Howells
2026-09-14 21:11 ` David Laight
2026-09-14 15:13 ` [PATCH net v10 02/14] afs: Fix afs to abort the rxrpc call on send error David Howells
2026-09-14 15:13 ` [PATCH net v10 03/14] rxrpc: Fix aborting in rxperf test server David Howells
2026-09-14 15:13 ` [PATCH net v10 04/14] rxrpc: Fix sendmsg length David Howells
2026-09-14 15:13 ` [PATCH net v10 05/14] rxrpc: Fix update of call->tx_pending without holding lock David Howells
2026-09-14 15:13 ` [PATCH net v10 06/14] rxrpc: Fix error handling in rxrpc_send_data() David Howells
2026-09-14 15:13 ` [PATCH net v10 07/14] rxrpc: Fix packet encryption error handling David Howells
2026-09-14 15:13 ` [PATCH net v10 08/14] rxrpc: Fix double IRQ enablement David Howells
2026-09-14 15:13 ` [PATCH net v10 09/14] rxrpc: Fix generation of notifications after call completion David Howells
2026-09-14 15:13 ` [PATCH net v10 10/14] rxrpc: Fix RxGK key parser to check enctype is supported David Howells
2026-09-14 15:13 ` [PATCH net v10 11/14] afs: Fix creation of RxGK CM channel token to have right size David Howells
2026-09-14 15:13 ` [PATCH net v10 12/14] afs: Fix lack of setting call->server when doing FS.InlineBulkStatus David Howells
2026-09-14 15:13 ` [PATCH net v10 13/14] afs: Fix uncleared op->call pointer David Howells
2026-09-14 15:13 ` [PATCH net v10 14/14] rxrpc: fix use-after-free in rxrpc_poke_conn() David Howells
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®