Re: [PATCH net 3/4] afs: Fix UAF when sending a message

From: Marc Dionne

Date: Fri Jul 03 2026 - 07:18:56 EST


On Thu, Jul 2, 2026 at 11:49 AM David Howells <dhowells@xxxxxxxxxx> wrote:
>
> In afs_make_call(), there's a race with async call reception and
> destruction. If a call is dispatched that doesn't have call->write_iter
> set (used to specify the data content for FS.StoreData), then the first
> rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr.
>
> Once rxrpc_send_data() queues the last request packet, the response could
> come in at any time and cause the call to be completed and put. However,
> afs_make_call() will look at the call again to see it ->write_iter should
> be handled - something it's only allowed to do if it has its own ref on the
> call. Whilst this is the case for synchronous calls, it isn't true for
> async calls such as FS.FetchData.
>
> generic/650 plays games with randomly taking CPUs offline, and can
> interject a significant delay such that the call is deallocated before
> afs_make_call() gets to check call->write_iter - and a UAF ensues (caught
> by KASAN).
>
> BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs]
> Read of size 8 at addr ffff888035e050e8 by task fsstress/1409
>
> Fix this by caching the call->write_iter and call->debug_id so that neither
> variable needs to be accessed after the first send.
>
> Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation")
> Reported-by: Marc Dionne <marc.dionne@xxxxxxxxxxxx>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> cc: Jeffrey Altman <jaltman@xxxxxxxxxxxx>
> cc: Eric Dumazet <edumazet@xxxxxxxxxx>
> cc: "David S. Miller" <davem@xxxxxxxxxxxxx>
> cc: Jakub Kicinski <kuba@xxxxxxxxxx>
> cc: Paolo Abeni <pabeni@xxxxxxxxxx>
> cc: Simon Horman <horms@xxxxxxxxxx>
> cc: linux-afs@xxxxxxxxxxxxxxxxxxx
> cc: stable@xxxxxxxxxx
> ---
> fs/afs/rxrpc.c | 12 ++++++++----
> include/trace/events/afs.h | 6 +++---
> 2 files changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index d82916657a3d..05fcb9b6adde 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
> @@ -347,7 +347,9 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
> struct rxrpc_call *rxcall;
> struct msghdr msg;
> struct kvec iov[1];
> + unsigned int debug_id = call->debug_id;
> size_t len;
> + bool write_iter = call->write_iter;
> s64 tx_total_len;
> int ret;
>
> @@ -410,7 +412,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
> iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
> msg.msg_control = NULL;
> msg.msg_controllen = 0;
> - msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
> + msg.msg_flags = MSG_WAITALL | (write_iter ? MSG_MORE : 0);
>
> ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
> &msg, call->request_size,
> @@ -418,7 +420,9 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
> if (ret < 0)
> goto error_do_abort;
>
> - if (call->write_iter) {
> + /* We lost our ref on call if MSG_MORE was set. */
> +
> + if (write_iter) {
> msg.msg_iter = *call->write_iter;
> msg.msg_flags &= ~MSG_MORE;
> trace_afs_send_data(call, &msg);
> @@ -427,9 +431,9 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
> call->rxcall, &msg,
> iov_iter_count(&msg.msg_iter),
> afs_notify_end_request_tx);
> - *call->write_iter = msg.msg_iter;
> + /* We lost our ref on call. */
>
> - trace_afs_sent_data(call, &msg, ret);
> + trace_afs_sent_data(debug_id, &msg, ret);
> if (ret < 0)
> goto error_do_abort;
> }
> diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
> index 1b3c48b5591d..cf7218efb861 100644
> --- a/include/trace/events/afs.h
> +++ b/include/trace/events/afs.h
> @@ -937,9 +937,9 @@ TRACE_EVENT(afs_send_data,
> );
>
> TRACE_EVENT(afs_sent_data,
> - TP_PROTO(struct afs_call *call, struct msghdr *msg, int ret),
> + TP_PROTO(unsigned int call_debug_id, struct msghdr *msg, int ret),
>
> - TP_ARGS(call, msg, ret),
> + TP_ARGS(call_debug_id, msg, ret),
>
> TP_STRUCT__entry(
> __field(unsigned int, call)
> @@ -949,7 +949,7 @@ TRACE_EVENT(afs_sent_data,
> ),
>
> TP_fast_assign(
> - __entry->call = call->debug_id;
> + __entry->call = call_debug_id;
> __entry->ret = ret;
> __entry->offset = msg->msg_iter.xarray_start + msg->msg_iter.iov_offset;
> __entry->count = iov_iter_count(&msg->msg_iter);
>
>

Reviewed-by: Marc Dionne <marc.dionne@xxxxxxxxxxxx>

Marc