Skip to content

Commit e0416e7

Browse files
dhowellsdavem330
authored andcommitted
rxrpc: Fix potential race in error handling in afs_make_call()
If the rxrpc call set up by afs_make_call() receives an error whilst it is transmitting the request, there's the possibility that it may get to the point the rxrpc call is ended (after the error_kill_call label) just as the call is queued for async processing. This could manifest itself as call->rxcall being seen as NULL in afs_deliver_to_call() when it tries to lock the call. Fix this by splitting rxrpc_kernel_end_call() into a function to shut down an rxrpc call and a function to release the caller's reference and calling the latter only when we get to afs_put_call(). Reported-by: Jeffrey Altman <jaltman@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: kafs-testing+fedora36_64checkkafs-build-306@auristor.com cc: Marc Dionne <marc.dionne@auristor.com> cc: "David S. Miller" <davem@davemloft.net> cc: Eric Dumazet <edumazet@google.com> cc: Jakub Kicinski <kuba@kernel.org> cc: Paolo Abeni <pabeni@redhat.com> cc: linux-afs@lists.infradead.org cc: netdev@vger.kernel.org Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 92ce288 commit e0416e7

5 files changed

Lines changed: 45 additions & 24 deletions

File tree

Documentation/networking/rxrpc.rst

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -848,14 +848,21 @@ The kernel interface functions are as follows:
848848
returned. The caller now holds a reference on this and it must be
849849
properly ended.
850850

851-
(#) End a client call::
851+
(#) Shut down a client call::
852852

853-
void rxrpc_kernel_end_call(struct socket *sock,
853+
void rxrpc_kernel_shutdown_call(struct socket *sock,
854+
struct rxrpc_call *call);
855+
856+
This is used to shut down a previously begun call. The user_call_ID is
857+
expunged from AF_RXRPC's knowledge and will not be seen again in
858+
association with the specified call.
859+
860+
(#) Release the ref on a client call::
861+
862+
void rxrpc_kernel_put_call(struct socket *sock,
854863
struct rxrpc_call *call);
855864
856-
This is used to end a previously begun call. The user_call_ID is expunged
857-
from AF_RXRPC's knowledge and will not be seen again in association with
858-
the specified call.
865+
This is used to release the caller's ref on an rxrpc call.
859866

860867
(#) Send data through a call::
861868

fs/afs/rxrpc.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ void afs_put_call(struct afs_call *call)
179179
ASSERT(call->type->name != NULL);
180180

181181
if (call->rxcall) {
182-
rxrpc_kernel_end_call(net->socket, call->rxcall);
182+
rxrpc_kernel_shutdown_call(net->socket, call->rxcall);
183+
rxrpc_kernel_put_call(net->socket, call->rxcall);
183184
call->rxcall = NULL;
184185
}
185186
if (call->type->destructor)
@@ -420,10 +421,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
420421
* The call, however, might be queued on afs_async_calls and we need to
421422
* make sure we don't get any more notifications that might requeue it.
422423
*/
423-
if (call->rxcall) {
424-
rxrpc_kernel_end_call(call->net->socket, call->rxcall);
425-
call->rxcall = NULL;
426-
}
424+
if (call->rxcall)
425+
rxrpc_kernel_shutdown_call(call->net->socket, call->rxcall);
427426
if (call->async) {
428427
if (cancel_work_sync(&call->async_work))
429428
afs_put_call(call);

include/net/af_rxrpc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
5757
struct iov_iter *, size_t *, bool, u32 *, u16 *);
5858
bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
5959
u32, int, enum rxrpc_abort_reason);
60-
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
60+
void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call);
61+
void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call);
6162
void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
6263
struct sockaddr_rxrpc *);
6364
bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *);

net/rxrpc/af_rxrpc.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -342,31 +342,44 @@ static void rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall,
342342
}
343343

344344
/**
345-
* rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
345+
* rxrpc_kernel_shutdown_call - Allow a kernel service to shut down a call it was using
346346
* @sock: The socket the call is on
347347
* @call: The call to end
348348
*
349-
* Allow a kernel service to end a call it was using. The call must be
349+
* Allow a kernel service to shut down a call it was using. The call must be
350350
* complete before this is called (the call should be aborted if necessary).
351351
*/
352-
void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
352+
void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call)
353353
{
354354
_enter("%d{%d}", call->debug_id, refcount_read(&call->ref));
355355

356356
mutex_lock(&call->user_mutex);
357-
rxrpc_release_call(rxrpc_sk(sock->sk), call);
358-
359-
/* Make sure we're not going to call back into a kernel service */
360-
if (call->notify_rx) {
361-
spin_lock(&call->notify_lock);
362-
call->notify_rx = rxrpc_dummy_notify_rx;
363-
spin_unlock(&call->notify_lock);
357+
if (!test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
358+
rxrpc_release_call(rxrpc_sk(sock->sk), call);
359+
360+
/* Make sure we're not going to call back into a kernel service */
361+
if (call->notify_rx) {
362+
spin_lock(&call->notify_lock);
363+
call->notify_rx = rxrpc_dummy_notify_rx;
364+
spin_unlock(&call->notify_lock);
365+
}
364366
}
365-
366367
mutex_unlock(&call->user_mutex);
368+
}
369+
EXPORT_SYMBOL(rxrpc_kernel_shutdown_call);
370+
371+
/**
372+
* rxrpc_kernel_put_call - Release a reference to a call
373+
* @sock: The socket the call is on
374+
* @call: The call to put
375+
*
376+
* Drop the application's ref on an rxrpc call.
377+
*/
378+
void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call)
379+
{
367380
rxrpc_put_call(call, rxrpc_call_put_kernel);
368381
}
369-
EXPORT_SYMBOL(rxrpc_kernel_end_call);
382+
EXPORT_SYMBOL(rxrpc_kernel_put_call);
370383

371384
/**
372385
* rxrpc_kernel_check_life - Check to see whether a call is still alive

net/rxrpc/rxperf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ static void rxperf_deliver_to_call(struct work_struct *work)
342342
call_complete:
343343
rxperf_set_call_complete(call, ret, remote_abort);
344344
/* The call may have been requeued */
345-
rxrpc_kernel_end_call(rxperf_socket, call->rxcall);
345+
rxrpc_kernel_shutdown_call(rxperf_socket, call->rxcall);
346+
rxrpc_kernel_put_call(rxperf_socket, call->rxcall);
346347
cancel_work(&call->work);
347348
kfree(call);
348349
}

0 commit comments

Comments
 (0)