From: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Date: Sat, 21 May 2022 12:08:45 +0800
Subject: [PATCH] nfsd: Fix null-ptr-deref in nfsd_fill_super()
Git-commit: 6f6f84aa215f7b6665ccbb937db50860f9ec2989
Patch-mainline: v5.19
References: git-fixes
KASAN report null-ptr-deref as follows:
BUG: KASAN: null-ptr-deref in nfsd_fill_super+0xc6/0xe0 [nfsd]
Write of size 8 at addr 000000000000005d by task a.out/852
CPU: 7 PID: 852 Comm: a.out Not tainted 5.18.0-rc7-dirty #66
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x34/0x44
kasan_report+0xab/0x120
? nfsd_mkdir+0x71/0x1c0 [nfsd]
? nfsd_fill_super+0xc6/0xe0 [nfsd]
nfsd_fill_super+0xc6/0xe0 [nfsd]
? nfsd_mkdir+0x1c0/0x1c0 [nfsd]
get_tree_keyed+0x8e/0x100
vfs_get_tree+0x41/0xf0
__do_sys_fsconfig+0x590/0x670
? fscontext_read+0x180/0x180
? anon_inode_getfd+0x4f/0x70
do_syscall_64+0x35/0x80
entry_SYSCALL_64_after_hwframe+0x44/0xae
This can be reproduce by concurrent operations:
1. fsopen(nfsd)/fsconfig
2. insmod/rmmod nfsd
Since the nfsd file system is registered before than nfsd_net allocated,
the caller may get the file_system_type and use the nfsd_net before it
allocated, then null-ptr-deref occurred.
So init_nfsd() should call register_filesystem() last.
Fixes: bd5ae9288d64 ("nfsd: register pernet ops last, unregister first")
Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Acked-by: NeilBrown <neilb@suse.com>
---
fs/nfsd/nfsctl.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1539,20 +1539,20 @@ static int __init init_nfsd(void)
retval = create_proc_exports_entry();
if (retval)
goto out_free_lockd;
- retval = register_filesystem(&nfsd_fs_type);
- if (retval)
- goto out_free_exports;
retval = register_pernet_subsys(&nfsd_net_ops);
if (retval < 0)
- goto out_free_filesystem;
+ goto out_free_exports;
retval = register_cld_notifier();
if (retval)
+ goto out_free_subsys;
+ retval = register_filesystem(&nfsd_fs_type);
+ if (retval)
goto out_free_all;
return 0;
out_free_all:
+ unregister_cld_notifier();
+out_free_subsys:
unregister_pernet_subsys(&nfsd_net_ops);
-out_free_filesystem:
- unregister_filesystem(&nfsd_fs_type);
out_free_exports:
remove_proc_entry("fs/nfs/exports", NULL);
remove_proc_entry("fs/nfs", NULL);
@@ -1570,6 +1570,7 @@ out_free_slabs:
static void __exit exit_nfsd(void)
{
+ unregister_filesystem(&nfsd_fs_type);
unregister_cld_notifier();
unregister_pernet_subsys(&nfsd_net_ops);
nfsd_drc_slab_free();
@@ -1579,7 +1580,6 @@ static void __exit exit_nfsd(void)
nfsd_lockd_shutdown();
nfsd4_free_slabs();
nfsd4_exit_pnfs();
- unregister_filesystem(&nfsd_fs_type);
}
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");