
From: Jeff Layton <jlayton@kernel.org> mainline inclusion from mainline-v6.15-rc1 commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC1QT8 CVE: CVE-2025-22026 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- Currently, nfsd_proc_stat_init() ignores the return value of svc_proc_register(). If the procfile creation fails, then the kernel will WARN when it tries to remove the entry later. Fix nfsd_proc_stat_init() to return the same type of pointer as svc_proc_register(), and fix up nfsd_net_init() to check that and fail the nfsd_net construction if it occurs. svc_proc_register() can fail if the dentry can't be allocated, or if an identical dentry already exists. The second case is pretty unlikely in the nfsd_net construction codepath, so if this happens, return -ENOMEM. Reported-by: syzbot+e34ad04f27991521104c@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-nfs/67a47501.050a0220.19061f.05f9.GAE@google.c... Cc: stable@vger.kernel.org # v6.9 Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Conflicts: fs/nfsd/nfsctl.c fs/nfsd/stats.c fs/nfsd/stats.h [Commit 5e092be7418f ("NFSD: Distinguish per-net namespace initialization") changes nfsd_init_net to nfsd_net_init; commit 93483ac5fec6 ("nfsd: expose /proc/net/sunrpc/nfsd in net namespaces") change nfsd_stat_init to nfsd_proc_stat_init.] Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com> Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com> --- fs/nfsd/nfsctl.c | 6 +++++- fs/nfsd/stats.c | 4 ++-- fs/nfsd/stats.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 02e3dd0c4703..040340080b3d 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1522,7 +1522,10 @@ static int __init init_nfsd(void) retval = nfsd4_init_pnfs(); if (retval) goto out_free_slabs; - nfsd_stat_init(); /* Statistics */ + if (!nfsd_stat_init()) { /* Statistics */ + retval = -ENOMEM; + goto out_free_pnfs; + } retval = nfsd_drc_slab_create(); if (retval) goto out_free_stat; @@ -1552,6 +1555,7 @@ static int __init init_nfsd(void) nfsd_drc_slab_free(); out_free_stat: nfsd_stat_shutdown(); +out_free_pnfs: nfsd4_exit_pnfs(); out_free_slabs: nfsd4_free_slabs(); diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index b1bc582b0493..9d45f4ce9344 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -91,10 +91,10 @@ static const struct proc_ops nfsd_proc_ops = { .proc_release = single_release, }; -void +struct proc_dir_entry * nfsd_stat_init(void) { - svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_ops); + return svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_ops); } void diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h index b23fdac69820..fdd7dfaee470 100644 --- a/fs/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -38,7 +38,7 @@ struct nfsd_stats { extern struct nfsd_stats nfsdstats; extern struct svc_stat nfsd_svcstats; -void nfsd_stat_init(void); +struct proc_dir_entry *nfsd_stat_init(void); void nfsd_stat_shutdown(void); #endif /* _NFSD_STATS_H */ -- 2.46.1