// For flags

CVE-2024-50106

nfsd: fix race between laundromat and free_stateid

Severity Score

"-"
*CVSS v-

Exploit Likelihood

*EPSS

Affected Versions

*CPE

Public Exploits

0
*Multiple Sources

Exploited in Wild

-
*KEV

Decision

-
*SSVC
Descriptions

In the Linux kernel, the following vulnerability has been resolved:

nfsd: fix race between laundromat and free_stateid

There is a race between laundromat handling of revoked delegations
and a client sending free_stateid operation. Laundromat thread
finds that delegation has expired and needs to be revoked so it
marks the delegation stid revoked and it puts it on a reaper list
but then it unlock the state lock and the actual delegation revocation
happens without the lock. Once the stid is marked revoked a racing
free_stateid processing thread does the following (1) it calls
list_del_init() which removes it from the reaper list and (2) frees
the delegation stid structure. The laundromat thread ends up not
calling the revoke_delegation() function for this particular delegation
but that means it will no release the lock lease that exists on
the file.

Now, a new open for this file comes in and ends up finding that
lease list isn't empty and calls nfsd_breaker_owns_lease() which ends
up trying to derefence a freed delegation stateid. Leading to the
followint use-after-free KASAN warning:

kernel: ==================================================================
kernel: BUG: KASAN: slab-use-after-free in nfsd_breaker_owns_lease+0x140/0x160 [nfsd]
kernel: Read of size 8 at addr ffff0000e73cd0c8 by task nfsd/6205
kernel:
kernel: CPU: 2 UID: 0 PID: 6205 Comm: nfsd Kdump: loaded Not tainted 6.11.0-rc7+ #9
kernel: Hardware name: Apple Inc. Apple Virtualization Generic Platform, BIOS 2069.0.0.0.0 08/03/2024
kernel: Call trace:
kernel: dump_backtrace+0x98/0x120
kernel: show_stack+0x1c/0x30
kernel: dump_stack_lvl+0x80/0xe8
kernel: print_address_description.constprop.0+0x84/0x390
kernel: print_report+0xa4/0x268
kernel: kasan_report+0xb4/0xf8
kernel: __asan_report_load8_noabort+0x1c/0x28
kernel: nfsd_breaker_owns_lease+0x140/0x160 [nfsd]
kernel: nfsd_file_do_acquire+0xb3c/0x11d0 [nfsd]
kernel: nfsd_file_acquire_opened+0x84/0x110 [nfsd]
kernel: nfs4_get_vfs_file+0x634/0x958 [nfsd]
kernel: nfsd4_process_open2+0xa40/0x1a40 [nfsd]
kernel: nfsd4_open+0xa08/0xe80 [nfsd]
kernel: nfsd4_proc_compound+0xb8c/0x2130 [nfsd]
kernel: nfsd_dispatch+0x22c/0x718 [nfsd]
kernel: svc_process_common+0x8e8/0x1960 [sunrpc]
kernel: svc_process+0x3d4/0x7e0 [sunrpc]
kernel: svc_handle_xprt+0x828/0xe10 [sunrpc]
kernel: svc_recv+0x2cc/0x6a8 [sunrpc]
kernel: nfsd+0x270/0x400 [nfsd]
kernel: kthread+0x288/0x310
kernel: ret_from_fork+0x10/0x20

This patch proposes a fixed that's based on adding 2 new additional
stid's sc_status values that help coordinate between the laundromat
and other operations (nfsd4_free_stateid() and nfsd4_delegreturn()).

First to make sure, that once the stid is marked revoked, it is not
removed by the nfsd4_free_stateid(), the laundromat take a reference
on the stateid. Then, coordinating whether the stid has been put
on the cl_revoked list or we are processing FREE_STATEID and need to
make sure to remove it from the list, each check that state and act
accordingly. If laundromat has added to the cl_revoke list before
the arrival of FREE_STATEID, then nfsd4_free_stateid() knows to remove
it from the list. If nfsd4_free_stateid() finds that operations arrived
before laundromat has placed it on cl_revoke list, it marks the state
freed and then laundromat will no longer add it to the list.

Also, for nfsd4_delegreturn() when looking for the specified stid,
we need to access stid that are marked removed or freeable, it means
the laundromat has started processing it but hasn't finished and this
delegreturn needs to return nfserr_deleg_revoked and not
nfserr_bad_stateid. The latter will not trigger a FREE_STATEID and the
lack of it will leave this stid on the cl_revoked list indefinitely.

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: nfsd: arregla la ejecución entre laundromat y free_stateid. Hay una ejecución entre el manejo de laundromat de delegaciones revocadas y un cliente que envía la operación free_stateid. El hilo de laundromat encuentra que la delegación ha expirado y necesita ser revocada, por lo que marca el stid de delegación revocado y lo pone en una lista de reaper, pero luego desbloquea el bloqueo de estado y la revocación de delegación real ocurre sin el bloqueo. Una vez que el stid está marcado como revocado, un hilo de procesamiento de free_stateid en ejecución hace lo siguiente: (1) llama a list_del_init() que lo elimina de la lista de reaper y (2) libera la estructura del stid de delegación. El hilo de laundromat termina sin llamar a la función revoke_delegation() para esta delegación en particular, pero eso significa que no liberará la concesión de bloqueo que existe en el archivo. Ahora, una nueva apertura para este archivo llega y termina encontrando que la lista de arrendamientos no está vacía y llama a nfsd_breaker_owns_lease() que termina intentando desreferenciar un stateid de delegación liberado. Lo que genera la siguiente advertencia de KASAN de use-after-free: kernel: == ... 2069.0.0.0.0 08/03/2024 núcleo: Seguimiento de llamadas: núcleo: dump_backtrace+0x98/0x120 núcleo: show_stack+0x1c/0x30 núcleo: dump_stack_lvl+0x80/0xe8 núcleo: print_address_description.constprop.0+0x84/0x390 núcleo: print_report+0xa4/0x268 núcleo: kasan_report+0xb4/0xf8 núcleo: __asan_report_load8_noabort+0x1c/0x28 núcleo: nfsd_breaker_owns_lease+0x140/0x160 [nfsd] núcleo: nfsd_file_do_acquire+0xb3c/0x11d0 [nfsd] núcleo: nfsd_file_acquire_opened+0x84/0x110 [nfsd] núcleo: nfs4_get_vfs_file+0x634/0x958 [nfsd] núcleo: nfsd4_process_open2+0xa40/0x1a40 [nfsd] núcleo: nfsd4_open+0xa08/0xe80 [nfsd] núcleo: nfsd4_proc_compound+0xb8c/0x2130 [nfsd] núcleo: nfsd_dispatch+0x22c/0x718 [nfsd] núcleo: svc_process_common+0x8e8/0x1960 [sunrpc] núcleo: svc_process+0x3d4/0x7e0 [sunrpc] núcleo: svc_handle_xprt+0x828/0xe10 [sunrpc] kernel: svc_recv+0x2cc/0x6a8 [sunrpc] kernel: nfsd+0x270/0x400 [nfsd] kernel: kthread+0x288/0x310 kernel: ret_from_fork+0x10/0x20 Este parche propone una solución basada en agregar 2 nuevos valores de stid adicionales sc_status que ayudan a coordinar entre la lavandería y otras operaciones (nfsd4_free_stateid() y nfsd4_delegreturn()). Primero, para asegurarse de que una vez que el stid esté marcado como revocado, no sea eliminado por nfsd4_free_stateid(), la lavandería tome una referencia en el stateid. Luego, al coordinar si el stid se ha colocado en la lista cl_revoked o si estamos procesando FREE_STATEID y debemos asegurarnos de eliminarlo de la lista, cada uno verifica ese estado y actúa en consecuencia. Si laundromat ha agregado a la lista cl_revoke antes de la llegada de FREE_STATEID, entonces nfsd4_free_stateid() sabe eliminarlo de la lista. Si nfsd4_free_stateid() encuentra que las operaciones llegaron antes de que laundromat lo haya colocado en la lista cl_revoke, marca el estado como liberado y luego laundromat ya no lo agregará a la lista. Además, para nfsd4_delegreturn() cuando buscamos el stid especificado, necesitamos acceder a los stid que están marcados como eliminados o liberables, significa que laundromat ha comenzado a procesarlo pero no ha terminado y este delegreturn debe devolver nfserr_deleg_revoked y no nfserr_bad_stateid. Este último no activará un FREE_STATEID y la falta del mismo dejará este stid en la lista cl_revoked indefinidamente.

*Credits: N/A
CVSS Scores
Attack Vector
-
Attack Complexity
-
Privileges Required
-
User Interaction
-
Scope
-
Confidentiality
-
Integrity
-
Availability
-
* Common Vulnerability Scoring System
SSVC
  • Decision:-
Exploitation
-
Automatable
-
Tech. Impact
-
* Organization's Worst-case Scenario
Timeline
  • 2024-10-21 CVE Reserved
  • 2024-11-05 CVE Published
  • 2024-11-05 CVE Updated
  • 2024-11-06 EPSS Updated
  • ---------- Exploited in Wild
  • ---------- KEV Due Date
  • ---------- First Exploit
CWE
CAPEC
Affected Vendors, Products, and Versions
Vendor Product Version Other Status
Vendor Product Version Other Status <-- --> Vendor Product Version Other Status
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 3.17 < 6.11.6
Search vendor "Linux" for product "Linux Kernel" and version " >= 3.17 < 6.11.6"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 3.17 < 6.12-rc5
Search vendor "Linux" for product "Linux Kernel" and version " >= 3.17 < 6.12-rc5"
en
Affected