linux/fs/nfsd
Yang Erkun 6f73f920b7 nfsd: fix nfs4_openowner leak when concurrent nfsd4_open occur
commit 98100e88dd upstream.

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.

Cc: stable@vger.kernel.org # v5.4+
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Yang Erkun <yangerkun@huawei.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2024-12-09 10:41:09 +01:00
..
acl.h NFSD: add posix ACLs to struct nfsd_attrs 2022-08-04 10:28:03 -04:00
auth.c nfsd: Pass 'cred' instead of 'rqstp' to some functions. 2024-09-20 19:31:03 -04:00
auth.h nfsd: Pass 'cred' instead of 'rqstp' to some functions. 2024-09-20 19:31:03 -04:00
blocklayout.c NFSD: Annotate struct pnfs_block_deviceaddr with __counted_by() 2024-09-20 19:31:03 -04:00
blocklayoutxdr.c NFSD: Make @gdev parameter of ->encode_getdeviceinfo a const pointer 2023-10-16 12:44:29 -04:00
blocklayoutxdr.h NFSD: Annotate struct pnfs_block_deviceaddr with __counted_by() 2024-09-20 19:31:03 -04:00
cache.h nfsd: don't allocate the versions array. 2024-09-20 19:29:23 -04:00
current_stateid.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
export.c nfsd: make sure exp active before svc_export_show 2024-12-09 10:41:09 +01:00
export.h nfsd: release svc_expkey/svc_export with rcu_work 2024-12-05 14:02:26 +01:00
filecache.c nfs_common: must not hold RCU while calling nfsd_file_put_local 2024-12-05 14:02:27 +01:00
filecache.h nfs_common: must not hold RCU while calling nfsd_file_put_local 2024-12-05 14:02:27 +01:00
flexfilelayout.c nfsd: move nfserrno() to vfs.c 2022-11-28 12:54:44 -05:00
flexfilelayoutxdr.c NFSD: Make @gdev parameter of ->encode_getdeviceinfo a const pointer 2023-10-16 12:44:29 -04:00
flexfilelayoutxdr.h NFSD: Make @gdev parameter of ->encode_getdeviceinfo a const pointer 2023-10-16 12:44:29 -04:00
idmap.h nfsd: Remove duplicate define of IDMAP_NAMESZ/IDMAP_TYPE_xx 2015-07-20 14:58:46 -04:00
Kconfig nfs_common: factor out nfs_errtbl and nfs_stat_to_errno 2024-09-23 15:03:29 -04:00
localio.c nfs_common: fix race in NFS calls to nfsd_file_put_local() and nfsd_serv_put() 2024-10-03 16:19:43 -04:00
lockd.c NFSD: simplify struct nfsfh 2021-10-02 15:51:10 -04:00
Makefile nfsd: add LOCALIO support 2024-09-23 15:03:30 -04:00
netlink.c nfsd: new netlink ops to get/set server pool_mode 2024-07-08 14:10:05 -04:00
netlink.h nfsd: new netlink ops to get/set server pool_mode 2024-07-08 14:10:05 -04:00
netns.h nfsd: add LOCALIO support 2024-09-23 15:03:30 -04:00
nfs2acl.c NFSD: remove unused structs 'nfsd3_voidargs' 2024-07-08 14:10:01 -04:00
nfs3acl.c NFSD: remove unused structs 'nfsd3_voidargs' 2024-07-08 14:10:01 -04:00
nfs3proc.c nfsd: move error choice for incorrect object types to version-specific code. 2024-09-20 19:31:03 -04:00
nfs3xdr.c nfsd: Fix NFSv3 atomicity bugs in nfsd_setattr() 2024-03-01 09:12:33 -05:00
nfs4acl.c nfsd: inherit required unset default acls from effective set 2023-08-29 17:45:22 -04:00
nfs4callback.c NFSD: Prevent a potential integer overflow 2024-12-05 14:03:02 +01:00
nfs4idmap.c nfsd: call cache_put if xdr_reserve_space returns NULL 2024-09-20 19:31:03 -04:00
nfs4layouts.c nfsd: track the main opcode for callbacks 2024-09-20 19:31:03 -04:00
nfs4proc.c NFSD: Fix nfsd4_shutdown_copy() 2024-12-05 14:02:26 +01:00
nfs4recover.c NFSD: Cap the number of bytes copied by nfs4_reset_recoverydir() 2024-12-05 14:02:26 +01:00
nfs4state.c nfsd: fix nfs4_openowner leak when concurrent nfsd4_open occur 2024-12-09 10:41:09 +01:00
nfs4xdr.c nfsd: drop inode parameter from nfsd4_change_attribute() 2024-12-05 14:02:24 +01:00
nfscache.c nfsd: Simplify the allocation of slab caches in nfsd_drc_slab_create 2024-03-01 09:12:24 -05:00
nfsctl.c nfsd: add LOCALIO support 2024-09-23 15:03:30 -04:00
nfsd.h nfsd: implement server support for NFS_LOCALIO_PROGRAM 2024-09-23 15:03:30 -04:00
nfsfh.c nfsd: drop inode parameter from nfsd4_change_attribute() 2024-12-05 14:02:24 +01:00
nfsfh.h nfsd: drop inode parameter from nfsd4_change_attribute() 2024-12-05 14:02:24 +01:00
nfsproc.c nfsd: move error choice for incorrect object types to version-specific code. 2024-09-20 19:31:03 -04:00
nfssvc.c NFS Client Bugfixes for Linux 6.12-rc 2024-10-11 15:37:15 -07:00
nfsxdr.c NFSD: Ensure that xdr_write_pages updates rq_next_page 2023-06-05 09:01:44 -04:00
pnfs.h nfsd: allow layout state to be admin-revoked. 2024-03-01 09:12:22 -05:00
state.h nfsd: fix race between laundromat and free_stateid 2024-10-18 16:40:37 -04:00
stats.c fs: nfsd: use group allocation/free of per-cpu counters API 2024-05-06 09:07:17 -04:00
stats.h fs: nfsd: use group allocation/free of per-cpu counters API 2024-05-06 09:07:17 -04:00
trace.c NFSD: Add SPDX header for fs/nfsd/trace.c 2020-11-30 13:00:24 -05:00
trace.h nfsd/localio: fix nfsd_file tracepoints to handle NULL rqstp 2024-10-04 14:52:04 -04:00
vfs.c NFSD: Fix READDIR on NFSv3 mounts of ext4 exports 2024-11-07 09:11:37 -05:00
vfs.h nfsd: add LOCALIO support 2024-09-23 15:03:30 -04:00
xdr.h NFSD: prevent underflow in nfssvc_decode_writeargs() 2022-03-15 09:35:56 -04:00
xdr3.h nfsd: Fix NFSv3 atomicity bugs in nfsd_setattr() 2024-03-01 09:12:33 -05:00
xdr4.h NFSD: Limit the number of concurrent async COPY operations 2024-09-20 19:31:03 -04:00
xdr4cb.h NFSD: add support for CB_GETATTR callback 2024-03-01 09:12:31 -05:00