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