1 /* $NetBSD: procfs_subr.c,v 1.120 2024/07/01 01:35:53 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Jan-Simon Pendry.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
64 */
65
66 /*
67 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
68 * Copyright (c) 1993 Jan-Simon Pendry
69 *
70 * This code is derived from software contributed to Berkeley by
71 * Jan-Simon Pendry.
72 *
73 * Redistribution and use in source and binary forms, with or without
74 * modification, are permitted provided that the following conditions
75 * are met:
76 * 1. Redistributions of source code must retain the above copyright
77 * notice, this list of conditions and the following disclaimer.
78 * 2. Redistributions in binary form must reproduce the above copyright
79 * notice, this list of conditions and the following disclaimer in the
80 * documentation and/or other materials provided with the distribution.
81 * 3. All advertising materials mentioning features or use of this software
82 * must display the following acknowledgement:
83 * This product includes software developed by the University of
84 * California, Berkeley and its contributors.
85 * 4. Neither the name of the University nor the names of its contributors
86 * may be used to endorse or promote products derived from this software
87 * without specific prior written permission.
88 *
89 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
90 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
91 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
92 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
93 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
94 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
95 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
96 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
97 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
98 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99 * SUCH DAMAGE.
100 *
101 * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
102 */
103
104 #include <sys/cdefs.h>
105 __KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.120 2024/07/01 01:35:53 christos Exp $");
106
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/time.h>
110 #include <sys/kernel.h>
111 #include <sys/proc.h>
112 #include <sys/fstrans.h>
113 #include <sys/vnode.h>
114 #include <sys/stat.h>
115 #include <sys/file.h>
116 #include <sys/filedesc.h>
117 #include <sys/kauth.h>
118 #include <sys/sysctl.h>
119
120 #include <miscfs/procfs/procfs.h>
121
122 /*
123 * Allocate a pfsnode/vnode pair. The vnode is referenced.
124 * The pid, type, and file descriptor uniquely identify a pfsnode.
125 */
126 int
procfs_allocvp(struct mount * mp,struct vnode ** vpp,pid_t pid,pfstype type,int fd)127 procfs_allocvp(struct mount *mp, struct vnode **vpp, pid_t pid,
128 pfstype type, int fd)
129 {
130 struct pfskey key;
131
132 memset(&key, 0, sizeof(key));
133 key.pk_type = type;
134 key.pk_pid = pid;
135 key.pk_fd = fd;
136
137 return vcache_get(mp, &key, sizeof(key), vpp);
138 }
139
140 int
procfs_rw(void * v)141 procfs_rw(void *v)
142 {
143 struct vop_read_args *ap = v;
144 struct vnode *vp = ap->a_vp;
145 struct uio *uio = ap->a_uio;
146 struct lwp *curl;
147 struct lwp *l;
148 struct pfsnode *pfs = VTOPFS(vp);
149 struct proc *p;
150 int error;
151
152 if (uio->uio_offset < 0)
153 return EINVAL;
154
155 if ((error =
156 procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH)) != 0)
157 return error;
158
159 curl = curlwp;
160
161 /*
162 * Do not allow init to be modified while in secure mode; it
163 * could be duped into changing the security level.
164 */
165 #define M2K(m) ((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \
166 KAUTH_REQ_PROCESS_PROCFS_WRITE)
167 mutex_enter(p->p_lock);
168 error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS,
169 p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL);
170 mutex_exit(p->p_lock);
171 if (error) {
172 procfs_proc_unlock(p);
173 return (error);
174 }
175 #undef M2K
176
177 mutex_enter(p->p_lock);
178 LIST_FOREACH(l, &p->p_lwps, l_sibling) {
179 if (l->l_stat != LSZOMB)
180 break;
181 }
182 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */
183 if (l == NULL) {
184 mutex_exit(p->p_lock);
185 procfs_proc_unlock(p);
186 return ESRCH;
187 }
188
189 lwp_addref(l);
190 mutex_exit(p->p_lock);
191
192 switch (pfs->pfs_type) {
193 case PFSnote:
194 case PFSnotepg:
195 error = procfs_donote(curl, p, pfs, uio);
196 break;
197
198 case PFSregs:
199 error = procfs_doregs(curl, l, pfs, uio);
200 break;
201
202 case PFSfpregs:
203 error = procfs_dofpregs(curl, l, pfs, uio);
204 break;
205
206 case PFSstatus:
207 error = procfs_dostatus(curl, l, pfs, uio);
208 break;
209
210 case PFSstat:
211 error = procfs_do_pid_stat(curl, l, pfs, uio);
212 break;
213
214 case PFSlimit:
215 error = procfs_dolimit(curl, p, pfs, uio);
216 break;
217
218 case PFSlimits:
219 error = procfs_dolimits(curl, p, pfs, uio);
220 break;
221
222 case PFSmap:
223 error = procfs_domap(curl, p, pfs, uio, 0);
224 break;
225
226 case PFSmaps:
227 error = procfs_domap(curl, p, pfs, uio, 1);
228 break;
229
230 case PFSmem:
231 error = procfs_domem(curl, l, pfs, uio);
232 break;
233
234 case PFScmdline:
235 error = procfs_doprocargs(curl, p, pfs, uio, KERN_PROC_ARGV);
236 break;
237
238 case PFSenviron:
239 error = procfs_doprocargs(curl, p, pfs, uio, KERN_PROC_ENV);
240 break;
241
242 case PFSmeminfo:
243 error = procfs_domeminfo(curl, p, pfs, uio);
244 break;
245
246 case PFSdevices:
247 error = procfs_dodevices(curl, p, pfs, uio);
248 break;
249
250 case PFScpuinfo:
251 error = procfs_docpuinfo(curl, p, pfs, uio);
252 break;
253
254 case PFScpustat:
255 error = procfs_docpustat(curl, p, pfs, uio);
256 break;
257
258 case PFSloadavg:
259 error = procfs_doloadavg(curl, p, pfs, uio);
260 break;
261
262 case PFSstatm:
263 error = procfs_do_pid_statm(curl, l, pfs, uio);
264 break;
265
266 case PFSfd:
267 error = procfs_dofd(curl, p, pfs, uio);
268 break;
269
270 case PFSuptime:
271 error = procfs_douptime(curl, p, pfs, uio);
272 break;
273
274 case PFSmounts:
275 error = procfs_domounts(curl, p, pfs, uio);
276 break;
277
278 case PFSemul:
279 error = procfs_doemul(curl, p, pfs, uio);
280 break;
281
282 case PFSversion:
283 error = procfs_doversion(curl, p, pfs, uio);
284 break;
285
286 case PFSauxv:
287 error = procfs_doauxv(curl, p, pfs, uio);
288 break;
289
290 case PFSsysvipc_msg:
291 error = procfs_dosysvipc_msg(curl, p, pfs, uio);
292 break;
293
294 case PFSsysvipc_sem:
295 error = procfs_dosysvipc_sem(curl, p, pfs, uio);
296 break;
297
298 case PFSsysvipc_shm:
299 error = procfs_dosysvipc_shm(curl, p, pfs, uio);
300 break;
301
302 case PFSmq_msg_def:
303 error = procfs_domq_msg_def(curl, p, pfs, uio);
304 break;
305
306 case PFSmq_msg_max:
307 error = procfs_domq_msg_max(curl, p, pfs, uio);
308 break;
309
310 case PFSmq_siz_def:
311 error = procfs_domq_siz_def(curl, p, pfs, uio);
312 break;
313
314 case PFSmq_siz_max:
315 error = procfs_domq_siz_max(curl, p, pfs, uio);
316 break;
317
318 case PFSmq_qmax:
319 error = procfs_domq_qmax(curl, p, pfs, uio);
320 break;
321
322 #ifdef __HAVE_PROCFS_MACHDEP
323 PROCFS_MACHDEP_NODETYPE_CASES
324 error = procfs_machdep_rw(curl, l, pfs, uio);
325 break;
326 #endif
327
328 default:
329 error = EOPNOTSUPP;
330 break;
331 }
332
333 /*
334 * Release the references that we acquired earlier.
335 */
336 lwp_delref(l);
337 procfs_proc_unlock(p);
338
339 return (error);
340 }
341
342 /*
343 * Get a string from userland into (bf). Strip a trailing
344 * nl character (to allow easy access from the shell).
345 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr
346 * will automatically add a nul char at the end.
347 *
348 * Returns 0 on success or the following errors
349 *
350 * EINVAL: file offset is non-zero.
351 * EMSGSIZE: message is longer than kernel buffer
352 * EFAULT: user i/o buffer is not addressable
353 */
354 int
vfs_getuserstr(struct uio * uio,char * bf,int * buflenp)355 vfs_getuserstr(struct uio *uio, char *bf, int *buflenp)
356 {
357 size_t xlen;
358 int error;
359
360 if (uio->uio_offset != 0)
361 return (EINVAL);
362
363 xlen = *buflenp;
364
365 /* must be able to read the whole string in one go */
366 if (xlen < uio->uio_resid)
367 return (EMSGSIZE);
368 xlen = uio->uio_resid;
369
370 if ((error = uiomove(bf, xlen, uio)) != 0)
371 return (error);
372
373 /* allow multiple writes without seeks */
374 uio->uio_offset = 0;
375
376 /* cleanup string and remove trailing newline */
377 bf[xlen] = '\0';
378 xlen = strlen(bf);
379 if (xlen > 0 && bf[xlen-1] == '\n')
380 bf[--xlen] = '\0';
381 *buflenp = xlen;
382
383 return (0);
384 }
385
386 const vfs_namemap_t *
vfs_findname(const vfs_namemap_t * nm,const char * bf,int buflen)387 vfs_findname(const vfs_namemap_t *nm, const char *bf, int buflen)
388 {
389
390 for (; nm->nm_name; nm++)
391 if (memcmp(bf, nm->nm_name, buflen+1) == 0)
392 return (nm);
393
394 return (0);
395 }
396
397 bool
procfs_use_linux_compat(struct mount * mp)398 procfs_use_linux_compat(struct mount *mp)
399 {
400 const int flags = VFSTOPROC(mp)->pmnt_flags;
401
402 return (flags & PROCFSMNT_LINUXCOMPAT) ? true : false;
403 }
404
405 struct proc *
procfs_proc_find(struct mount * mp,pid_t pid)406 procfs_proc_find(struct mount *mp, pid_t pid)
407 {
408
409 KASSERT(mutex_owned(&proc_lock));
410 return procfs_use_linux_compat(mp) ? proc_find_lwpid(pid)
411 : proc_find(pid);
412 }
413
414 int
procfs_proc_lock(struct mount * mp,int pid,struct proc ** bunghole,int notfound)415 procfs_proc_lock(struct mount *mp, int pid, struct proc **bunghole,
416 int notfound)
417 {
418 struct proc *tp;
419 int error = 0;
420
421 mutex_enter(&proc_lock);
422
423 if (pid == 0)
424 tp = &proc0;
425 else if ((tp = procfs_proc_find(mp, pid)) == NULL)
426 error = notfound;
427 if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER))
428 error = EBUSY;
429
430 mutex_exit(&proc_lock);
431
432 *bunghole = tp;
433 return error;
434 }
435
436 void
procfs_proc_unlock(struct proc * p)437 procfs_proc_unlock(struct proc *p)
438 {
439
440 rw_exit(&p->p_reflock);
441 }
442
443 int
procfs_doemul(struct lwp * curl,struct proc * p,struct pfsnode * pfs,struct uio * uio)444 procfs_doemul(struct lwp *curl, struct proc *p,
445 struct pfsnode *pfs, struct uio *uio)
446 {
447 const char *ename = p->p_emul->e_name;
448 return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio);
449 }
450