1 /* $OpenBSD: kern_unveil.c,v 1.15 2018/09/25 19:24:17 jasper Exp $ */ 2 3 /* 4 * Copyright (c) 2017-2018 Bob Beck <beck@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 21 #include <sys/mount.h> 22 #include <sys/proc.h> 23 #include <sys/namei.h> 24 #include <sys/pool.h> 25 #include <sys/vnode.h> 26 #include <sys/ktrace.h> 27 #include <sys/types.h> 28 #include <sys/malloc.h> 29 #include <sys/tree.h> 30 31 #include <sys/conf.h> 32 #include <sys/syscall.h> 33 #include <sys/syscallargs.h> 34 #include <sys/systm.h> 35 36 #include <sys/pledge.h> 37 38 /* #define DEBUG_UNVEIL */ 39 40 #define UNVEIL_MAX_VNODES 128 41 #define UNVEIL_MAX_NAMES 128 42 43 static inline int 44 unvname_compare(const struct unvname *n1, const struct unvname *n2) 45 { 46 if (n1->un_namesize == n2->un_namesize) 47 return (memcmp(n1->un_name, n2->un_name, n1->un_namesize)); 48 else 49 return (n1->un_namesize - n2->un_namesize); 50 } 51 52 struct unvname * 53 unvname_new(const char *name, size_t size, u_char flags) 54 { 55 struct unvname *ret = malloc(sizeof(struct unvname), M_PROC, M_WAITOK); 56 ret->un_name = malloc(size, M_PROC, M_WAITOK); 57 memcpy(ret->un_name, name, size); 58 ret->un_namesize = size; 59 ret->un_flags = flags; 60 return ret; 61 } 62 63 void 64 unveil_free_traversed_vnodes(struct nameidata *ndp) 65 { 66 if (ndp->ni_tvpsize) { 67 size_t i; 68 69 for (i = 0; i < ndp->ni_tvpend; i++) 70 vrele(ndp->ni_tvp[i]); /* ref for being in list */ 71 free(ndp->ni_tvp, M_PROC, ndp->ni_tvpsize * sizeof(struct vnode *)); 72 ndp->ni_tvpsize = 0; 73 ndp->ni_tvpend = 0; 74 } 75 } 76 77 void 78 unveil_save_traversed_vnode(struct nameidata *ndp, struct vnode *vp) 79 { 80 if (ndp->ni_tvpsize == 0) { 81 ndp->ni_tvp = mallocarray(MAXPATHLEN, sizeof(struct vnode *), 82 M_PROC, M_WAITOK); 83 ndp->ni_tvpsize = MAXPATHLEN; 84 } 85 /* This should be limited by MAXPATHLEN on a single lookup */ 86 KASSERT(ndp->ni_tvpsize > ndp->ni_tvpend); 87 vref(vp); /* ref for being in the list */ 88 ndp->ni_tvp[ndp->ni_tvpend++] = vp; 89 } 90 91 void 92 unvname_delete(struct unvname *name) 93 { 94 free(name->un_name, M_PROC, name->un_namesize);; 95 free(name, M_PROC, sizeof(struct unvname)); 96 } 97 98 RBT_PROTOTYPE(unvname_rbt, unvname, un_rbt, unvname_compare); 99 RBT_GENERATE(unvname_rbt, unvname, un_rbt, unvname_compare); 100 101 int 102 unveil_delete_names(struct unveil *uv) 103 { 104 struct unvname *unvn, *next; 105 int ret = 0; 106 107 rw_enter_write(&uv->uv_lock); 108 RBT_FOREACH_SAFE(unvn, unvname_rbt, &uv->uv_names, next) { 109 RBT_REMOVE(unvname_rbt, &uv->uv_names, unvn); 110 unvname_delete(unvn); 111 ret++; 112 } 113 rw_exit_write(&uv->uv_lock); 114 #ifdef DEBUG_UNVEIL 115 printf("deleted %d names\n", ret); 116 #endif 117 return ret; 118 } 119 120 void 121 unveil_add_name(struct unveil *uv, char *name, u_char flags) 122 { 123 struct unvname *unvn; 124 125 rw_enter_write(&uv->uv_lock); 126 unvn = unvname_new(name, strlen(name) + 1, flags); 127 RBT_INSERT(unvname_rbt, &uv->uv_names, unvn); 128 rw_exit_write(&uv->uv_lock); 129 #ifdef DEBUG_UNVEIL 130 printf("added name %s underneath vnode %p\n", name, uv->uv_vp); 131 #endif 132 } 133 134 struct unvname * 135 unveil_namelookup(struct unveil *uv, char *name) 136 { 137 struct unvname n, *ret = NULL; 138 139 rw_enter_read(&uv->uv_lock); 140 141 #ifdef DEBUG_UNVEIL 142 printf("unveil_namelookup: looking up name %s (%p) in vnode %p\n", 143 name, name, uv->uv_vp); 144 #endif 145 146 KASSERT(uv->uv_vp != NULL); 147 148 n.un_name = name; 149 n.un_namesize = strlen(name) + 1; 150 151 ret = RBT_FIND(unvname_rbt, &uv->uv_names, &n); 152 153 rw_exit_read(&uv->uv_lock); 154 155 #ifdef DEBUG_UNVEIL 156 if (ret == NULL) 157 printf("unveil_namelookup: no match for name %s in vnode %p\n", 158 name, uv->uv_vp); 159 else 160 printf("unveil_namelookup: matched name %s in vnode %p\n", 161 name, uv->uv_vp); 162 #endif 163 return ret; 164 } 165 166 void 167 unveil_destroy(struct process *ps) 168 { 169 size_t i; 170 171 for (i = 0; ps->ps_uvpaths != NULL && i < ps->ps_uvvcount; i++) { 172 struct unveil *uv = ps->ps_uvpaths + i; 173 174 struct vnode *vp = uv->uv_vp; 175 /* skip any vnodes zapped by unveil_removevnode */ 176 if (vp != NULL) { 177 vp->v_uvcount--; 178 #ifdef DEBUG_UNVEIL 179 printf("unveil: %s(%d): removing vnode %p uvcount %d " 180 "in position %ld\n", 181 ps->ps_comm, ps->ps_pid, vp, vp->v_uvcount, i); 182 #endif 183 vrele(vp); 184 } 185 ps->ps_uvncount -= unveil_delete_names(uv); 186 uv->uv_vp = NULL; 187 uv->uv_flags = 0; 188 } 189 190 KASSERT(ps->ps_uvncount == 0); 191 free(ps->ps_uvpaths, M_PROC, UNVEIL_MAX_VNODES * 192 sizeof(struct unveil)); 193 ps->ps_uvvcount = 0; 194 ps->ps_uvpaths = NULL; 195 } 196 197 void 198 unveil_copy(struct process *parent, struct process *child) 199 { 200 size_t i; 201 202 if (parent->ps_uvvcount == 0) 203 return; 204 205 child->ps_uvpaths = mallocarray(UNVEIL_MAX_VNODES, sizeof(struct unveil), 206 M_PROC, M_WAITOK|M_ZERO); 207 208 child->ps_uvncount = 0; 209 for (i = 0; parent->ps_uvpaths != NULL && i < parent->ps_uvvcount; 210 i++) { 211 struct unveil *from = parent->ps_uvpaths + i; 212 struct unveil *to = child->ps_uvpaths + i; 213 struct unvname *unvn, *next; 214 215 to->uv_vp = from->uv_vp; 216 if (to->uv_vp != NULL) { 217 vref(to->uv_vp); 218 to->uv_vp->v_uvcount++; 219 } 220 rw_init(&to->uv_lock, "unveil"); 221 RBT_INIT(unvname_rbt, &to->uv_names); 222 rw_enter_read(&from->uv_lock); 223 RBT_FOREACH_SAFE(unvn, unvname_rbt, &from->uv_names, next) { 224 unveil_add_name(&child->ps_uvpaths[i], unvn->un_name, 225 unvn->un_flags); 226 child->ps_uvncount++; 227 } 228 rw_exit_read(&from->uv_lock); 229 to->uv_flags = from->uv_flags; 230 } 231 child->ps_uvvcount = parent->ps_uvvcount; 232 if (parent->ps_uvpcwd) 233 child->ps_uvpcwd = child->ps_uvpaths + 234 (parent->ps_uvpcwd - parent->ps_uvpaths); 235 child->ps_uvpcwdgone = parent->ps_uvpcwdgone; 236 child->ps_uvdone = parent->ps_uvdone; 237 child->ps_uvshrink = parent->ps_uvshrink; 238 } 239 240 struct unveil * 241 unveil_lookup(struct vnode *vp, struct proc *p) 242 { 243 struct process *pr = p->p_p; 244 struct unveil *uv = pr->ps_uvpaths; 245 ssize_t l, r; 246 247 if (vp->v_uvcount == 0) 248 return NULL; 249 250 /* 251 * shrink if told to do so to remove dead vnodes. 252 */ 253 if (pr->ps_uvshrink) { 254 size_t i = 0, j; 255 256 while (i < pr->ps_uvvcount) { 257 if (uv[i].uv_vp == NULL) { 258 pr->ps_uvncount -= unveil_delete_names(&uv[i]); 259 for (j = i + 1; j < pr->ps_uvvcount; j++) 260 uv[j - 1] = uv[j]; 261 pr->ps_uvvcount--; 262 } 263 i++; 264 } 265 pr->ps_uvshrink = 0; 266 } 267 268 if (pr->ps_uvvcount == 0) 269 return NULL; 270 271 /* clear the cwd unveil when we .. past it */ 272 if (pr->ps_uvpcwd && (vp == pr->ps_uvpcwd->uv_vp)) { 273 #ifdef DEBUG_UNVEIL 274 printf("unveil: %s(%d): nuking cwd traversing vnode %p\n", 275 p->p_p->ps_comm, p->p_p->ps_pid, vp); 276 #endif 277 p->p_p->ps_uvpcwd = NULL; 278 p->p_p->ps_uvpcwdgone = 0; 279 } 280 #ifdef DEBUG_UNVEIL 281 else { 282 if (pr->ps_uvpcwd) { 283 printf("unveil: %s(%d): did not nuke cwd because %p != %p\n", 284 p->p_p->ps_comm, p->p_p->ps_pid, vp, pr->ps_uvpcwd->uv_vp); 285 } else 286 printf("unveil: %s(%d): cwd is null\n", 287 p->p_p->ps_comm, p->p_p->ps_pid); 288 } 289 #endif 290 291 l = 0; 292 r = pr->ps_uvvcount - 1; 293 while (l <= r) { 294 size_t m = l + (r - l)/2; 295 #ifdef DEBUG_UNVEIL 296 printf("unveil: checking vnode %p vs. unveil vnode %p\n", 297 vp, uv[m].uv_vp); 298 #endif 299 if (vp == uv[m].uv_vp) { 300 KASSERT(uv[m].uv_vp->v_uvcount > 0); 301 KASSERT(uv[m].uv_vp->v_usecount > 0); 302 return &uv[m]; 303 } 304 if (vp > uv[m].uv_vp) 305 l = m + 1; 306 else 307 r = m - 1; 308 } 309 return NULL; 310 } 311 312 int 313 unveil_parsepermissions(const char *permissions, u_char *perms) 314 { 315 size_t i = 0; 316 char c; 317 318 *perms = 0; 319 while ((c = permissions[i++]) != '\0') { 320 switch (c) { 321 case 'r': 322 *perms |= UNVEIL_READ; 323 break; 324 case 'w': 325 *perms |= UNVEIL_WRITE; 326 break; 327 case 'x': 328 *perms |= UNVEIL_EXEC; 329 break; 330 case 'c': 331 *perms |= UNVEIL_CREATE; 332 break; 333 default: 334 return -1; 335 } 336 } 337 return 0; 338 } 339 340 int 341 unveil_setflags(u_char *flags, u_char nflags) 342 { 343 #if 0 344 if (((~(*flags)) & nflags) != 0) { 345 #ifdef DEBUG_UNVEIL 346 printf("Flags escalation %llX -> %llX\n", *flags, nflags); 347 #endif 348 return 1; 349 } 350 #endif 351 *flags = nflags; 352 return 1; 353 } 354 355 struct unveil * 356 unveil_add_vnode(struct process *pr, struct vnode *vp) 357 { 358 struct unveil *uv = NULL; 359 ssize_t i; 360 361 KASSERT(pr->ps_uvvcount < UNVEIL_MAX_VNODES); 362 363 for (i = pr->ps_uvvcount; 364 i > 0 && pr->ps_uvpaths[i - 1].uv_vp > vp; 365 i--) 366 pr->ps_uvpaths[i] = pr->ps_uvpaths[i - 1]; 367 368 uv = &pr->ps_uvpaths[i]; 369 rw_init(&uv->uv_lock, "unveil"); 370 RBT_INIT(unvname_rbt, &uv->uv_names); 371 uv->uv_vp = vp; 372 /* 373 * Added vnodes are added with the UNVEIL_INSPECT flag 374 * to allow operations such as access and stat. This lets 375 * TOCTOU fans that call access on all components of 376 * an unveil'ed path before the final operations 377 * work. 378 */ 379 uv->uv_flags = UNVEIL_INSPECT; 380 pr->ps_uvvcount++; 381 return (uv); 382 } 383 384 void 385 unveil_add_traversed_vnodes(struct proc *p, struct nameidata *ndp) 386 { 387 struct unveil *uv; 388 389 if (ndp->ni_tvpsize) { 390 size_t i; 391 392 for (i = 0; i < ndp->ni_tvpend; i++) { 393 struct vnode *vp = ndp->ni_tvp[i]; 394 if (unveil_lookup(vp, p) == NULL) { 395 vref(vp); 396 vp->v_uvcount++; 397 uv = unveil_add_vnode(p->p_p, vp); 398 } 399 } 400 } 401 } 402 403 int 404 unveil_add(struct proc *p, struct nameidata *ndp, const char *permissions) 405 { 406 struct process *pr = p->p_p; 407 struct vnode *vp; 408 struct unveil *uv; 409 int directory_add; 410 int ret = EINVAL; 411 u_char flags; 412 413 KASSERT(ISSET(ndp->ni_cnd.cn_flags, HASBUF)); /* must have SAVENAME */ 414 415 if (unveil_parsepermissions(permissions, &flags) == -1) 416 goto done; 417 418 if (pr->ps_uvpaths == NULL) { 419 pr->ps_uvpaths = mallocarray(UNVEIL_MAX_VNODES, 420 sizeof(struct unveil), M_PROC, M_WAITOK|M_ZERO); 421 } 422 423 if ((pr->ps_uvvcount + ndp->ni_tvpend) >= UNVEIL_MAX_VNODES || 424 pr->ps_uvncount >= UNVEIL_MAX_NAMES) { 425 ret = E2BIG; 426 goto done; 427 } 428 429 /* Are we a directory? or something else */ 430 directory_add = ndp->ni_vp != NULL && ndp->ni_vp->v_type == VDIR; 431 432 if (directory_add) 433 vp = ndp->ni_vp; 434 else 435 vp = ndp->ni_dvp; 436 437 KASSERT(vp->v_type == VDIR); 438 vref(vp); 439 vp->v_uvcount++; 440 if ((uv = unveil_lookup(vp, p)) != NULL) { 441 /* 442 * We already have unveiled this directory 443 * vnode 444 */ 445 vp->v_uvcount--; 446 vrele(vp); 447 448 /* 449 * If we are adding a directory which was already 450 * unveiled containing only specific terminals, 451 * unrestrict it. 452 */ 453 if (directory_add) { 454 #ifdef DEBUG_UNVEIL 455 printf("unveil: %s(%d): updating directory vnode %p" 456 " to unrestricted uvcount %d\n", 457 pr->ps_comm, pr->ps_pid, vp, vp->v_uvcount); 458 #endif 459 if (!unveil_setflags(&uv->uv_flags, flags)) 460 ret = EPERM; 461 else 462 ret = 0; 463 goto done; 464 } 465 466 /* 467 * If we are adding a terminal that is already unveiled, just 468 * replace the flags and we are done 469 */ 470 if (!directory_add) { 471 struct unvname *tname; 472 if ((tname = unveil_namelookup(uv, 473 ndp->ni_cnd.cn_nameptr)) != NULL) { 474 #ifdef DEBUG_UNVEIL 475 printf("unveil: %s(%d): changing flags for %s" 476 "in vnode %p, uvcount %d\n", 477 pr->ps_comm, pr->ps_pid, tname->un_name, vp, 478 vp->v_uvcount); 479 #endif 480 if (!unveil_setflags(&tname->un_flags, flags)) 481 ret = EPERM; 482 else 483 ret = 0; 484 goto done; 485 } 486 } 487 488 } else { 489 /* 490 * New unveil involving this directory vnode. 491 */ 492 uv = unveil_add_vnode(pr, vp); 493 } 494 495 /* 496 * At this stage with have a unveil in uv with a vnode for a 497 * directory. If the component we are adding is a directory, 498 * we are done. Otherwise, we add the component name the name 499 * list in uv. 500 */ 501 502 if (directory_add) { 503 uv->uv_flags = flags; 504 ret = 0; 505 #ifdef DEBUG_UNVEIL 506 printf("unveil: %s(%d): added unrestricted directory vnode %p" 507 ", uvcount %d\n", 508 pr->ps_comm, pr->ps_pid, vp, vp->v_uvcount); 509 #endif 510 goto done; 511 } 512 513 unveil_add_name(uv, ndp->ni_cnd.cn_nameptr, flags); 514 pr->ps_uvncount++; 515 ret = 0; 516 517 #ifdef DEBUG_UNVEIL 518 printf("unveil: %s(%d): added name %s beneath %s vnode %p," 519 " uvcount %d\n", 520 pr->ps_comm, pr->ps_pid, ndp->ni_cnd.cn_nameptr, 521 uv->uv_flags ? "unrestricted" : "restricted", 522 vp, vp->v_uvcount); 523 #endif 524 525 done: 526 if (ret == 0) 527 unveil_add_traversed_vnodes(p, ndp); 528 unveil_free_traversed_vnodes(ndp); 529 pool_put(&namei_pool, ndp->ni_cnd.cn_pnbuf); 530 return ret; 531 } 532 533 /* 534 * XXX this will probably change. 535 * XXX collapse down later once debug surely unneded 536 */ 537 int 538 unveil_flagmatch(struct nameidata *ni, u_char flags) 539 { 540 if (flags == 0) { 541 #ifdef DEBUG_UNVEIL 542 printf("All operations forbidden for 0 flags\n"); 543 #endif 544 return 0; 545 } 546 if (ni->ni_unveil & UNVEIL_READ) { 547 if ((flags & UNVEIL_READ) == 0) { 548 #ifdef DEBUG_UNVEIL 549 printf("unveil lacks UNVEIL_READ\n"); 550 #endif 551 return 0; 552 } 553 } 554 if (ni->ni_unveil & UNVEIL_WRITE) { 555 if ((flags & UNVEIL_WRITE) == 0) { 556 #ifdef DEBUG_UNVEIL 557 printf("unveil lacks UNVEIL_WRITE\n"); 558 #endif 559 return 0; 560 } 561 } 562 if (ni->ni_unveil & UNVEIL_EXEC) { 563 if ((flags & UNVEIL_EXEC) == 0) { 564 #ifdef DEBUG_UNVEIL 565 printf("unveil lacks UNVEIL_EXEC\n"); 566 #endif 567 return 0; 568 } 569 } 570 if (ni->ni_unveil & UNVEIL_CREATE) { 571 if ((flags & UNVEIL_CREATE) == 0) { 572 #ifdef DEBUG_UNVEIL 573 printf("unveil lacks UNVEIL_CREATE\n"); 574 #endif 575 return 0; 576 } 577 } 578 if (ni->ni_unveil & UNVEIL_INSPECT) { 579 #ifdef DEBUG_UNVEIL 580 printf("any unveil allows UNVEIL_INSPECT\n"); 581 #endif 582 } 583 return 1; 584 } 585 586 /* 587 * unveil checking - for component directories in a namei lookup. 588 */ 589 void 590 unveil_check_component(struct proc *p, struct nameidata *ni, struct vnode *dp) 591 { 592 struct unveil *uv = NULL; 593 594 if (ni->ni_pledge != PLEDGE_UNVEIL) { 595 if ((ni->ni_cnd.cn_flags & BYPASSUNVEIL) == 0 && 596 ! (ni->ni_cnd.cn_flags & ISDOTDOT) && 597 (uv = unveil_lookup(dp, p)) != NULL) { 598 /* if directory flags match, it's a match */ 599 if (unveil_flagmatch(ni, uv->uv_flags)) { 600 if (uv->uv_flags & UNVEIL_USERSET) { 601 ni->ni_unveil_match = uv; 602 #ifdef DEBUG_UNVEIL 603 printf("unveil: %s(%d): component directory match" 604 " for vnode %p\n", 605 p->p_p->ps_comm, p->p_p->ps_pid, dp); 606 607 #endif 608 } 609 } 610 } 611 } else 612 unveil_save_traversed_vnode(ni, dp); 613 } 614 615 /* 616 * unveil checking - only done after namei lookup has succeeded on 617 * the last component of a namei lookup. 618 */ 619 int 620 unveil_check_final(struct proc *p, struct nameidata *ni) 621 { 622 struct unveil *uv; 623 struct unvname *tname = NULL; 624 625 if (ni->ni_pledge == PLEDGE_UNVEIL || 626 p->p_p->ps_uvpaths == NULL) 627 return (0); 628 629 if (ni->ni_cnd.cn_flags & BYPASSUNVEIL) { 630 #ifdef DEBUG_UNVEIL 631 printf("unveil: %s(%d): BYPASSUNVEIL.\n", 632 p->p_p->ps_comm, p->p_p->ps_pid); 633 #endif 634 CLR(ni->ni_pledge, PLEDGE_STATLIE); 635 return (0); 636 } 637 if (ni->ni_vp != NULL && ni->ni_vp->v_type == VDIR) { 638 uv = unveil_lookup(ni->ni_vp, p); 639 if (uv == NULL) { 640 #ifdef DEBUG_UNVEIL 641 printf("unveil: %s(%d) no match for vnode %p\n", 642 p->p_p->ps_comm, p->p_p->ps_pid, ni->ni_vp); 643 #endif 644 goto done; 645 } 646 if (!unveil_flagmatch(ni, uv->uv_flags)) { 647 #ifdef DEBUG_UNVEIL 648 printf("unveil: %s(%d) flag mismatch for directory" 649 " vnode %p\n", 650 p->p_p->ps_comm, p->p_p->ps_pid, ni->ni_vp); 651 #endif 652 return EACCES; 653 } 654 } else { 655 uv = unveil_lookup(ni->ni_dvp, p); 656 if (uv == NULL) { 657 #ifdef DEBUG_UNVEIL 658 printf("unveil: %s(%d) no match for directory" 659 " vnode %p\n", 660 p->p_p->ps_comm, p->p_p->ps_pid, ni->ni_dvp); 661 #endif 662 goto done; 663 } 664 if ((tname = unveil_namelookup(uv, ni->ni_cnd.cn_nameptr)) 665 == NULL) { 666 #ifdef DEBUG_UNVEIL 667 printf("unveil: %s(%d) no match for terminal '%s' in " 668 "directory vnode %p\n", 669 p->p_p->ps_comm, p->p_p->ps_pid, 670 ni->ni_cnd.cn_nameptr, ni->ni_dvp); 671 #endif 672 uv = NULL; 673 goto done; 674 } 675 if (!unveil_flagmatch(ni, tname->un_flags)) { 676 #ifdef DEBUG_UNVEIL 677 printf("unveil: %s(%d) flag mismatch for terminal '%s'\n", 678 p->p_p->ps_comm, p->p_p->ps_pid, tname->un_name); 679 #endif 680 return EACCES; 681 } 682 } 683 ni->ni_unveil_match = uv; 684 done: 685 if (ni->ni_unveil_match) { 686 #ifdef DEBUG_UNVEIL 687 printf("unveil: %s(%d): matched \"%s\" underneath/at vnode %p\n", 688 p->p_p->ps_comm, p->p_p->ps_pid, ni->ni_cnd.cn_nameptr, 689 ni->ni_unveil_match->uv_vp); 690 #endif 691 return (0); 692 } else if (p->p_p->ps_uvpcwd) { 693 ni->ni_unveil_match = p->p_p->ps_uvpcwd; 694 #ifdef DEBUG_UNVEIL 695 printf("unveil: %s(%d): used cwd unveil vnode from vnode %p\n", 696 p->p_p->ps_comm, p->p_p->ps_pid, ni->ni_unveil_match->uv_vp); 697 #endif 698 return (0); 699 } else if (p->p_p->ps_uvpcwdgone) { 700 printf("Corner cases make Bob cry in a corner\n"); 701 } 702 return ENOENT; 703 } 704 705 /* 706 * Scan all active processes to see if any of them have a unveil 707 * to this vnode. If so, NULL the vnode in their unveil list, 708 * vrele, drop the reference, and mark their unveil list 709 * as needing to have the hole shrunk the next time the process 710 * uses it for lookup. 711 */ 712 void 713 unveil_removevnode(struct vnode *vp) 714 { 715 struct process *pr; 716 717 if (vp->v_uvcount == 0) 718 return; 719 720 #ifdef DEBUG_UNVEIL 721 printf("unveil_removevnode found vnode %p with count %d\n", 722 vp, vp->v_uvcount); 723 #endif 724 vref(vp); /* make sure it is held till we are done */ 725 726 LIST_FOREACH(pr, &allprocess, ps_list) { 727 struct unveil * uv; 728 729 if ((uv = unveil_lookup(vp, pr->ps_mainproc)) != NULL && 730 uv->uv_vp != NULL) { 731 uv->uv_vp = NULL; 732 uv->uv_flags = 0; 733 #ifdef DEBUG_UNVEIL 734 printf("unveil_removevnode vnode %p now count %d\n", 735 vp, vp->v_uvcount); 736 #endif 737 pr->ps_uvshrink = 1; 738 if (vp->v_uvcount > 0) { 739 vrele(vp); 740 vp->v_uvcount--; 741 } else 742 panic("vp %p, v_uvcount of %d should be 0", 743 vp, vp->v_uvcount); 744 } 745 } 746 KASSERT(vp->v_uvcount == 0); 747 748 vrele(vp); /* release our ref */ 749 } 750