1 /* $NetBSD: procfs_subr.c,v 1.104 2014/02/07 15:29:22 hannken 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.104 2014/02/07 15:29:22 hannken 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/malloc.h> 114 #include <sys/stat.h> 115 #include <sys/file.h> 116 #include <sys/filedesc.h> 117 #include <sys/kauth.h> 118 119 #include <miscfs/procfs/procfs.h> 120 121 void procfs_hashins(struct pfsnode *); 122 void procfs_hashrem(struct pfsnode *); 123 struct vnode *procfs_hashget(pid_t, pfstype, int, struct mount *); 124 125 LIST_HEAD(pfs_hashhead, pfsnode) *pfs_hashtbl; 126 u_long pfs_ihash; /* size of hash table - 1 */ 127 #define PFSPIDHASH(pid) ((pid) & pfs_ihash) 128 129 kmutex_t pfs_hashlock; 130 kmutex_t pfs_ihash_lock; 131 132 #define ISSET(t, f) ((t) & (f)) 133 134 /* 135 * allocate a pfsnode/vnode pair. the vnode is 136 * referenced, and locked. 137 * 138 * the pid, pfs_type, and mount point uniquely 139 * identify a pfsnode. the mount point is needed 140 * because someone might mount this filesystem 141 * twice. 142 * 143 * all pfsnodes are maintained on a singly-linked 144 * list. new nodes are only allocated when they cannot 145 * be found on this list. entries on the list are 146 * removed when the vfs reclaim entry is called. 147 * 148 * a single lock is kept for the entire list. this is 149 * needed because the getnewvnode() function can block 150 * waiting for a vnode to become free, in which case there 151 * may be more than one process trying to get the same 152 * vnode. this lock is only taken if we are going to 153 * call getnewvnode, since the kernel itself is single-threaded. 154 * 155 * if an entry is found on the list, then call vget() to 156 * take a reference. this is done because there may be 157 * zero references to it and so it needs to removed from 158 * the vnode free list. 159 */ 160 int 161 procfs_allocvp(struct mount *mp, struct vnode **vpp, pid_t pid, 162 pfstype pfs_type, int fd, struct proc *p) 163 { 164 struct pfsnode *pfs; 165 struct vnode *vp; 166 int error; 167 168 *vpp = procfs_hashget(pid, pfs_type, fd, mp); 169 if (*vpp != NULL) 170 return (0); 171 172 error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, NULL, &vp); 173 if (error) { 174 *vpp = NULL; 175 return (error); 176 } 177 pfs = malloc(sizeof(struct pfsnode), M_TEMP, M_WAITOK); 178 179 mutex_enter(&pfs_hashlock); 180 if ((*vpp = procfs_hashget(pid, pfs_type, fd, mp)) != NULL) { 181 mutex_exit(&pfs_hashlock); 182 ungetnewvnode(vp); 183 free(pfs, M_TEMP); 184 return 0; 185 } 186 187 vp->v_data = pfs; 188 pfs->pfs_pid = pid; 189 pfs->pfs_type = pfs_type; 190 pfs->pfs_vnode = vp; 191 pfs->pfs_flags = 0; 192 pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type, fd); 193 pfs->pfs_fd = fd; 194 195 switch (pfs_type) { 196 case PFSroot: /* /proc = dr-xr-xr-x */ 197 vp->v_vflag |= VV_ROOT; 198 /*FALLTHROUGH*/ 199 case PFSproc: /* /proc/N = dr-xr-xr-x */ 200 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 201 vp->v_type = VDIR; 202 break; 203 204 case PFStask: /* /proc/N/task = dr-xr-xr-x */ 205 if (fd == -1) { 206 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP| 207 S_IROTH|S_IXOTH; 208 vp->v_type = VDIR; 209 break; 210 } 211 /*FALLTHROUGH*/ 212 case PFScurproc: /* /proc/curproc = lr-xr-xr-x */ 213 case PFSself: /* /proc/self = lr-xr-xr-x */ 214 case PFScwd: /* /proc/N/cwd = lr-xr-xr-x */ 215 case PFSchroot: /* /proc/N/chroot = lr-xr-xr-x */ 216 case PFSexe: /* /proc/N/exe = lr-xr-xr-x */ 217 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 218 vp->v_type = VLNK; 219 break; 220 221 case PFSfd: 222 if (fd == -1) { /* /proc/N/fd = dr-x------ */ 223 pfs->pfs_mode = S_IRUSR|S_IXUSR; 224 vp->v_type = VDIR; 225 } else { /* /proc/N/fd/M = [ps-]rw------- */ 226 file_t *fp; 227 vnode_t *vxp; 228 229 if ((fp = fd_getfile2(p, pfs->pfs_fd)) == NULL) { 230 error = EBADF; 231 goto bad; 232 } 233 234 pfs->pfs_mode = S_IRUSR|S_IWUSR; 235 switch (fp->f_type) { 236 case DTYPE_VNODE: 237 vxp = fp->f_data; 238 239 /* 240 * We make symlinks for directories 241 * to avoid cycles. 242 */ 243 if (vxp->v_type == VDIR) 244 goto symlink; 245 vp->v_type = vxp->v_type; 246 break; 247 case DTYPE_PIPE: 248 vp->v_type = VFIFO; 249 break; 250 case DTYPE_SOCKET: 251 vp->v_type = VSOCK; 252 break; 253 case DTYPE_KQUEUE: 254 case DTYPE_MISC: 255 case DTYPE_SEM: 256 symlink: 257 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP| 258 S_IXGRP|S_IROTH|S_IXOTH; 259 vp->v_type = VLNK; 260 break; 261 default: 262 error = EOPNOTSUPP; 263 closef(fp); 264 goto bad; 265 } 266 closef(fp); 267 } 268 break; 269 270 case PFSfile: /* /proc/N/file = -rw------- */ 271 case PFSmem: /* /proc/N/mem = -rw------- */ 272 case PFSregs: /* /proc/N/regs = -rw------- */ 273 case PFSfpregs: /* /proc/N/fpregs = -rw------- */ 274 pfs->pfs_mode = S_IRUSR|S_IWUSR; 275 vp->v_type = VREG; 276 break; 277 278 case PFSctl: /* /proc/N/ctl = --w------ */ 279 case PFSnote: /* /proc/N/note = --w------ */ 280 case PFSnotepg: /* /proc/N/notepg = --w------ */ 281 pfs->pfs_mode = S_IWUSR; 282 vp->v_type = VREG; 283 break; 284 285 case PFSmap: /* /proc/N/map = -r--r--r-- */ 286 case PFSmaps: /* /proc/N/maps = -r--r--r-- */ 287 case PFSstatus: /* /proc/N/status = -r--r--r-- */ 288 case PFSstat: /* /proc/N/stat = -r--r--r-- */ 289 case PFScmdline: /* /proc/N/cmdline = -r--r--r-- */ 290 case PFSemul: /* /proc/N/emul = -r--r--r-- */ 291 case PFSmeminfo: /* /proc/meminfo = -r--r--r-- */ 292 case PFScpustat: /* /proc/stat = -r--r--r-- */ 293 case PFSdevices: /* /proc/devices = -r--r--r-- */ 294 case PFScpuinfo: /* /proc/cpuinfo = -r--r--r-- */ 295 case PFSuptime: /* /proc/uptime = -r--r--r-- */ 296 case PFSmounts: /* /proc/mounts = -r--r--r-- */ 297 case PFSloadavg: /* /proc/loadavg = -r--r--r-- */ 298 case PFSstatm: /* /proc/N/statm = -r--r--r-- */ 299 case PFSversion: /* /proc/version = -r--r--r-- */ 300 pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH; 301 vp->v_type = VREG; 302 break; 303 304 #ifdef __HAVE_PROCFS_MACHDEP 305 PROCFS_MACHDEP_NODETYPE_CASES 306 procfs_machdep_allocvp(vp); 307 break; 308 #endif 309 310 default: 311 panic("procfs_allocvp"); 312 } 313 314 procfs_hashins(pfs); 315 uvm_vnp_setsize(vp, 0); 316 mutex_exit(&pfs_hashlock); 317 318 *vpp = vp; 319 return (0); 320 321 bad: 322 mutex_exit(&pfs_hashlock); 323 free(pfs, M_TEMP); 324 vp->v_data = NULL; 325 ungetnewvnode(vp); 326 return (error); 327 } 328 329 int 330 procfs_freevp(struct vnode *vp) 331 { 332 struct pfsnode *pfs = VTOPFS(vp); 333 334 procfs_hashrem(pfs); 335 336 free(vp->v_data, M_TEMP); 337 vp->v_data = NULL; 338 return (0); 339 } 340 341 int 342 procfs_rw(void *v) 343 { 344 struct vop_read_args *ap = v; 345 struct vnode *vp = ap->a_vp; 346 struct uio *uio = ap->a_uio; 347 struct lwp *curl; 348 struct lwp *l; 349 struct pfsnode *pfs = VTOPFS(vp); 350 struct proc *p; 351 int error; 352 353 if (uio->uio_offset < 0) 354 return EINVAL; 355 356 if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0) 357 return error; 358 359 curl = curlwp; 360 361 /* 362 * Do not allow init to be modified while in secure mode; it 363 * could be duped into changing the security level. 364 */ 365 #define M2K(m) ((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \ 366 KAUTH_REQ_PROCESS_PROCFS_WRITE) 367 mutex_enter(p->p_lock); 368 error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS, 369 p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL); 370 mutex_exit(p->p_lock); 371 if (error) { 372 procfs_proc_unlock(p); 373 return (error); 374 } 375 #undef M2K 376 377 mutex_enter(p->p_lock); 378 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 379 if (l->l_stat != LSZOMB) 380 break; 381 } 382 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */ 383 if (l == NULL) { 384 mutex_exit(p->p_lock); 385 procfs_proc_unlock(p); 386 return ESRCH; 387 } 388 389 lwp_addref(l); 390 mutex_exit(p->p_lock); 391 392 switch (pfs->pfs_type) { 393 case PFSnote: 394 case PFSnotepg: 395 error = procfs_donote(curl, p, pfs, uio); 396 break; 397 398 case PFSregs: 399 error = procfs_doregs(curl, l, pfs, uio); 400 break; 401 402 case PFSfpregs: 403 error = procfs_dofpregs(curl, l, pfs, uio); 404 break; 405 406 case PFSctl: 407 error = procfs_doctl(curl, l, pfs, uio); 408 break; 409 410 case PFSstatus: 411 error = procfs_dostatus(curl, l, pfs, uio); 412 break; 413 414 case PFSstat: 415 error = procfs_do_pid_stat(curl, l, pfs, uio); 416 break; 417 418 case PFSmap: 419 error = procfs_domap(curl, p, pfs, uio, 0); 420 break; 421 422 case PFSmaps: 423 error = procfs_domap(curl, p, pfs, uio, 1); 424 break; 425 426 case PFSmem: 427 error = procfs_domem(curl, l, pfs, uio); 428 break; 429 430 case PFScmdline: 431 error = procfs_docmdline(curl, p, pfs, uio); 432 break; 433 434 case PFSmeminfo: 435 error = procfs_domeminfo(curl, p, pfs, uio); 436 break; 437 438 case PFSdevices: 439 error = procfs_dodevices(curl, p, pfs, uio); 440 break; 441 442 case PFScpuinfo: 443 error = procfs_docpuinfo(curl, p, pfs, uio); 444 break; 445 446 case PFScpustat: 447 error = procfs_docpustat(curl, p, pfs, uio); 448 break; 449 450 case PFSloadavg: 451 error = procfs_doloadavg(curl, p, pfs, uio); 452 break; 453 454 case PFSstatm: 455 error = procfs_do_pid_statm(curl, l, pfs, uio); 456 break; 457 458 case PFSfd: 459 error = procfs_dofd(curl, p, pfs, uio); 460 break; 461 462 case PFSuptime: 463 error = procfs_douptime(curl, p, pfs, uio); 464 break; 465 466 case PFSmounts: 467 error = procfs_domounts(curl, p, pfs, uio); 468 break; 469 470 case PFSemul: 471 error = procfs_doemul(curl, p, pfs, uio); 472 break; 473 474 case PFSversion: 475 error = procfs_doversion(curl, p, pfs, uio); 476 break; 477 478 #ifdef __HAVE_PROCFS_MACHDEP 479 PROCFS_MACHDEP_NODETYPE_CASES 480 error = procfs_machdep_rw(curl, l, pfs, uio); 481 break; 482 #endif 483 484 default: 485 error = EOPNOTSUPP; 486 break; 487 } 488 489 /* 490 * Release the references that we acquired earlier. 491 */ 492 lwp_delref(l); 493 procfs_proc_unlock(p); 494 495 return (error); 496 } 497 498 /* 499 * Get a string from userland into (bf). Strip a trailing 500 * nl character (to allow easy access from the shell). 501 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr 502 * will automatically add a nul char at the end. 503 * 504 * Returns 0 on success or the following errors 505 * 506 * EINVAL: file offset is non-zero. 507 * EMSGSIZE: message is longer than kernel buffer 508 * EFAULT: user i/o buffer is not addressable 509 */ 510 int 511 vfs_getuserstr(struct uio *uio, char *bf, int *buflenp) 512 { 513 int xlen; 514 int error; 515 516 if (uio->uio_offset != 0) 517 return (EINVAL); 518 519 xlen = *buflenp; 520 521 /* must be able to read the whole string in one go */ 522 if (xlen < uio->uio_resid) 523 return (EMSGSIZE); 524 xlen = uio->uio_resid; 525 526 if ((error = uiomove(bf, xlen, uio)) != 0) 527 return (error); 528 529 /* allow multiple writes without seeks */ 530 uio->uio_offset = 0; 531 532 /* cleanup string and remove trailing newline */ 533 bf[xlen] = '\0'; 534 xlen = strlen(bf); 535 if (xlen > 0 && bf[xlen-1] == '\n') 536 bf[--xlen] = '\0'; 537 *buflenp = xlen; 538 539 return (0); 540 } 541 542 const vfs_namemap_t * 543 vfs_findname(const vfs_namemap_t *nm, const char *bf, int buflen) 544 { 545 546 for (; nm->nm_name; nm++) 547 if (memcmp(bf, nm->nm_name, buflen+1) == 0) 548 return (nm); 549 550 return (0); 551 } 552 553 /* 554 * Initialize pfsnode hash table. 555 */ 556 void 557 procfs_hashinit(void) 558 { 559 mutex_init(&pfs_hashlock, MUTEX_DEFAULT, IPL_NONE); 560 mutex_init(&pfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE); 561 pfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, true, &pfs_ihash); 562 } 563 564 void 565 procfs_hashreinit(void) 566 { 567 struct pfsnode *pp; 568 struct pfs_hashhead *oldhash, *hash; 569 u_long i, oldmask, mask, val; 570 571 hash = hashinit(desiredvnodes / 4, HASH_LIST, true, &mask); 572 573 mutex_enter(&pfs_ihash_lock); 574 oldhash = pfs_hashtbl; 575 oldmask = pfs_ihash; 576 pfs_hashtbl = hash; 577 pfs_ihash = mask; 578 for (i = 0; i <= oldmask; i++) { 579 while ((pp = LIST_FIRST(&oldhash[i])) != NULL) { 580 LIST_REMOVE(pp, pfs_hash); 581 val = PFSPIDHASH(pp->pfs_pid); 582 LIST_INSERT_HEAD(&hash[val], pp, pfs_hash); 583 } 584 } 585 mutex_exit(&pfs_ihash_lock); 586 hashdone(oldhash, HASH_LIST, oldmask); 587 } 588 589 /* 590 * Free pfsnode hash table. 591 */ 592 void 593 procfs_hashdone(void) 594 { 595 hashdone(pfs_hashtbl, HASH_LIST, pfs_ihash); 596 mutex_destroy(&pfs_hashlock); 597 mutex_destroy(&pfs_ihash_lock); 598 } 599 600 struct vnode * 601 procfs_hashget(pid_t pid, pfstype type, int fd, struct mount *mp) 602 { 603 struct pfs_hashhead *ppp; 604 struct pfsnode *pp; 605 struct vnode *vp; 606 607 loop: 608 mutex_enter(&pfs_ihash_lock); 609 ppp = &pfs_hashtbl[PFSPIDHASH(pid)]; 610 LIST_FOREACH(pp, ppp, pfs_hash) { 611 vp = PFSTOV(pp); 612 if (pid == pp->pfs_pid && pp->pfs_type == type && 613 pp->pfs_fd == fd && vp->v_mount == mp) { 614 mutex_enter(vp->v_interlock); 615 mutex_exit(&pfs_ihash_lock); 616 if (vget(vp, 0)) 617 goto loop; 618 return (vp); 619 } 620 } 621 mutex_exit(&pfs_ihash_lock); 622 return (NULL); 623 } 624 625 /* 626 * Insert the pfsnode into the hash table and lock it. 627 */ 628 void 629 procfs_hashins(struct pfsnode *pp) 630 { 631 struct pfs_hashhead *ppp; 632 633 mutex_enter(&pfs_ihash_lock); 634 ppp = &pfs_hashtbl[PFSPIDHASH(pp->pfs_pid)]; 635 LIST_INSERT_HEAD(ppp, pp, pfs_hash); 636 mutex_exit(&pfs_ihash_lock); 637 } 638 639 /* 640 * Remove the pfsnode from the hash table. 641 */ 642 void 643 procfs_hashrem(struct pfsnode *pp) 644 { 645 mutex_enter(&pfs_ihash_lock); 646 LIST_REMOVE(pp, pfs_hash); 647 mutex_exit(&pfs_ihash_lock); 648 } 649 650 void 651 procfs_revoke_vnodes(struct proc *p, void *arg) 652 { 653 struct pfsnode *pfs, *pnext; 654 struct vnode *vp; 655 struct mount *mp = (struct mount *)arg; 656 struct pfs_hashhead *ppp; 657 658 if (!(p->p_flag & PK_SUGID)) 659 return; 660 661 mutex_enter(&pfs_ihash_lock); 662 ppp = &pfs_hashtbl[PFSPIDHASH(p->p_pid)]; 663 for (pfs = LIST_FIRST(ppp); pfs; pfs = pnext) { 664 vp = PFSTOV(pfs); 665 pnext = LIST_NEXT(pfs, pfs_hash); 666 if (pfs->pfs_pid != p->p_pid || vp->v_mount != mp) 667 continue; 668 mutex_enter(vp->v_interlock); 669 mutex_exit(&pfs_ihash_lock); 670 if (vget(vp, 0) != 0) { 671 mutex_enter(&pfs_ihash_lock); 672 continue; 673 } 674 VOP_REVOKE(vp, REVOKEALL); 675 vrele(vp); 676 mutex_enter(&pfs_ihash_lock); 677 } 678 mutex_exit(&pfs_ihash_lock); 679 } 680 681 int 682 procfs_proc_lock(int pid, struct proc **bunghole, int notfound) 683 { 684 struct proc *tp; 685 int error = 0; 686 687 mutex_enter(proc_lock); 688 689 if (pid == 0) 690 tp = &proc0; 691 else if ((tp = proc_find(pid)) == NULL) 692 error = notfound; 693 if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER)) 694 error = EBUSY; 695 696 mutex_exit(proc_lock); 697 698 *bunghole = tp; 699 return error; 700 } 701 702 void 703 procfs_proc_unlock(struct proc *p) 704 { 705 706 rw_exit(&p->p_reflock); 707 } 708 709 int 710 procfs_doemul(struct lwp *curl, struct proc *p, 711 struct pfsnode *pfs, struct uio *uio) 712 { 713 const char *ename = p->p_emul->e_name; 714 return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio); 715 } 716