procfs_subr.c revision 1.110 1 /* $NetBSD: procfs_subr.c,v 1.110 2017/12/31 03:02:23 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.110 2017/12/31 03:02:23 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/vnode.h>
113 #include <sys/stat.h>
114 #include <sys/file.h>
115 #include <sys/filedesc.h>
116 #include <sys/kauth.h>
117 #include <sys/sysctl.h>
118
119 #include <miscfs/procfs/procfs.h>
120
121 /*
122 * Allocate a pfsnode/vnode pair. The vnode is referenced.
123 * The pid, type, and file descriptor uniquely identify a pfsnode.
124 */
125 int
126 procfs_allocvp(struct mount *mp, struct vnode **vpp, pid_t pid,
127 pfstype type, int fd)
128 {
129 struct pfskey key;
130
131 memset(&key, 0, sizeof(key));
132 key.pk_type = type;
133 key.pk_pid = pid;
134 key.pk_fd = fd;
135
136 return vcache_get(mp, &key, sizeof(key), vpp);
137 }
138
139 int
140 procfs_rw(void *v)
141 {
142 struct vop_read_args *ap = v;
143 struct vnode *vp = ap->a_vp;
144 struct uio *uio = ap->a_uio;
145 struct lwp *curl;
146 struct lwp *l;
147 struct pfsnode *pfs = VTOPFS(vp);
148 struct proc *p;
149 int error;
150
151 if (uio->uio_offset < 0)
152 return EINVAL;
153
154 if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
155 return error;
156
157 curl = curlwp;
158
159 /*
160 * Do not allow init to be modified while in secure mode; it
161 * could be duped into changing the security level.
162 */
163 #define M2K(m) ((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \
164 KAUTH_REQ_PROCESS_PROCFS_WRITE)
165 mutex_enter(p->p_lock);
166 error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS,
167 p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL);
168 mutex_exit(p->p_lock);
169 if (error) {
170 procfs_proc_unlock(p);
171 return (error);
172 }
173 #undef M2K
174
175 mutex_enter(p->p_lock);
176 LIST_FOREACH(l, &p->p_lwps, l_sibling) {
177 if (l->l_stat != LSZOMB)
178 break;
179 }
180 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */
181 if (l == NULL) {
182 mutex_exit(p->p_lock);
183 procfs_proc_unlock(p);
184 return ESRCH;
185 }
186
187 lwp_addref(l);
188 mutex_exit(p->p_lock);
189
190 switch (pfs->pfs_type) {
191 case PFSnote:
192 case PFSnotepg:
193 error = procfs_donote(curl, p, pfs, uio);
194 break;
195
196 case PFSregs:
197 error = procfs_doregs(curl, l, pfs, uio);
198 break;
199
200 case PFSfpregs:
201 error = procfs_dofpregs(curl, l, pfs, uio);
202 break;
203
204 case PFSstatus:
205 error = procfs_dostatus(curl, l, pfs, uio);
206 break;
207
208 case PFSstat:
209 error = procfs_do_pid_stat(curl, l, pfs, uio);
210 break;
211
212 case PFSmap:
213 error = procfs_domap(curl, p, pfs, uio, 0);
214 break;
215
216 case PFSmaps:
217 error = procfs_domap(curl, p, pfs, uio, 1);
218 break;
219
220 case PFSmem:
221 error = procfs_domem(curl, l, pfs, uio);
222 break;
223
224 case PFScmdline:
225 error = procfs_docmdline(curl, p, pfs, uio, KERN_PROC_ARGV);
226 break;
227
228 case PFSenviron:
229 error = procfs_docmdline(curl, p, pfs, uio, KERN_PROC_ENV);
230 break;
231
232 case PFSmeminfo:
233 error = procfs_domeminfo(curl, p, pfs, uio);
234 break;
235
236 case PFSdevices:
237 error = procfs_dodevices(curl, p, pfs, uio);
238 break;
239
240 case PFScpuinfo:
241 error = procfs_docpuinfo(curl, p, pfs, uio);
242 break;
243
244 case PFScpustat:
245 error = procfs_docpustat(curl, p, pfs, uio);
246 break;
247
248 case PFSloadavg:
249 error = procfs_doloadavg(curl, p, pfs, uio);
250 break;
251
252 case PFSstatm:
253 error = procfs_do_pid_statm(curl, l, pfs, uio);
254 break;
255
256 case PFSfd:
257 error = procfs_dofd(curl, p, pfs, uio);
258 break;
259
260 case PFSuptime:
261 error = procfs_douptime(curl, p, pfs, uio);
262 break;
263
264 case PFSmounts:
265 error = procfs_domounts(curl, p, pfs, uio);
266 break;
267
268 case PFSemul:
269 error = procfs_doemul(curl, p, pfs, uio);
270 break;
271
272 case PFSversion:
273 error = procfs_doversion(curl, p, pfs, uio);
274 break;
275
276 case PFSauxv:
277 error = procfs_doauxv(curl, p, pfs, uio);
278 break;
279
280 #ifdef __HAVE_PROCFS_MACHDEP
281 PROCFS_MACHDEP_NODETYPE_CASES
282 error = procfs_machdep_rw(curl, l, pfs, uio);
283 break;
284 #endif
285
286 default:
287 error = EOPNOTSUPP;
288 break;
289 }
290
291 /*
292 * Release the references that we acquired earlier.
293 */
294 lwp_delref(l);
295 procfs_proc_unlock(p);
296
297 return (error);
298 }
299
300 /*
301 * Get a string from userland into (bf). Strip a trailing
302 * nl character (to allow easy access from the shell).
303 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr
304 * will automatically add a nul char at the end.
305 *
306 * Returns 0 on success or the following errors
307 *
308 * EINVAL: file offset is non-zero.
309 * EMSGSIZE: message is longer than kernel buffer
310 * EFAULT: user i/o buffer is not addressable
311 */
312 int
313 vfs_getuserstr(struct uio *uio, char *bf, int *buflenp)
314 {
315 int xlen;
316 int error;
317
318 if (uio->uio_offset != 0)
319 return (EINVAL);
320
321 xlen = *buflenp;
322
323 /* must be able to read the whole string in one go */
324 if (xlen < uio->uio_resid)
325 return (EMSGSIZE);
326 xlen = uio->uio_resid;
327
328 if ((error = uiomove(bf, xlen, uio)) != 0)
329 return (error);
330
331 /* allow multiple writes without seeks */
332 uio->uio_offset = 0;
333
334 /* cleanup string and remove trailing newline */
335 bf[xlen] = '\0';
336 xlen = strlen(bf);
337 if (xlen > 0 && bf[xlen-1] == '\n')
338 bf[--xlen] = '\0';
339 *buflenp = xlen;
340
341 return (0);
342 }
343
344 const vfs_namemap_t *
345 vfs_findname(const vfs_namemap_t *nm, const char *bf, int buflen)
346 {
347
348 for (; nm->nm_name; nm++)
349 if (memcmp(bf, nm->nm_name, buflen+1) == 0)
350 return (nm);
351
352 return (0);
353 }
354
355 static bool
356 procfs_revoke_selector(void *arg, struct vnode *vp)
357 {
358 struct proc *p = arg;
359 struct pfsnode *pfs;
360
361 KASSERT(mutex_owned(vp->v_interlock));
362
363 pfs = VTOPFS(vp);
364
365 return (pfs != NULL && pfs->pfs_pid == p->p_pid);
366 }
367
368 void
369 procfs_revoke_vnodes(struct proc *p, void *arg)
370 {
371 struct vnode *vp;
372 struct vnode_iterator *marker;
373 struct mount *mp = (struct mount *)arg;
374
375 if (!(p->p_flag & PK_SUGID))
376 return;
377
378 vfs_vnode_iterator_init(mp, &marker);
379
380 while ((vp = vfs_vnode_iterator_next(marker,
381 procfs_revoke_selector, p)) != NULL) {
382 VOP_REVOKE(vp, REVOKEALL);
383 vrele(vp);
384 }
385
386 vfs_vnode_iterator_destroy(marker);
387 }
388
389 int
390 procfs_proc_lock(int pid, struct proc **bunghole, int notfound)
391 {
392 struct proc *tp;
393 int error = 0;
394
395 mutex_enter(proc_lock);
396
397 if (pid == 0)
398 tp = &proc0;
399 else if ((tp = proc_find(pid)) == NULL)
400 error = notfound;
401 if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER))
402 error = EBUSY;
403
404 mutex_exit(proc_lock);
405
406 *bunghole = tp;
407 return error;
408 }
409
410 void
411 procfs_proc_unlock(struct proc *p)
412 {
413
414 rw_exit(&p->p_reflock);
415 }
416
417 int
418 procfs_doemul(struct lwp *curl, struct proc *p,
419 struct pfsnode *pfs, struct uio *uio)
420 {
421 const char *ename = p->p_emul->e_name;
422 return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio);
423 }
424