Skip to content

Commit 603ad23

Browse files
committed
nfsd: don't ignore the return code of svc_proc_register()
jira LE-4321 cve CVE-2025-22026 Rebuild_History Non-Buildable kernel-4.18.0-553.77.1.el8_10 commit-author Jeff Layton <jlayton@kernel.org> commit 930b64c Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed 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.com/ Cc: stable@vger.kernel.org # v6.9 Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> (cherry picked from commit 930b64c) Signed-off-by: Jonathan Maple <jmaple@ciq.com> # Conflicts: # fs/nfsd/nfsctl.c # fs/nfsd/stats.c # fs/nfsd/stats.h
1 parent 38f3196 commit 603ad23

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
nfsd: don't ignore the return code of svc_proc_register()
2+
3+
jira LE-4321
4+
cve CVE-2025-22026
5+
Rebuild_History Non-Buildable kernel-4.18.0-553.77.1.el8_10
6+
commit-author Jeff Layton <jlayton@kernel.org>
7+
commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b
8+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
9+
Will be included in final tarball splat. Ref for failed cherry-pick at:
10+
ciq/ciq_backports/kernel-4.18.0-553.77.1.el8_10/930b64ca.failed
11+
12+
Currently, nfsd_proc_stat_init() ignores the return value of
13+
svc_proc_register(). If the procfile creation fails, then the kernel
14+
will WARN when it tries to remove the entry later.
15+
16+
Fix nfsd_proc_stat_init() to return the same type of pointer as
17+
svc_proc_register(), and fix up nfsd_net_init() to check that and fail
18+
the nfsd_net construction if it occurs.
19+
20+
svc_proc_register() can fail if the dentry can't be allocated, or if an
21+
identical dentry already exists. The second case is pretty unlikely in
22+
the nfsd_net construction codepath, so if this happens, return -ENOMEM.
23+
24+
Reported-by: syzbot+e34ad04f27991521104c@syzkaller.appspotmail.com
25+
Closes: https://lore.kernel.org/linux-nfs/67a47501.050a0220.19061f.05f9.GAE@google.com/
26+
Cc: stable@vger.kernel.org # v6.9
27+
Signed-off-by: Jeff Layton <jlayton@kernel.org>
28+
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
29+
(cherry picked from commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b)
30+
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
31+
32+
# Conflicts:
33+
# fs/nfsd/nfsctl.c
34+
# fs/nfsd/stats.c
35+
# fs/nfsd/stats.h
36+
diff --cc fs/nfsd/nfsctl.c
37+
index 9bd5cf3f6d3c,ac265d6fde35..000000000000
38+
--- a/fs/nfsd/nfsctl.c
39+
+++ b/fs/nfsd/nfsctl.c
40+
@@@ -1463,27 -2198,36 +1463,57 @@@ static __net_init int nfsd_init_net(str
41+
retval = nfsd_idmap_init(net);
42+
if (retval)
43+
goto out_idmap_error;
44+
- retval = percpu_counter_init_many(nn->counter, 0, GFP_KERNEL,
45+
- NFSD_STATS_COUNTERS_NUM);
46+
+ nn->nfsd_versions = NULL;
47+
+ nn->nfsd4_minorversions = NULL;
48+
+ retval = nfsd_reply_cache_init(nn);
49+
if (retval)
50+
++<<<<<<< HEAD
51+
+ goto out_drc_error;
52+
+ nn->nfsd4_lease = 90; /* default lease time */
53+
+ nn->nfsd4_grace = 90;
54+
+ nn->somebody_reclaimed = false;
55+
+ nn->track_reclaim_completes = false;
56+
+ nn->clverifier_counter = prandom_u32();
57+
+ nn->clientid_base = prandom_u32();
58+
+ nn->clientid_counter = nn->clientid_base + 1;
59+
+ nn->s2s_cp_cl_id = nn->clientid_counter++;
60+
+
61+
+ atomic_set(&nn->ntf_refcnt, 0);
62+
+ init_waitqueue_head(&nn->ntf_wq);
63+
+ seqlock_init(&nn->boot_lock);
64+
+
65+
+ return 0;
66+
+
67+
+out_drc_error:
68+
++=======
69+
+ goto out_repcache_error;
70+
+
71+
+ memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
72+
+ nn->nfsd_svcstats.program = &nfsd_programs[0];
73+
+ if (!nfsd_proc_stat_init(net)) {
74+
+ retval = -ENOMEM;
75+
+ goto out_proc_error;
76+
+ }
77+
+
78+
+ for (i = 0; i < sizeof(nn->nfsd_versions); i++)
79+
+ nn->nfsd_versions[i] = nfsd_support_version(i);
80+
+ for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)
81+
+ nn->nfsd4_minorversions[i] = nfsd_support_version(4);
82+
+ nn->nfsd_info.mutex = &nfsd_mutex;
83+
+ nn->nfsd_serv = NULL;
84+
+ nfsd4_init_leases_net(nn);
85+
+ get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
86+
+ seqlock_init(&nn->writeverf_lock);
87+
+ #if IS_ENABLED(CONFIG_NFS_LOCALIO)
88+
+ spin_lock_init(&nn->local_clients_lock);
89+
+ INIT_LIST_HEAD(&nn->local_clients);
90+
+ #endif
91+
+ return 0;
92+
+
93+
+ out_proc_error:
94+
+ percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
95+
+ out_repcache_error:
96+
++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register())
97+
nfsd_idmap_shutdown(net);
98+
out_idmap_error:
99+
nfsd_export_shutdown(net);
100+
diff --cc fs/nfsd/stats.c
101+
index 9bce3b913189,f7eaf95e20fc..000000000000
102+
--- a/fs/nfsd/stats.c
103+
+++ b/fs/nfsd/stats.c
104+
@@@ -79,26 -71,16 +79,36 @@@ static int nfsd_proc_show(struct seq_fi
105+
return 0;
106+
}
107+
108+
++<<<<<<< HEAD
109+
+static int nfsd_proc_open(struct inode *inode, struct file *file)
110+
+{
111+
+ return single_open(file, nfsd_proc_show, NULL);
112+
++=======
113+
+ DEFINE_PROC_SHOW_ATTRIBUTE(nfsd);
114+
+
115+
+ struct proc_dir_entry *nfsd_proc_stat_init(struct net *net)
116+
+ {
117+
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
118+
+
119+
+ return svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
120+
++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register())
121+
+}
122+
+
123+
+static const struct file_operations nfsd_proc_fops = {
124+
+ .open = nfsd_proc_open,
125+
+ .read = seq_read,
126+
+ .llseek = seq_lseek,
127+
+ .release = single_release,
128+
+};
129+
+
130+
+void
131+
+nfsd_stat_init(void)
132+
+{
133+
+ svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops);
134+
}
135+
136+
-void nfsd_proc_stat_shutdown(struct net *net)
137+
+void
138+
+nfsd_stat_shutdown(void)
139+
{
140+
- svc_proc_unregister(net, "nfsd");
141+
+ svc_proc_unregister(&init_net, "nfsd");
142+
}
143+
diff --cc fs/nfsd/stats.h
144+
index b23fdac69820,e4efb0e4e56d..000000000000
145+
--- a/fs/nfsd/stats.h
146+
+++ b/fs/nfsd/stats.h
147+
@@@ -8,37 -8,69 +8,96 @@@
148+
#define _NFSD_STATS_H
149+
150+
#include <uapi/linux/nfsd/stats.h>
151+
-#include <linux/percpu_counter.h>
152+
153+
++<<<<<<< HEAD
154+
++=======
155+
+ struct proc_dir_entry *nfsd_proc_stat_init(struct net *net);
156+
+ void nfsd_proc_stat_shutdown(struct net *net);
157+
+
158+
+ static inline void nfsd_stats_rc_hits_inc(struct nfsd_net *nn)
159+
+ {
160+
+ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_HITS]);
161+
+ }
162+
+
163+
+ static inline void nfsd_stats_rc_misses_inc(struct nfsd_net *nn)
164+
+ {
165+
+ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_MISSES]);
166+
+ }
167+
+
168+
+ static inline void nfsd_stats_rc_nocache_inc(struct nfsd_net *nn)
169+
+ {
170+
+ percpu_counter_inc(&nn->counter[NFSD_STATS_RC_NOCACHE]);
171+
+ }
172+
+
173+
+ static inline void nfsd_stats_fh_stale_inc(struct nfsd_net *nn,
174+
+ struct svc_export *exp)
175+
+ {
176+
+ percpu_counter_inc(&nn->counter[NFSD_STATS_FH_STALE]);
177+
+ if (exp && exp->ex_stats)
178+
+ percpu_counter_inc(&exp->ex_stats->counter[EXP_STATS_FH_STALE]);
179+
+ }
180+
+
181+
+ static inline void nfsd_stats_io_read_add(struct nfsd_net *nn,
182+
+ struct svc_export *exp, s64 amount)
183+
+ {
184+
+ percpu_counter_add(&nn->counter[NFSD_STATS_IO_READ], amount);
185+
+ if (exp && exp->ex_stats)
186+
+ percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_READ], amount);
187+
+ }
188+
+
189+
+ static inline void nfsd_stats_io_write_add(struct nfsd_net *nn,
190+
+ struct svc_export *exp, s64 amount)
191+
+ {
192+
+ percpu_counter_add(&nn->counter[NFSD_STATS_IO_WRITE], amount);
193+
+ if (exp && exp->ex_stats)
194+
+ percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_WRITE], amount);
195+
+ }
196+
+
197+
+ static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn)
198+
+ {
199+
+ percpu_counter_inc(&nn->counter[NFSD_STATS_PAYLOAD_MISSES]);
200+
+ }
201+
+
202+
+ static inline void nfsd_stats_drc_mem_usage_add(struct nfsd_net *nn, s64 amount)
203+
+ {
204+
+ percpu_counter_add(&nn->counter[NFSD_STATS_DRC_MEM_USAGE], amount);
205+
+ }
206+
+
207+
+ static inline void nfsd_stats_drc_mem_usage_sub(struct nfsd_net *nn, s64 amount)
208+
+ {
209+
+ percpu_counter_sub(&nn->counter[NFSD_STATS_DRC_MEM_USAGE], amount);
210+
+ }
211+
++>>>>>>> 930b64ca0c51 (nfsd: don't ignore the return code of svc_proc_register())
212+
213+
+struct nfsd_stats {
214+
+ unsigned int rchits; /* repcache hits */
215+
+ unsigned int rcmisses; /* repcache hits */
216+
+ unsigned int rcnocache; /* uncached reqs */
217+
+ unsigned int fh_stale; /* FH stale error */
218+
+ unsigned int fh_lookup; /* dentry cached */
219+
+ unsigned int fh_anon; /* anon file dentry returned */
220+
+ unsigned int fh_nocache_dir; /* filehandle not found in dcache */
221+
+ unsigned int fh_nocache_nondir; /* filehandle not found in dcache */
222+
+ unsigned int io_read; /* bytes returned to read requests */
223+
+ unsigned int io_write; /* bytes passed in write requests */
224+
+ unsigned int th_cnt; /* number of available threads */
225+
+ unsigned int th_usage[10]; /* number of ticks during which n perdeciles
226+
+ * of available threads were in use */
227+
+ unsigned int th_fullcnt; /* number of times last free thread was used */
228+
+ unsigned int ra_size; /* size of ra cache */
229+
+ unsigned int ra_depth[11]; /* number of times ra entry was found that deep
230+
+ * in the cache (10percentiles). [10] = not found */
231+
#ifdef CONFIG_NFSD_V4
232+
-static inline void nfsd_stats_wdeleg_getattr_inc(struct nfsd_net *nn)
233+
-{
234+
- percpu_counter_inc(&nn->counter[NFSD_STATS_WDELEG_GETATTR]);
235+
-}
236+
+ unsigned int nfs4_opcount[LAST_NFS4_OP + 1]; /* count of individual nfsv4 operations */
237+
#endif
238+
+
239+
+};
240+
+
241+
+
242+
+extern struct nfsd_stats nfsdstats;
243+
+extern struct svc_stat nfsd_svcstats;
244+
+
245+
+void nfsd_stat_init(void);
246+
+void nfsd_stat_shutdown(void);
247+
+
248+
#endif /* _NFSD_STATS_H */
249+
* Unmerged path fs/nfsd/nfsctl.c
250+
* Unmerged path fs/nfsd/stats.c
251+
* Unmerged path fs/nfsd/stats.h

0 commit comments

Comments
 (0)