| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2024-56779: nfsd: fix nfs4_openowner leak when concurrent nfsd4_open occur |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| nfsd: fix nfs4_openowner leak when concurrent nfsd4_open occur |
| |
| The action force umount(umount -f) will attempt to kill all rpc_task even |
| umount operation may ultimately fail if some files remain open. |
| Consequently, if an action attempts to open a file, it can potentially |
| send two rpc_task to nfs server. |
| |
| NFS CLIENT |
| thread1 thread2 |
| open("file") |
| ... |
| nfs4_do_open |
| _nfs4_do_open |
| _nfs4_open_and_get_state |
| _nfs4_proc_open |
| nfs4_run_open_task |
| /* rpc_task1 */ |
| rpc_run_task |
| rpc_wait_for_completion_task |
| |
| umount -f |
| nfs_umount_begin |
| rpc_killall_tasks |
| rpc_signal_task |
| rpc_task1 been wakeup |
| and return -512 |
| _nfs4_do_open // while loop |
| ... |
| nfs4_run_open_task |
| /* rpc_task2 */ |
| rpc_run_task |
| rpc_wait_for_completion_task |
| |
| While processing an open request, nfsd will first attempt to find or |
| allocate an nfs4_openowner. If it finds an nfs4_openowner that is not |
| marked as NFS4_OO_CONFIRMED, this nfs4_openowner will released. Since |
| two rpc_task can attempt to open the same file simultaneously from the |
| client to server, and because two instances of nfsd can run |
| concurrently, this situation can lead to lots of memory leak. |
| Additionally, when we echo 0 to /proc/fs/nfsd/threads, warning will be |
| triggered. |
| |
| NFS SERVER |
| nfsd1 nfsd2 echo 0 > /proc/fs/nfsd/threads |
| |
| nfsd4_open |
| nfsd4_process_open1 |
| find_or_alloc_open_stateowner |
| // alloc oo1, stateid1 |
| nfsd4_open |
| nfsd4_process_open1 |
| find_or_alloc_open_stateowner |
| // find oo1, without NFS4_OO_CONFIRMED |
| release_openowner |
| unhash_openowner_locked |
| list_del_init(&oo->oo_perclient) |
| // cannot find this oo |
| // from client, LEAK!!! |
| alloc_stateowner // alloc oo2 |
| |
| nfsd4_process_open2 |
| init_open_stateid |
| // associate oo1 |
| // with stateid1, stateid1 LEAK!!! |
| nfs4_get_vfs_file |
| // alloc nfsd_file1 and nfsd_file_mark1 |
| // all LEAK!!! |
| |
| nfsd4_process_open2 |
| ... |
| |
| write_threads |
| ... |
| nfsd_destroy_serv |
| nfsd_shutdown_net |
| nfs4_state_shutdown_net |
| nfs4_state_destroy_net |
| destroy_client |
| __destroy_client |
| // won't find oo1!!! |
| nfsd_shutdown_generic |
| nfsd_file_cache_shutdown |
| kmem_cache_destroy |
| for nfsd_file_slab |
| and nfsd_file_mark_slab |
| // bark since nfsd_file1 |
| // and nfsd_file_mark1 |
| // still alive |
| |
| ======================================================================= |
| BUG nfsd_file (Not tainted): Objects remaining in nfsd_file on |
| __kmem_cache_shutdown() |
| ----------------------------------------------------------------------- |
| |
| Slab 0xffd4000004438a80 objects=34 used=1 fp=0xff11000110e2ad28 |
| flags=0x17ffffc0000240(workingset|head|node=0|zone=2|lastcpupid=0x1fffff) |
| CPU: 4 UID: 0 PID: 757 Comm: sh Not tainted 6.12.0-rc6+ #19 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS |
| 1.16.1-2.fc37 04/01/2014 |
| Call Trace: |
| <TASK> |
| dump_stack_lvl+0x53/0x70 |
| slab_err+0xb0/0xf0 |
| __kmem_cache_shutdown+0x15c/0x310 |
| kmem_cache_destroy+0x66/0x160 |
| nfsd_file_cache_shutdown+0xac/0x210 [nfsd] |
| nfsd_destroy_serv+0x251/0x2a0 [nfsd] |
| nfsd_svc+0x125/0x1e0 [nfsd] |
| write_threads+0x16a/0x2a0 [nfsd] |
| nfsctl_transaction_write+0x74/0xa0 [nfsd] |
| vfs_write+0x1ae/0x6d0 |
| ksys_write+0xc1/0x160 |
| do_syscall_64+0x5f/0x170 |
| entry_SYSCALL_64_after_hwframe+0x76/0x7e |
| |
| Disabling lock debugging due to kernel taint |
| Object 0xff11000110e2ac38 @offset=3128 |
| Allocated in nfsd_file_do_acquire+0x20f/0xa30 [nfsd] age=1635 cpu=3 |
| pid=800 |
| nfsd_file_do_acquire+0x20f/0xa30 [nfsd] |
| nfsd_file_acquire_opened+0x5f/0x90 [nfsd] |
| nfs4_get_vfs_file+0x4c9/0x570 [nfsd] |
| nfsd4_process_open2+0x713/0x1070 [nfsd] |
| nfsd4_open+0x74b/0x8b0 [nfsd] |
| nfsd4_proc_compound+0x70b/0xc20 [nfsd] |
| nfsd_dispatch+0x1b4/0x3a0 [nfsd] |
| svc_process_common+0x5b8/0xc50 [sunrpc] |
| svc_process+0x2ab/0x3b0 [sunrpc] |
| svc_handle_xprt+0x681/0xa20 [sunrpc] |
| nfsd+0x183/0x220 [nfsd] |
| kthread+0x199/0x1e0 |
| ret_from_fork+0x31/0x60 |
| ret_from_fork_asm+0x1a/0x30 |
| |
| Add nfs4_openowner_unhashed to help found unhashed nfs4_openowner, and |
| break nfsd4_open process to fix this problem. |
| |
| The Linux kernel CVE team has assigned CVE-2024-56779 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Fixed in 5.4.287 with commit a85364f0d30dee01c5d5b4afa55a9629a8f36d8e |
| Fixed in 5.10.231 with commit 2d505a801e57428057563762f67a5a62009b2600 |
| Fixed in 5.15.174 with commit 0ab0a3ad24e970e894abcac58f85c332d1726749 |
| Fixed in 6.1.120 with commit 45abb68c941ebc9a35c6d3a7b08196712093c636 |
| Fixed in 6.6.64 with commit 37dfc81266d3a32294524bfadd3396614f8633ee |
| Fixed in 6.12.4 with commit 6f73f920b7ad0084373e46121d7ac34117aed652 |
| Fixed in 6.13 with commit 98100e88dd8865999dc6379a3356cd799795fe7b |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2024-56779 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| fs/nfsd/nfs4state.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/a85364f0d30dee01c5d5b4afa55a9629a8f36d8e |
| https://git.kernel.org/stable/c/2d505a801e57428057563762f67a5a62009b2600 |
| https://git.kernel.org/stable/c/0ab0a3ad24e970e894abcac58f85c332d1726749 |
| https://git.kernel.org/stable/c/45abb68c941ebc9a35c6d3a7b08196712093c636 |
| https://git.kernel.org/stable/c/37dfc81266d3a32294524bfadd3396614f8633ee |
| https://git.kernel.org/stable/c/6f73f920b7ad0084373e46121d7ac34117aed652 |
| https://git.kernel.org/stable/c/98100e88dd8865999dc6379a3356cd799795fe7b |