[PATCH net v3 09/14] afs: Fix UAF in afs_make_call()
From: David Howells <dhowells@redhat.com>
Date: 2026-07-13 08:11:17
Also in:
lkml
Subsystem:
afs filesystem, filesystems (vfs and infrastructure), the rest, tracing · Maintainers:
David Howells, Marc Dionne, Alexander Viro, Christian Brauner, Linus Torvalds, Steven Rostedt, Masami Hiramatsu
There's a potential UAF in afs_make_call() in the event that an
asynchronous call is being sent, but the call fails in some way (e.g. it
gets aborted from the server). The problem is that afs_make_call() tries
to abort a call if the rxrpc send fails, but the asynchronous notification
from rxrpc may have caused the afs_call to be torn down.
Fix this making afs_make_op_call() give the op->call its own ref rather
than transferring the caller's ref to it and then dropping the ref when
afs_make_call() returns.
This also means that the afs_make_call() func never loses its ref on the
call now.
Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept")
Link: 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: Jeffrey Altman <redacted>
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
---
fs/afs/internal.h | 3 ++-
fs/afs/rxrpc.c | 3 ---
include/trace/events/afs.h | 2 ++
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 4901d0acbe14..645fe2f12dc5 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h@@ -1417,7 +1417,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c { struct afs_addr_list *alist = op->estate->addresses; - op->call = call; + op->call = afs_get_call(call, afs_call_trace_get_op_call); op->type = call->type; call->op = op; call->key = op->key;
@@ -1425,6 +1425,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c 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, afs_call_trace_put_made_call); } static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index a1b9ced4e0f4..6dc6fd853832 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c@@ -382,8 +382,6 @@ void afs_make_call(struct afs_call *call, gfp_t gfp) if (ret < 0) goto error_do_abort; - /* We lost our ref on call if MSG_MORE was not set and ret >= 0. */ - if (write_iter) { msg.msg_iter = *call->write_iter; msg.msg_flags &= ~MSG_MORE;
@@ -393,7 +391,6 @@ 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); - /* We lost our ref on call if ret >= 0. */ trace_afs_sent_data(debug_id, &msg, ret); if (ret < 0)
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index df397c11df85..a1963e21f034 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h@@ -122,8 +122,10 @@ enum yfs_cm_operation { #define afs_call_traces \ EM(afs_call_trace_alloc, "ALLOC ") \ EM(afs_call_trace_free, "FREE ") \ + EM(afs_call_trace_get_op_call, "GET op ") \ EM(afs_call_trace_get_make_async_call, "GET a-make ") \ EM(afs_call_trace_put_async_complete, "PUT a-cmpl ") \ + EM(afs_call_trace_put_made_call, "PUT made ") \ EM(afs_call_trace_put_discard_prealloc, "PUT dis-pre") \ EM(afs_call_trace_put_get_capabilities, "PUT get-cap") \ EM(afs_call_trace_put_giveupcallbacks, "PUT gvup-cb") \