1 /* $NetBSD: procfs_subr.c,v 1.111 2017/12/31 03:29:18 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.111 2017/12/31 03:29:18 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_doprocargs(curl, p, pfs, uio, KERN_PROC_ARGV); 226 break; 227 228 case PFSenviron: 229 error = procfs_doprocargs(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