linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] afs: Fix refcount underflow from error handling race
@ 2023-12-11 21:43 David Howells
  2023-12-15 17:54 ` Jeffrey E Altman
  0 siblings, 1 reply; 5+ messages in thread
From: David Howells @ 2023-12-11 21:43 UTC (permalink / raw)
  To: torvalds
  Cc: Bill MacAllister, David Howells, Jeffrey E Altman, Marc Dionne,
	linux-afs, linux-fsdevel, linux-kernel

Hi Linus,

Could you apply this fix, please?

David
---
afs: Fix refcount underflow from error handling race

If an AFS cell that has an unreachable (eg. ENETUNREACH) server listed (VL
server or fileserver), an asynchronous probe to one of its addresses may
fail immediately because sendmsg() returns an error.  When this happens, a
refcount underflow can happen if certain events hit a very small window.

The way this occurs is:

 (1) There are two levels of "call" object, the afs_call and the
     rxrpc_call.  Each of them can be transitioned to a "completed" state
     in the event of success or failure.

 (2) Asynchronous afs_calls are self-referential whilst they are active to
     prevent them from evaporating when they're not being processed.  This
     reference is disposed of when the afs_call is completed.

     Note that an afs_call may only be completed once; once completed
     completing it again will do nothing.

 (3) When a call transmission is made, the app-side rxrpc code queues a Tx
     buffer for the rxrpc I/O thread to transmit.  The I/O thread invokes
     sendmsg() to transmit it - and in the case of failure, it transitions
     the rxrpc_call to the completed state.

 (4) When an rxrpc_call is completed, the app layer is notified.  In this
     case, the app is kafs and it schedules a work item to process events
     pertaining to an afs_call.

 (5) When the afs_call event processor is run, it goes down through the
     RPC-specific handler to afs_extract_data() to retrieve data from rxrpc
     - and, in this case, it picks up the error from the rxrpc_call and
     returns it.

     The error is then propagated to the afs_call and that is completed
     too.  At this point the self-reference is released.

 (6) If the rxrpc I/O thread manages to complete the rxrpc_call within the
     window between rxrpc_send_data() queuing the request packet and
     checking for call completion on the way out, then
     rxrpc_kernel_send_data() will return the error from sendmsg() to the
     app.

 (7) Then afs_make_call() will see an error and will jump to the error
     handling path which will attempt to clean up the afs_call.

 (8) The problem comes when the error handling path in afs_make_call()
     tries to unconditionally drop an async afs_call's self-reference.
     This self-reference, however, may already have been dropped by
     afs_extract_data() completing the afs_call

 (9) The refcount underflows when we return to afs_do_probe_vlserver() and
     that tries to drop its reference on the afs_call.

Fix this by making afs_make_call() attempt to complete the afs_call rather
than unconditionally putting it.  That way, if afs_extract_data() manages
to complete the call first, afs_make_call() won't do anything.

The bug can be forced by making do_udp_sendmsg() return -ENETUNREACH and
sticking an msleep() in rxrpc_send_data() after the 'success:' label to
widen the race window.

The error message looks something like:

    refcount_t: underflow; use-after-free.
    WARNING: CPU: 3 PID: 720 at lib/refcount.c:28 refcount_warn_saturate+0xba/0x110
    ...
    RIP: 0010:refcount_warn_saturate+0xba/0x110
    ...
    afs_put_call+0x1dc/0x1f0 [kafs]
    afs_fs_get_capabilities+0x8b/0xe0 [kafs]
    afs_fs_probe_fileserver+0x188/0x1e0 [kafs]
    afs_lookup_server+0x3bf/0x3f0 [kafs]
    afs_alloc_server_list+0x130/0x2e0 [kafs]
    afs_create_volume+0x162/0x400 [kafs]
    afs_get_tree+0x266/0x410 [kafs]
    vfs_get_tree+0x25/0xc0
    fc_mount+0xe/0x40
    afs_d_automount+0x1b3/0x390 [kafs]
    __traverse_mounts+0x8f/0x210
    step_into+0x340/0x760
    path_openat+0x13a/0x1260
    do_filp_open+0xaf/0x160
    do_sys_openat2+0xaf/0x170

or something like:

    refcount_t: underflow; use-after-free.
    ...
    RIP: 0010:refcount_warn_saturate+0x99/0xda
    ...
    afs_put_call+0x4a/0x175
    afs_send_vl_probes+0x108/0x172
    afs_select_vlserver+0xd6/0x311
    afs_do_cell_detect_alias+0x5e/0x1e9
    afs_cell_detect_alias+0x44/0x92
    afs_validate_fc+0x9d/0x134
    afs_get_tree+0x20/0x2e6
    vfs_get_tree+0x1d/0xc9
    fc_mount+0xe/0x33
    afs_d_automount+0x48/0x9d
    __traverse_mounts+0xe0/0x166
    step_into+0x140/0x274
    open_last_lookups+0x1c1/0x1df
    path_openat+0x138/0x1c3
    do_filp_open+0x55/0xb4
    do_sys_openat2+0x6c/0xb6

Fixes: 34fa47612bfe ("afs: Fix race in async call refcounting")
Reported-by: Bill MacAllister <bill@ca-zephyr.org>
Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304
Suggested-by: Jeffrey E Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Link: https://lore.kernel.org/r/2633992.1702073229@warthog.procyon.org.uk/ # v1
---
 fs/afs/rxrpc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index ed1644e7683f..d642d06a453b 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -424,7 +424,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
 	if (call->async) {
 		if (cancel_work_sync(&call->async_work))
 			afs_put_call(call);
-		afs_put_call(call);
+		afs_set_call_complete(call, ret, 0);
 	}
 
 	ac->error = ret;


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] afs: Fix refcount underflow from error handling race
  2023-12-11 21:43 [PATCH] afs: Fix refcount underflow from error handling race David Howells
@ 2023-12-15 17:54 ` Jeffrey E Altman
  0 siblings, 0 replies; 5+ messages in thread
From: Jeffrey E Altman @ 2023-12-15 17:54 UTC (permalink / raw)
  To: David Howells, torvalds
  Cc: Bill MacAllister, Marc Dionne, linux-afs, linux-fsdevel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5869 bytes --]

On 12/11/2023 4:43 PM, David Howells wrote:
> Hi Linus,
>
> Could you apply this fix, please?
>
> David
> ---
> afs: Fix refcount underflow from error handling race
>
> If an AFS cell that has an unreachable (eg. ENETUNREACH) server listed (VL
> server or fileserver), an asynchronous probe to one of its addresses may
> fail immediately because sendmsg() returns an error.  When this happens, a
> refcount underflow can happen if certain events hit a very small window.
>
> The way this occurs is:
>
>   (1) There are two levels of "call" object, the afs_call and the
>       rxrpc_call.  Each of them can be transitioned to a "completed" state
>       in the event of success or failure.
>
>   (2) Asynchronous afs_calls are self-referential whilst they are active to
>       prevent them from evaporating when they're not being processed.  This
>       reference is disposed of when the afs_call is completed.
>
>       Note that an afs_call may only be completed once; once completed
>       completing it again will do nothing.
>
>   (3) When a call transmission is made, the app-side rxrpc code queues a Tx
>       buffer for the rxrpc I/O thread to transmit.  The I/O thread invokes
>       sendmsg() to transmit it - and in the case of failure, it transitions
>       the rxrpc_call to the completed state.
>
>   (4) When an rxrpc_call is completed, the app layer is notified.  In this
>       case, the app is kafs and it schedules a work item to process events
>       pertaining to an afs_call.
>
>   (5) When the afs_call event processor is run, it goes down through the
>       RPC-specific handler to afs_extract_data() to retrieve data from rxrpc
>       - and, in this case, it picks up the error from the rxrpc_call and
>       returns it.
>
>       The error is then propagated to the afs_call and that is completed
>       too.  At this point the self-reference is released.
>
>   (6) If the rxrpc I/O thread manages to complete the rxrpc_call within the
>       window between rxrpc_send_data() queuing the request packet and
>       checking for call completion on the way out, then
>       rxrpc_kernel_send_data() will return the error from sendmsg() to the
>       app.
>
>   (7) Then afs_make_call() will see an error and will jump to the error
>       handling path which will attempt to clean up the afs_call.
>
>   (8) The problem comes when the error handling path in afs_make_call()
>       tries to unconditionally drop an async afs_call's self-reference.
>       This self-reference, however, may already have been dropped by
>       afs_extract_data() completing the afs_call
>
>   (9) The refcount underflows when we return to afs_do_probe_vlserver() and
>       that tries to drop its reference on the afs_call.
>
> Fix this by making afs_make_call() attempt to complete the afs_call rather
> than unconditionally putting it.  That way, if afs_extract_data() manages
> to complete the call first, afs_make_call() won't do anything.
>
> The bug can be forced by making do_udp_sendmsg() return -ENETUNREACH and
> sticking an msleep() in rxrpc_send_data() after the 'success:' label to
> widen the race window.
>
> The error message looks something like:
>
>      refcount_t: underflow; use-after-free.
>      WARNING: CPU: 3 PID: 720 at lib/refcount.c:28 refcount_warn_saturate+0xba/0x110
>      ...
>      RIP: 0010:refcount_warn_saturate+0xba/0x110
>      ...
>      afs_put_call+0x1dc/0x1f0 [kafs]
>      afs_fs_get_capabilities+0x8b/0xe0 [kafs]
>      afs_fs_probe_fileserver+0x188/0x1e0 [kafs]
>      afs_lookup_server+0x3bf/0x3f0 [kafs]
>      afs_alloc_server_list+0x130/0x2e0 [kafs]
>      afs_create_volume+0x162/0x400 [kafs]
>      afs_get_tree+0x266/0x410 [kafs]
>      vfs_get_tree+0x25/0xc0
>      fc_mount+0xe/0x40
>      afs_d_automount+0x1b3/0x390 [kafs]
>      __traverse_mounts+0x8f/0x210
>      step_into+0x340/0x760
>      path_openat+0x13a/0x1260
>      do_filp_open+0xaf/0x160
>      do_sys_openat2+0xaf/0x170
>
> or something like:
>
>      refcount_t: underflow; use-after-free.
>      ...
>      RIP: 0010:refcount_warn_saturate+0x99/0xda
>      ...
>      afs_put_call+0x4a/0x175
>      afs_send_vl_probes+0x108/0x172
>      afs_select_vlserver+0xd6/0x311
>      afs_do_cell_detect_alias+0x5e/0x1e9
>      afs_cell_detect_alias+0x44/0x92
>      afs_validate_fc+0x9d/0x134
>      afs_get_tree+0x20/0x2e6
>      vfs_get_tree+0x1d/0xc9
>      fc_mount+0xe/0x33
>      afs_d_automount+0x48/0x9d
>      __traverse_mounts+0xe0/0x166
>      step_into+0x140/0x274
>      open_last_lookups+0x1c1/0x1df
>      path_openat+0x138/0x1c3
>      do_filp_open+0x55/0xb4
>      do_sys_openat2+0x6c/0xb6
>
> Fixes: 34fa47612bfe ("afs: Fix race in async call refcounting")
> Reported-by: Bill MacAllister <bill@ca-zephyr.org>
> Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304
> Suggested-by: Jeffrey E Altman <jaltman@auristor.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: linux-afs@lists.infradead.org
> Link: https://lore.kernel.org/r/2633992.1702073229@warthog.procyon.org.uk/ # v1
> ---
>   fs/afs/rxrpc.c |    2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index ed1644e7683f..d642d06a453b 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
> @@ -424,7 +424,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
>   	if (call->async) {
>   		if (cancel_work_sync(&call->async_work))
>   			afs_put_call(call);
> -		afs_put_call(call);
> +		afs_set_call_complete(call, ret, 0);
>   	}
>   
>   	ac->error = ret;

According to an update from Bill MacAllister to 
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304 this patch 
fixes the bug.

Tested-by: Bill MacAllister <bill@ca-zephyr.org>


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4039 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] afs: Fix refcount underflow from error handling race
  2023-12-08 22:07 David Howells
  2023-12-08 22:23 ` Jeffrey Altman
@ 2023-12-11 15:21 ` Marc Dionne
  1 sibling, 0 replies; 5+ messages in thread
From: Marc Dionne @ 2023-12-11 15:21 UTC (permalink / raw)
  To: David Howells; +Cc: Bill MacAllister, linux-afs, linux-fsdevel, linux-kernel

On Fri, Dec 8, 2023 at 6:07 PM David Howells <dhowells@redhat.com> wrote:
>
> If an AFS cell that has an unreachable (eg. ENETUNREACH) Volume Location
> server listed, an asynchronous probe to one of its addresses may fail
> immediately because sendmsg() returns an error.  When this happens, a
> refcount underflow can happen if certain events hit a very small window.
>
> The way this occurs is:
>
>  (1) There are two levels of "call" object, the afs_call and the
>      rxrpc_call.  Each of them can be transitioned to a "completed" state
>      in the event of success or failure.
>
>  (2) Asynchronous afs_calls are self-referential whilst they are active to
>      prevent them from evaporating when they're not being processed.  This
>      reference is disposed of when the afs_call is completed.
>
>      Note that an afs_call may only be completed once; once completed
>      completing it again will do nothing.
>
>  (3) When a call transmission is made, the app-side rxrpc code queues a Tx
>      buffer for the rxrpc I/O thread to transmit.  The I/O thread invokes
>      sendmsg() to transmit it - and in the case of failure, it transitions
>      the rxrpc_call to the completed state.
>
>  (4) When an rxrpc_call is completed, the app layer is notified.  In this
>      case, the app is kafs and it schedules a work item to process events
>      pertaining to an afs_call.
>
>  (5) When the afs_call event processor is run, it goes down through the
>      RPC-specific handler to afs_extract_data() to retrieve data from rxrpc
>      - and, in this case, it picks up the error from the rxrpc_call and
>      returns it.
>
>      The error is then propagated to the afs_call and that is completed
>      too.  At this point the self-reference is released.
>
>  (6) If the rxrpc I/O thread manages to complete the rxrpc_call within the
>      window between rxrpc_send_data() queuing the request packet and
>      checking for call completion on the way out, then
>      rxrpc_kernel_send_data() will return the error from sendmsg() to the
>      app.
>
>  (7) Then afs_make_call() will see an error and will jump to the error
>      handling path which will attempt to clean up the afs_call.
>
>  (8) The problem comes when the error handling path in afs_make_call()
>      tries to unconditionally drop an async afs_call's self-reference.
>      This self-reference, however, may already have been dropped by
>      afs_extract_data() completing the afs_call
>
>  (9) The refcount underflows when we return to afs_do_probe_vlserver() and
>      that tries to drop its reference on the afs_call.
>
> Fix this by making afs_make_call() attempt to complete the afs_call rather
> than unconditionally putting it.  That way, if afs_extract_data() manages
> to complete the call first, afs_make_call() won't do anything.
>
> The bug can be forced by making do_udp_sendmsg() return -ENETUNREACH and
> sticking an msleep() in rxrpc_send_data() after the 'success:' label.
>
> The error message looks something like:
>
>     refcount_t: underflow; use-after-free.
>     WARNING: CPU: 3 PID: 720 at lib/refcount.c:28 refcount_warn_saturate+0xba/0x110
>     ...
>     RIP: 0010:refcount_warn_saturate+0xba/0x110
>     ...
>     afs_put_call+0x1dc/0x1f0 [kafs]
>     afs_fs_get_capabilities+0x8b/0xe0 [kafs]
>     afs_fs_probe_fileserver+0x188/0x1e0 [kafs]
>     afs_lookup_server+0x3bf/0x3f0 [kafs]
>     afs_alloc_server_list+0x130/0x2e0 [kafs]
>     afs_create_volume+0x162/0x400 [kafs]
>     afs_get_tree+0x266/0x410 [kafs]
>     vfs_get_tree+0x25/0xc0
>     fc_mount+0xe/0x40
>     afs_d_automount+0x1b3/0x390 [kafs]
>     __traverse_mounts+0x8f/0x210
>     step_into+0x340/0x760
>     path_openat+0x13a/0x1260
>     do_filp_open+0xaf/0x160
>     do_sys_openat2+0xaf/0x170
>
> or something like:
>
>     refcount_t: underflow; use-after-free.
>     ...
>     RIP: 0010:refcount_warn_saturate+0x99/0xda
>     ...
>     afs_put_call+0x4a/0x175
>     afs_send_vl_probes+0x108/0x172
>     afs_select_vlserver+0xd6/0x311
>     afs_do_cell_detect_alias+0x5e/0x1e9
>     afs_cell_detect_alias+0x44/0x92
>     afs_validate_fc+0x9d/0x134
>     afs_get_tree+0x20/0x2e6
>     vfs_get_tree+0x1d/0xc9
>     fc_mount+0xe/0x33
>     afs_d_automount+0x48/0x9d
>     __traverse_mounts+0xe0/0x166
>     step_into+0x140/0x274
>     open_last_lookups+0x1c1/0x1df
>     path_openat+0x138/0x1c3
>     do_filp_open+0x55/0xb4
>     do_sys_openat2+0x6c/0xb6
>
> Fixes: 34fa47612bfe ("afs: Fix race in async call refcounting")
> Reported-by: Bill MacAllister <bill@ca-zephyr.org>
> Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304
> Suggested-by: Jeffrey E Altman <jaltman@auristor.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: linux-afs@lists.infradead.org
> ---
>  fs/afs/rxrpc.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index ed1644e7683f..d642d06a453b 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
> @@ -424,7 +424,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
>         if (call->async) {
>                 if (cancel_work_sync(&call->async_work))
>                         afs_put_call(call);
> -               afs_put_call(call);
> +               afs_set_call_complete(call, ret, 0);
>         }
>
>         ac->error = ret;

Reviewed-by: Marc Dionne <marc.dionne@auristor.com>
Tested-by: Marc Dionne <marc.dionne@auristor.com>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] afs: Fix refcount underflow from error handling race
  2023-12-08 22:07 David Howells
@ 2023-12-08 22:23 ` Jeffrey Altman
  2023-12-11 15:21 ` Marc Dionne
  1 sibling, 0 replies; 5+ messages in thread
From: Jeffrey Altman @ 2023-12-08 22:23 UTC (permalink / raw)
  To: David Howells
  Cc: Bill MacAllister, linux-afs, Marc Dionne, linux-fsdevel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5461 bytes --]


> On Dec 8, 2023, at 5:07 PM, David Howells <dhowells@redhat.com> wrote:
> 
> If an AFS cell that has an unreachable (eg. ENETUNREACH) Volume Location
> server listed, an asynchronous probe to one of its addresses may fail
> immediately because sendmsg() returns an error.  When this happens, a
> refcount underflow can happen if certain events hit a very small window.
> 
> The way this occurs is:
> 
> (1) There are two levels of "call" object, the afs_call and the
>     rxrpc_call.  Each of them can be transitioned to a "completed" state
>     in the event of success or failure.
> 
> (2) Asynchronous afs_calls are self-referential whilst they are active to
>     prevent them from evaporating when they're not being processed.  This
>     reference is disposed of when the afs_call is completed.
> 
>     Note that an afs_call may only be completed once; once completed
>     completing it again will do nothing.
> 
> (3) When a call transmission is made, the app-side rxrpc code queues a Tx
>     buffer for the rxrpc I/O thread to transmit.  The I/O thread invokes
>     sendmsg() to transmit it - and in the case of failure, it transitions
>     the rxrpc_call to the completed state.
> 
> (4) When an rxrpc_call is completed, the app layer is notified.  In this
>     case, the app is kafs and it schedules a work item to process events
>     pertaining to an afs_call.
> 
> (5) When the afs_call event processor is run, it goes down through the
>     RPC-specific handler to afs_extract_data() to retrieve data from rxrpc
>     - and, in this case, it picks up the error from the rxrpc_call and
>     returns it.
> 
>     The error is then propagated to the afs_call and that is completed
>     too.  At this point the self-reference is released.
> 
> (6) If the rxrpc I/O thread manages to complete the rxrpc_call within the
>     window between rxrpc_send_data() queuing the request packet and
>     checking for call completion on the way out, then
>     rxrpc_kernel_send_data() will return the error from sendmsg() to the
>     app.
> 
> (7) Then afs_make_call() will see an error and will jump to the error
>     handling path which will attempt to clean up the afs_call.
> 
> (8) The problem comes when the error handling path in afs_make_call()
>     tries to unconditionally drop an async afs_call's self-reference.
>     This self-reference, however, may already have been dropped by
>     afs_extract_data() completing the afs_call
> 
> (9) The refcount underflows when we return to afs_do_probe_vlserver() and
>     that tries to drop its reference on the afs_call.
> 
> Fix this by making afs_make_call() attempt to complete the afs_call rather
> than unconditionally putting it.  That way, if afs_extract_data() manages
> to complete the call first, afs_make_call() won't do anything.
> 
> The bug can be forced by making do_udp_sendmsg() return -ENETUNREACH and
> sticking an msleep() in rxrpc_send_data() after the 'success:' label.
> 
> The error message looks something like:
> 
>    refcount_t: underflow; use-after-free.
>    WARNING: CPU: 3 PID: 720 at lib/refcount.c:28 refcount_warn_saturate+0xba/0x110
>    ...
>    RIP: 0010:refcount_warn_saturate+0xba/0x110
>    ...
>    afs_put_call+0x1dc/0x1f0 [kafs]
>    afs_fs_get_capabilities+0x8b/0xe0 [kafs]
>    afs_fs_probe_fileserver+0x188/0x1e0 [kafs]
>    afs_lookup_server+0x3bf/0x3f0 [kafs]
>    afs_alloc_server_list+0x130/0x2e0 [kafs]
>    afs_create_volume+0x162/0x400 [kafs]
>    afs_get_tree+0x266/0x410 [kafs]
>    vfs_get_tree+0x25/0xc0
>    fc_mount+0xe/0x40
>    afs_d_automount+0x1b3/0x390 [kafs]
>    __traverse_mounts+0x8f/0x210
>    step_into+0x340/0x760
>    path_openat+0x13a/0x1260
>    do_filp_open+0xaf/0x160
>    do_sys_openat2+0xaf/0x170
> 
> or something like:
> 
>    refcount_t: underflow; use-after-free.
>    ...
>    RIP: 0010:refcount_warn_saturate+0x99/0xda
>    ...
>    afs_put_call+0x4a/0x175
>    afs_send_vl_probes+0x108/0x172
>    afs_select_vlserver+0xd6/0x311
>    afs_do_cell_detect_alias+0x5e/0x1e9
>    afs_cell_detect_alias+0x44/0x92
>    afs_validate_fc+0x9d/0x134
>    afs_get_tree+0x20/0x2e6
>    vfs_get_tree+0x1d/0xc9
>    fc_mount+0xe/0x33
>    afs_d_automount+0x48/0x9d
>    __traverse_mounts+0xe0/0x166
>    step_into+0x140/0x274
>    open_last_lookups+0x1c1/0x1df
>    path_openat+0x138/0x1c3
>    do_filp_open+0x55/0xb4
>    do_sys_openat2+0x6c/0xb6
> 
> Fixes: 34fa47612bfe ("afs: Fix race in async call refcounting")
> Reported-by: Bill MacAllister <bill@ca-zephyr.org>
> Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304
> Suggested-by: Jeffrey E Altman <jaltman@auristor.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: linux-afs@lists.infradead.org
> ---
> fs/afs/rxrpc.c |    2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index ed1644e7683f..d642d06a453b 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
> @@ -424,7 +424,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
> if (call->async) {
> if (cancel_work_sync(&call->async_work))
> afs_put_call(call);
> - afs_put_call(call);
> + afs_set_call_complete(call, ret, 0);
> }
> 
> ac->error = ret;
> 

Reviewed-by: Jeffrey Altman <jaltman@auristor.com>


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3929 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] afs: Fix refcount underflow from error handling race
@ 2023-12-08 22:07 David Howells
  2023-12-08 22:23 ` Jeffrey Altman
  2023-12-11 15:21 ` Marc Dionne
  0 siblings, 2 replies; 5+ messages in thread
From: David Howells @ 2023-12-08 22:07 UTC (permalink / raw)
  To: Bill MacAllister, linux-afs
  Cc: David Howells, Jeffrey E Altman, Marc Dionne, linux-fsdevel,
	linux-kernel

If an AFS cell that has an unreachable (eg. ENETUNREACH) Volume Location
server listed, an asynchronous probe to one of its addresses may fail
immediately because sendmsg() returns an error.  When this happens, a
refcount underflow can happen if certain events hit a very small window.

The way this occurs is:

 (1) There are two levels of "call" object, the afs_call and the
     rxrpc_call.  Each of them can be transitioned to a "completed" state
     in the event of success or failure.

 (2) Asynchronous afs_calls are self-referential whilst they are active to
     prevent them from evaporating when they're not being processed.  This
     reference is disposed of when the afs_call is completed.

     Note that an afs_call may only be completed once; once completed
     completing it again will do nothing.

 (3) When a call transmission is made, the app-side rxrpc code queues a Tx
     buffer for the rxrpc I/O thread to transmit.  The I/O thread invokes
     sendmsg() to transmit it - and in the case of failure, it transitions
     the rxrpc_call to the completed state.

 (4) When an rxrpc_call is completed, the app layer is notified.  In this
     case, the app is kafs and it schedules a work item to process events
     pertaining to an afs_call.

 (5) When the afs_call event processor is run, it goes down through the
     RPC-specific handler to afs_extract_data() to retrieve data from rxrpc
     - and, in this case, it picks up the error from the rxrpc_call and
     returns it.

     The error is then propagated to the afs_call and that is completed
     too.  At this point the self-reference is released.

 (6) If the rxrpc I/O thread manages to complete the rxrpc_call within the
     window between rxrpc_send_data() queuing the request packet and
     checking for call completion on the way out, then
     rxrpc_kernel_send_data() will return the error from sendmsg() to the
     app.

 (7) Then afs_make_call() will see an error and will jump to the error
     handling path which will attempt to clean up the afs_call.

 (8) The problem comes when the error handling path in afs_make_call()
     tries to unconditionally drop an async afs_call's self-reference.
     This self-reference, however, may already have been dropped by
     afs_extract_data() completing the afs_call

 (9) The refcount underflows when we return to afs_do_probe_vlserver() and
     that tries to drop its reference on the afs_call.

Fix this by making afs_make_call() attempt to complete the afs_call rather
than unconditionally putting it.  That way, if afs_extract_data() manages
to complete the call first, afs_make_call() won't do anything.

The bug can be forced by making do_udp_sendmsg() return -ENETUNREACH and
sticking an msleep() in rxrpc_send_data() after the 'success:' label.

The error message looks something like:

    refcount_t: underflow; use-after-free.
    WARNING: CPU: 3 PID: 720 at lib/refcount.c:28 refcount_warn_saturate+0xba/0x110
    ...
    RIP: 0010:refcount_warn_saturate+0xba/0x110
    ...
    afs_put_call+0x1dc/0x1f0 [kafs]
    afs_fs_get_capabilities+0x8b/0xe0 [kafs]
    afs_fs_probe_fileserver+0x188/0x1e0 [kafs]
    afs_lookup_server+0x3bf/0x3f0 [kafs]
    afs_alloc_server_list+0x130/0x2e0 [kafs]
    afs_create_volume+0x162/0x400 [kafs]
    afs_get_tree+0x266/0x410 [kafs]
    vfs_get_tree+0x25/0xc0
    fc_mount+0xe/0x40
    afs_d_automount+0x1b3/0x390 [kafs]
    __traverse_mounts+0x8f/0x210
    step_into+0x340/0x760
    path_openat+0x13a/0x1260
    do_filp_open+0xaf/0x160
    do_sys_openat2+0xaf/0x170

or something like:

    refcount_t: underflow; use-after-free.
    ...
    RIP: 0010:refcount_warn_saturate+0x99/0xda
    ...
    afs_put_call+0x4a/0x175
    afs_send_vl_probes+0x108/0x172
    afs_select_vlserver+0xd6/0x311
    afs_do_cell_detect_alias+0x5e/0x1e9
    afs_cell_detect_alias+0x44/0x92
    afs_validate_fc+0x9d/0x134
    afs_get_tree+0x20/0x2e6
    vfs_get_tree+0x1d/0xc9
    fc_mount+0xe/0x33
    afs_d_automount+0x48/0x9d
    __traverse_mounts+0xe0/0x166
    step_into+0x140/0x274
    open_last_lookups+0x1c1/0x1df
    path_openat+0x138/0x1c3
    do_filp_open+0x55/0xb4
    do_sys_openat2+0x6c/0xb6

Fixes: 34fa47612bfe ("afs: Fix race in async call refcounting")
Reported-by: Bill MacAllister <bill@ca-zephyr.org>
Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1052304
Suggested-by: Jeffrey E Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
---
 fs/afs/rxrpc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index ed1644e7683f..d642d06a453b 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -424,7 +424,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
 	if (call->async) {
 		if (cancel_work_sync(&call->async_work))
 			afs_put_call(call);
-		afs_put_call(call);
+		afs_set_call_complete(call, ret, 0);
 	}
 
 	ac->error = ret;


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-12-15 18:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-11 21:43 [PATCH] afs: Fix refcount underflow from error handling race David Howells
2023-12-15 17:54 ` Jeffrey E Altman
  -- strict thread matches above, loose matches on Subject: below --
2023-12-08 22:07 David Howells
2023-12-08 22:23 ` Jeffrey Altman
2023-12-11 15:21 ` Marc Dionne

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).