1 /* $OpenBSD: kern_unveil.c,v 1.48 2021/07/16 07:59:38 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2017-2019 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/acct.h> 22 #include <sys/mount.h> 23 #include <sys/filedesc.h> 24 #include <sys/proc.h> 25 #include <sys/namei.h> 26 #include <sys/pool.h> 27 #include <sys/vnode.h> 28 #include <sys/ktrace.h> 29 #include <sys/types.h> 30 #include <sys/malloc.h> 31 #include <sys/tree.h> 32 #include <sys/lock.h> 33 34 #include <sys/conf.h> 35 #include <sys/syscall.h> 36 #include <sys/syscallargs.h> 37 #include <sys/systm.h> 38 39 #include <sys/pledge.h> 40 41 struct unvname { 42 char *un_name; 43 size_t un_namesize; 44 u_char un_flags; 45 RBT_ENTRY(unvnmae) un_rbt; 46 }; 47 48 RBT_HEAD(unvname_rbt, unvname); 49 50 struct unveil { 51 struct vnode *uv_vp; 52 ssize_t uv_cover; 53 struct unvname_rbt uv_names; 54 struct rwlock uv_lock; 55 u_char uv_flags; 56 }; 57 58 /* #define DEBUG_UNVEIL */ 59 60 #define UNVEIL_MAX_VNODES 128 61 #define UNVEIL_MAX_NAMES 128 62 63 static inline int 64 unvname_compare(const struct unvname *n1, const struct unvname *n2) 65 { 66 if (n1->un_namesize == n2->un_namesize) 67 return (memcmp(n1->un_name, n2->un_name, n1->un_namesize)); 68 else 69 return (n1->un_namesize - n2->un_namesize); 70 } 71 72 struct unvname * 73 unvname_new(const char *name, size_t size, u_char flags) 74 { 75 struct unvname *ret = malloc(sizeof(struct unvname), M_PROC, M_WAITOK); 76 ret->un_name = malloc(size, M_PROC, M_WAITOK); 77 memcpy(ret->un_name, name, size); 78 ret->un_namesize = size; 79 ret->un_flags = flags; 80 return ret; 81 } 82 83 void 84 unvname_delete(struct unvname *name) 85 { 86 free(name->un_name, M_PROC, name->un_namesize); 87 free(name, M_PROC, sizeof(struct unvname)); 88 } 89 90 RBT_PROTOTYPE(unvname_rbt, unvname, un_rbt, unvname_compare); 91 RBT_GENERATE(unvname_rbt, unvname, un_rbt, unvname_compare); 92 93 int 94 unveil_delete_names(struct unveil *uv) 95 { 96 struct unvname *unvn, *next; 97 int ret = 0; 98 99 rw_enter_write(&uv->uv_lock); 100 RBT_FOREACH_SAFE(unvn, unvname_rbt, &uv->uv_names, next) { 101 RBT_REMOVE(unvname_rbt, &uv->uv_names, unvn); 102 unvname_delete(unvn); 103 ret++; 104 } 105 rw_exit_write(&uv->uv_lock); 106 #ifdef DEBUG_UNVEIL 107 printf("deleted %d names\n", ret); 108 #endif 109 return ret; 110 } 111 112 int 113 unveil_add_name_unlocked(struct unveil *uv, char *name, u_char flags) 114 { 115 struct unvname *unvn; 116 117 unvn = unvname_new(name, strlen(name) + 1, flags); 118 if (RBT_INSERT(unvname_rbt, &uv->uv_names, unvn) != NULL) { 119 /* Name already present. */ 120 unvname_delete(unvn); 121 return 0; 122 } 123 #ifdef DEBUG_UNVEIL 124 printf("added name %s underneath vnode %p\n", name, uv->uv_vp); 125 #endif 126 return 1; 127 } 128 129 int 130 unveil_add_name(struct unveil *uv, char *name, u_char flags) 131 { 132 int ret; 133 134 rw_enter_write(&uv->uv_lock); 135 ret = unveil_add_name_unlocked(uv, name, flags); 136 rw_exit_write(&uv->uv_lock); 137 return ret; 138 } 139 140 struct unvname * 141 unveil_namelookup(struct unveil *uv, char *name) 142 { 143 struct unvname n, *ret = NULL; 144 145 rw_enter_read(&uv->uv_lock); 146 147 #ifdef DEBUG_UNVEIL 148 printf("unveil_namelookup: looking up name %s (%p) in vnode %p\n", 149 name, name, uv->uv_vp); 150 #endif 151 152 KASSERT(uv->uv_vp != NULL); 153 154 n.un_name = name; 155 n.un_namesize = strlen(name) + 1; 156 157 ret = RBT_FIND(unvname_rbt, &uv->uv_names, &n); 158 159 rw_exit_read(&uv->uv_lock); 160 161 #ifdef DEBUG_UNVEIL 162 if (ret == NULL) 163 printf("unveil_namelookup: no match for name %s in vnode %p\n", 164 name, uv->uv_vp); 165 else 166 printf("unveil_namelookup: matched name %s in vnode %p\n", 167 name, uv->uv_vp); 168 #endif 169 return ret; 170 } 171 172 void 173 unveil_destroy(struct process *ps) 174 { 175 size_t i; 176 177 for (i = 0; ps->ps_uvpaths != NULL && i < ps->ps_uvvcount; i++) { 178 struct unveil *uv = ps->ps_uvpaths + i; 179 180 struct vnode *vp = uv->uv_vp; 181 /* skip any vnodes zapped by unveil_removevnode */ 182 if (vp != NULL) { 183 vp->v_uvcount--; 184 #ifdef DEBUG_UNVEIL 185 printf("unveil: %s(%d): removing vnode %p uvcount %d " 186 "in position %ld\n", 187 ps->ps_comm, ps->ps_pid, vp, vp->v_uvcount, i); 188 #endif 189 vrele(vp); 190 } 191 ps->ps_uvncount -= unveil_delete_names(uv); 192 uv->uv_vp = NULL; 193 uv->uv_flags = 0; 194 } 195 196 KASSERT(ps->ps_uvncount == 0); 197 free(ps->ps_uvpaths, M_PROC, UNVEIL_MAX_VNODES * 198 sizeof(struct unveil)); 199 ps->ps_uvvcount = 0; 200 ps->ps_uvpaths = NULL; 201 } 202 203 void 204 unveil_copy(struct process *parent, struct process *child) 205 { 206 size_t i; 207 208 if (parent->ps_uvvcount == 0) 209 return; 210 211 child->ps_uvpaths = mallocarray(UNVEIL_MAX_VNODES, 212 sizeof(struct unveil), M_PROC, M_WAITOK|M_ZERO); 213 214 child->ps_uvncount = 0; 215 for (i = 0; parent->ps_uvpaths != NULL && i < parent->ps_uvvcount; 216 i++) { 217 struct unveil *from = parent->ps_uvpaths + i; 218 struct unveil *to = child->ps_uvpaths + i; 219 struct unvname *unvn, *next; 220 221 to->uv_vp = from->uv_vp; 222 if (to->uv_vp != NULL) { 223 vref(to->uv_vp); 224 to->uv_vp->v_uvcount++; 225 } 226 rw_init(&to->uv_lock, "unveil"); 227 RBT_INIT(unvname_rbt, &to->uv_names); 228 rw_enter_read(&from->uv_lock); 229 RBT_FOREACH_SAFE(unvn, unvname_rbt, &from->uv_names, next) { 230 if (unveil_add_name_unlocked(&child->ps_uvpaths[i], 231 unvn->un_name, unvn->un_flags)) 232 child->ps_uvncount++; 233 } 234 rw_exit_read(&from->uv_lock); 235 to->uv_flags = from->uv_flags; 236 to->uv_cover = from->uv_cover; 237 } 238 child->ps_uvvcount = parent->ps_uvvcount; 239 child->ps_uvdone = parent->ps_uvdone; 240 } 241 242 /* 243 * Walk up from vnode dp, until we find a matching unveil, or the root vnode 244 * returns -1 if no unveil to be found above dp or if dp is the root vnode. 245 */ 246 ssize_t 247 unveil_find_cover(struct vnode *dp, struct proc *p) 248 { 249 struct vnode *vp = NULL, *parent = NULL, *root; 250 ssize_t ret = -1; 251 int error; 252 253 /* use the correct root to stop at, chrooted or not.. */ 254 root = p->p_fd->fd_rdir ? p->p_fd->fd_rdir : rootvnode; 255 vp = dp; 256 257 while (vp != root) { 258 struct componentname cn = { 259 .cn_nameiop = LOOKUP, 260 .cn_flags = ISLASTCN | ISDOTDOT | RDONLY, 261 .cn_proc = p, 262 .cn_cred = p->p_ucred, 263 .cn_pnbuf = NULL, 264 .cn_nameptr = "..", 265 .cn_namelen = 2, 266 .cn_consume = 0 267 }; 268 269 /* 270 * If we are at the root of a filesystem, and we are 271 * still mounted somewhere, take the .. in the above 272 * filesystem. 273 */ 274 if (vp != root && (vp->v_flag & VROOT)) { 275 if (vp->v_mount == NULL) 276 return -1; 277 vp = vp->v_mount->mnt_vnodecovered ? 278 vp->v_mount->mnt_vnodecovered : vp; 279 } 280 281 if (vget(vp, LK_EXCLUSIVE|LK_RETRY) != 0) 282 return -1; 283 /* Get parent vnode of vp using lookup of '..' */ 284 /* This returns with vp unlocked but ref'ed*/ 285 error = VOP_LOOKUP(vp, &parent, &cn); 286 if (error) { 287 if (!(cn.cn_flags & PDIRUNLOCK)) 288 vput(vp); 289 else { 290 /* 291 * This corner case should not happen because 292 * we have not set LOCKPARENT in the flags 293 */ 294 printf("vnode %p PDIRUNLOCK on error\n", vp); 295 vrele(vp); 296 } 297 break; 298 } 299 300 vrele(vp); 301 (void) unveil_lookup(parent, p->p_p, &ret); 302 vput(parent); 303 304 if (ret >= 0) 305 break; 306 307 if (vp == parent) { 308 ret = -1; 309 break; 310 } 311 vp = parent; 312 parent = NULL; 313 } 314 return ret; 315 } 316 317 318 struct unveil * 319 unveil_lookup(struct vnode *vp, struct process *pr, ssize_t *position) 320 { 321 struct unveil *uv = pr->ps_uvpaths; 322 ssize_t i; 323 324 if (position != NULL) 325 *position = -1; 326 327 if (vp->v_uvcount == 0) 328 return NULL; 329 330 for (i = 0; i < pr->ps_uvvcount; i++) { 331 if (vp == uv[i].uv_vp) { 332 KASSERT(uv[i].uv_vp->v_uvcount > 0); 333 KASSERT(uv[i].uv_vp->v_usecount > 0); 334 if (position != NULL) 335 *position = i; 336 return &uv[i]; 337 } 338 } 339 return NULL; 340 } 341 342 int 343 unveil_parsepermissions(const char *permissions, u_char *perms) 344 { 345 size_t i = 0; 346 char c; 347 348 *perms = 0; 349 while ((c = permissions[i++]) != '\0') { 350 switch (c) { 351 case 'r': 352 *perms |= UNVEIL_READ; 353 break; 354 case 'w': 355 *perms |= UNVEIL_WRITE; 356 break; 357 case 'x': 358 *perms |= UNVEIL_EXEC; 359 break; 360 case 'c': 361 *perms |= UNVEIL_CREATE; 362 break; 363 default: 364 return -1; 365 } 366 } 367 return 0; 368 } 369 370 int 371 unveil_setflags(u_char *flags, u_char nflags) 372 { 373 #if 0 374 if (((~(*flags)) & nflags) != 0) { 375 #ifdef DEBUG_UNVEIL 376 printf("Flags escalation %llX -> %llX\n", *flags, nflags); 377 #endif 378 return 1; 379 } 380 #endif 381 *flags = nflags; 382 return 1; 383 } 384 385 struct unveil * 386 unveil_add_vnode(struct proc *p, struct vnode *vp) 387 { 388 struct process *pr = p->p_p; 389 struct unveil *uv = NULL; 390 ssize_t i; 391 392 KASSERT(pr->ps_uvvcount < UNVEIL_MAX_VNODES); 393 394 uv = &pr->ps_uvpaths[pr->ps_uvvcount++]; 395 rw_init(&uv->uv_lock, "unveil"); 396 RBT_INIT(unvname_rbt, &uv->uv_names); 397 uv->uv_vp = vp; 398 uv->uv_flags = 0; 399 400 /* find out what we are covered by */ 401 uv->uv_cover = unveil_find_cover(vp, p); 402 403 /* 404 * Find anyone covered by what we are covered by 405 * and re-check what covers them (we could have 406 * interposed a cover) 407 */ 408 for (i = 0; i < pr->ps_uvvcount - 1; i++) { 409 if (pr->ps_uvpaths[i].uv_cover == uv->uv_cover) 410 pr->ps_uvpaths[i].uv_cover = 411 unveil_find_cover(pr->ps_uvpaths[i].uv_vp, p); 412 } 413 414 return (uv); 415 } 416 417 int 418 unveil_add(struct proc *p, struct nameidata *ndp, const char *permissions) 419 { 420 struct process *pr = p->p_p; 421 struct vnode *vp; 422 struct unveil *uv; 423 int directory_add; 424 int ret = EINVAL; 425 u_char flags; 426 427 KASSERT(ISSET(ndp->ni_cnd.cn_flags, HASBUF)); /* must have SAVENAME */ 428 429 if (unveil_parsepermissions(permissions, &flags) == -1) 430 goto done; 431 432 if (pr->ps_uvpaths == NULL) { 433 pr->ps_uvpaths = mallocarray(UNVEIL_MAX_VNODES, 434 sizeof(struct unveil), M_PROC, M_WAITOK|M_ZERO); 435 } 436 437 if (pr->ps_uvvcount >= UNVEIL_MAX_VNODES || 438 pr->ps_uvncount >= UNVEIL_MAX_NAMES) { 439 ret = E2BIG; 440 goto done; 441 } 442 443 /* Are we a directory? or something else */ 444 directory_add = ndp->ni_vp != NULL && ndp->ni_vp->v_type == VDIR; 445 446 if (directory_add) 447 vp = ndp->ni_vp; 448 else 449 vp = ndp->ni_dvp; 450 451 KASSERT(vp->v_type == VDIR); 452 vref(vp); 453 vp->v_uvcount++; 454 if ((uv = unveil_lookup(vp, pr, NULL)) != NULL) { 455 /* 456 * We already have unveiled this directory 457 * vnode 458 */ 459 vp->v_uvcount--; 460 vrele(vp); 461 462 /* 463 * If we are adding a directory which was already 464 * unveiled containing only specific terminals, 465 * unrestrict it. 466 */ 467 if (directory_add) { 468 #ifdef DEBUG_UNVEIL 469 printf("unveil: %s(%d): updating directory vnode %p" 470 " to unrestricted uvcount %d\n", 471 pr->ps_comm, pr->ps_pid, vp, vp->v_uvcount); 472 #endif 473 if (!unveil_setflags(&uv->uv_flags, flags)) 474 ret = EPERM; 475 else 476 ret = 0; 477 goto done; 478 } 479 480 /* 481 * If we are adding a terminal that is already unveiled, just 482 * replace the flags and we are done 483 */ 484 if (!directory_add) { 485 struct unvname *tname; 486 if ((tname = unveil_namelookup(uv, 487 ndp->ni_cnd.cn_nameptr)) != NULL) { 488 #ifdef DEBUG_UNVEIL 489 printf("unveil: %s(%d): changing flags for %s" 490 "in vnode %p, uvcount %d\n", 491 pr->ps_comm, pr->ps_pid, tname->un_name, vp, 492 vp->v_uvcount); 493 #endif 494 if (!unveil_setflags(&tname->un_flags, flags)) 495 ret = EPERM; 496 else 497 ret = 0; 498 goto done; 499 } 500 } 501 502 } else { 503 /* 504 * New unveil involving this directory vnode. 505 */ 506 uv = unveil_add_vnode(p, vp); 507 } 508 509 /* 510 * At this stage with have a unveil in uv with a vnode for a 511 * directory. If the component we are adding is a directory, 512 * we are done. Otherwise, we add the component name the name 513 * list in uv. 514 */ 515 516 if (directory_add) { 517 uv->uv_flags = flags; 518 ret = 0; 519 #ifdef DEBUG_UNVEIL 520 printf("unveil: %s(%d): added unrestricted directory vnode %p" 521 ", uvcount %d\n", 522 pr->ps_comm, pr->ps_pid, vp, vp->v_uvcount); 523 #endif 524 goto done; 525 } 526 527 if (unveil_add_name(uv, ndp->ni_cnd.cn_nameptr, flags)) 528 pr->ps_uvncount++; 529 ret = 0; 530 531 #ifdef DEBUG_UNVEIL 532 printf("unveil: %s(%d): added name %s beneath %s vnode %p," 533 " uvcount %d\n", 534 pr->ps_comm, pr->ps_pid, ndp->ni_cnd.cn_nameptr, 535 uv->uv_flags ? "unrestricted" : "restricted", 536 vp, vp->v_uvcount); 537 #endif 538 539 done: 540 return ret; 541 } 542 543 /* 544 * XXX this will probably change. 545 * XXX collapse down later once debug surely unneeded 546 */ 547 int 548 unveil_flagmatch(struct nameidata *ni, u_char flags) 549 { 550 if (flags == 0) { 551 #ifdef DEBUG_UNVEIL 552 printf("All operations forbidden for 0 flags\n"); 553 #endif 554 return 0; 555 } 556 if (ni->ni_unveil & UNVEIL_READ) { 557 if ((flags & UNVEIL_READ) == 0) { 558 #ifdef DEBUG_UNVEIL 559 printf("unveil lacks UNVEIL_READ\n"); 560 #endif 561 if (flags & UNVEIL_USERSET) 562 ni->ni_unveil_eacces = 1; 563 return 0; 564 } 565 } 566 if (ni->ni_unveil & UNVEIL_WRITE) { 567 if ((flags & UNVEIL_WRITE) == 0) { 568 #ifdef DEBUG_UNVEIL 569 printf("unveil lacks UNVEIL_WRITE\n"); 570 #endif 571 if (flags & UNVEIL_USERSET) 572 ni->ni_unveil_eacces = 1; 573 return 0; 574 } 575 } 576 if (ni->ni_unveil & UNVEIL_EXEC) { 577 if ((flags & UNVEIL_EXEC) == 0) { 578 #ifdef DEBUG_UNVEIL 579 printf("unveil lacks UNVEIL_EXEC\n"); 580 #endif 581 if (flags & UNVEIL_USERSET) 582 ni->ni_unveil_eacces = 1; 583 return 0; 584 } 585 } 586 if (ni->ni_unveil & UNVEIL_CREATE) { 587 if ((flags & UNVEIL_CREATE) == 0) { 588 #ifdef DEBUG_UNVEIL 589 printf("unveil lacks UNVEIL_CREATE\n"); 590 #endif 591 if (flags & UNVEIL_USERSET) 592 ni->ni_unveil_eacces = 1; 593 return 0; 594 } 595 } 596 return 1; 597 } 598 599 /* 600 * When traversing up towards the root figure out the proper unveil for 601 * the parent directory. 602 */ 603 struct unveil * 604 unveil_covered(struct unveil *uv, struct vnode *dvp, struct proc *p) 605 { 606 if (uv && uv->uv_vp == dvp) { 607 /* if at the root, chrooted or not, return the current uv */ 608 if (dvp == (p->p_fd->fd_rdir ? p->p_fd->fd_rdir : rootvnode)) 609 return uv; 610 if (uv->uv_cover >=0) { 611 KASSERT(uv->uv_cover < p->p_p->ps_uvvcount); 612 return &p->p_p->ps_uvpaths[uv->uv_cover]; 613 } 614 return NULL; 615 } 616 return uv; 617 } 618 619 620 /* 621 * Start a relative path lookup. Ensure we find whatever unveil covered 622 * where we start from, either by having a saved current working directory 623 * unveil, or by walking up and finding a cover the hard way if we are 624 * doing a non AT_FDCWD relative lookup. Caller passes a NULL dp 625 * if we are using AT_FDCWD. 626 */ 627 void 628 unveil_start_relative(struct proc *p, struct nameidata *ni, struct vnode *dp) 629 { 630 struct process *pr = p->p_p; 631 struct unveil *uv = NULL; 632 ssize_t uvi; 633 634 if (pr->ps_uvpaths == NULL) 635 return; 636 637 uv = unveil_lookup(dp, pr, NULL); 638 if (uv == NULL) { 639 uvi = unveil_find_cover(dp, p); 640 if (uvi >= 0) { 641 KASSERT(uvi < pr->ps_uvvcount); 642 uv = &pr->ps_uvpaths[uvi]; 643 } 644 } 645 646 /* 647 * If the flags don't match, we have no match from our 648 * starting point. If we do not find a matching unveil later 649 * on a later component of this lookup, we'll be out of luck 650 */ 651 if (uv && (unveil_flagmatch(ni, uv->uv_flags))) { 652 #ifdef DEBUG_UNVEIL 653 printf("unveil: %s(%d): cwd unveil at %p matches", 654 pr->ps_comm, pr->ps_pid, uv); 655 #endif 656 ni->ni_unveil_match = uv; 657 } 658 } 659 660 /* 661 * unveil checking - for component directories in a namei lookup. 662 */ 663 void 664 unveil_check_component(struct proc *p, struct nameidata *ni, struct vnode *dp) 665 { 666 struct process *pr = p->p_p; 667 struct unveil *uv = NULL; 668 669 if (ni->ni_pledge == PLEDGE_UNVEIL || pr->ps_uvpaths == NULL) 670 return; 671 if (ni->ni_cnd.cn_flags & BYPASSUNVEIL) 672 return; 673 674 if (ni->ni_cnd.cn_flags & ISDOTDOT) { 675 /* 676 * adjust unveil match as necessary 677 */ 678 uv = unveil_covered(ni->ni_unveil_match, dp, p); 679 680 /* clear the match when we DOTDOT above it */ 681 if (ni->ni_unveil_match && 682 ni->ni_unveil_match->uv_vp == dp) { 683 ni->ni_unveil_match = NULL; 684 ni->ni_unveil_eacces = 0; 685 } 686 } else 687 uv = unveil_lookup(dp, pr, NULL); 688 689 if (uv != NULL) { 690 /* if directory flags match, it's a match */ 691 if (unveil_flagmatch(ni, uv->uv_flags)) { 692 if (uv->uv_flags & UNVEIL_USERSET) { 693 ni->ni_unveil_match = uv; 694 #ifdef DEBUG_UNVEIL 695 printf("unveil: %s(%d): component " 696 "directory match for vnode %p\n", 697 pr->ps_comm, pr->ps_pid, dp); 698 #endif 699 } 700 } 701 } 702 } 703 704 /* 705 * unveil checking - only done after namei lookup has succeeded on 706 * the last component of a namei lookup. 707 */ 708 int 709 unveil_check_final(struct proc *p, struct nameidata *ni) 710 { 711 struct process *pr = p->p_p; 712 struct unveil *uv = NULL; 713 struct unvname *tname = NULL; 714 715 if (ni->ni_pledge == PLEDGE_UNVEIL || pr->ps_uvpaths == NULL) 716 return (0); 717 718 if (ni->ni_cnd.cn_flags & BYPASSUNVEIL) { 719 #ifdef DEBUG_UNVEIL 720 printf("unveil: %s(%d): BYPASSUNVEIL.\n", 721 pr->ps_comm, pr->ps_pid); 722 #endif 723 return (0); 724 } 725 if (ni->ni_vp != NULL && ni->ni_vp->v_type == VDIR) { 726 /* We are matching a directory terminal component */ 727 uv = unveil_lookup(ni->ni_vp, pr, NULL); 728 if (uv == NULL) { 729 #ifdef DEBUG_UNVEIL 730 printf("unveil: %s(%d) no match for vnode %p\n", 731 pr->ps_comm, pr->ps_pid, ni->ni_vp); 732 #endif 733 goto done; 734 } 735 if (!unveil_flagmatch(ni, uv->uv_flags)) { 736 #ifdef DEBUG_UNVEIL 737 printf("unveil: %s(%d) flag mismatch for directory" 738 " vnode %p\n", 739 pr->ps_comm, pr->ps_pid, ni->ni_vp); 740 #endif 741 pr->ps_acflag |= AUNVEIL; 742 if (uv->uv_flags & UNVEIL_USERSET) 743 return EACCES; 744 else 745 return ENOENT; 746 747 } 748 /* directory and flags match, update match */ 749 ni->ni_unveil_match = uv; 750 goto done; 751 } 752 /* Otherwise, we are matching a non-terminal component */ 753 uv = unveil_lookup(ni->ni_dvp, pr, NULL); 754 if (uv == NULL) { 755 #ifdef DEBUG_UNVEIL 756 printf("unveil: %s(%d) no match for directory" 757 " vnode %p\n", 758 pr->ps_comm, pr->ps_pid, ni->ni_dvp); 759 #endif 760 goto done; 761 } 762 if ((tname = unveil_namelookup(uv, ni->ni_cnd.cn_nameptr)) 763 == NULL) { 764 #ifdef DEBUG_UNVEIL 765 printf("unveil: %s(%d) no match for terminal '%s' in " 766 "directory vnode %p\n", 767 pr->ps_comm, pr->ps_pid, 768 ni->ni_cnd.cn_nameptr, ni->ni_dvp); 769 #endif 770 /* no specific name, so check unveil directory flags */ 771 if (!unveil_flagmatch(ni, uv->uv_flags)) { 772 #ifdef DEBUG_UNVEIL 773 printf("unveil: %s(%d) terminal " 774 "'%s' flags mismatch in directory " 775 "vnode %p\n", 776 pr->ps_comm, pr->ps_pid, 777 ni->ni_cnd.cn_nameptr, ni->ni_dvp); 778 #endif 779 /* 780 * If dir has user set restrictions fail with 781 * EACCES. Otherwise, use any covering match 782 * that we found above this dir. 783 */ 784 if (uv->uv_flags & UNVEIL_USERSET) { 785 pr->ps_acflag |= AUNVEIL; 786 return EACCES; 787 } 788 goto done; 789 } 790 /* directory flags match, update match */ 791 if (uv->uv_flags & UNVEIL_USERSET) 792 ni->ni_unveil_match = uv; 793 goto done; 794 } 795 if (!unveil_flagmatch(ni, tname->un_flags)) { 796 /* do flags match for matched name */ 797 #ifdef DEBUG_UNVEIL 798 printf("unveil: %s(%d) flag mismatch for terminal '%s'\n", 799 pr->ps_comm, pr->ps_pid, tname->un_name); 800 #endif 801 pr->ps_acflag |= AUNVEIL; 802 return EACCES; 803 } 804 /* name and flags match in this dir. update match*/ 805 ni->ni_unveil_match = uv; 806 807 done: 808 if (ni->ni_unveil_match) { 809 #ifdef DEBUG_UNVEIL 810 printf("unveil: %s(%d): matched \"%s\" underneath/at " 811 "vnode %p\n", 812 pr->ps_comm, pr->ps_pid, ni->ni_cnd.cn_nameptr, 813 ni->ni_unveil_match->uv_vp); 814 #endif 815 return (0); 816 } 817 if (ni->ni_unveil_eacces) { 818 #ifdef DEBUG_UNVEIL 819 printf("unveil: %s(%d): \"%s\" flag mismatch above/at " 820 "vnode %p\n", 821 pr->ps_comm, pr->ps_pid, ni->ni_cnd.cn_nameptr, 822 ni->ni_unveil_match->uv_vp); 823 #endif 824 pr->ps_acflag |= AUNVEIL; 825 return EACCES; 826 } 827 pr->ps_acflag |= AUNVEIL; 828 return ENOENT; 829 } 830 831 /* 832 * Scan all active processes to see if any of them have a unveil 833 * to this vnode. If so, NULL the vnode in their unveil list, 834 * vrele, drop the reference, and mark their unveil list 835 * as needing to have the hole shrunk the next time the process 836 * uses it for lookup. 837 */ 838 void 839 unveil_removevnode(struct vnode *vp) 840 { 841 struct process *pr; 842 843 if (vp->v_uvcount == 0) 844 return; 845 846 #ifdef DEBUG_UNVEIL 847 printf("unveil_removevnode found vnode %p with count %d\n", 848 vp, vp->v_uvcount); 849 #endif 850 vref(vp); /* make sure it is held till we are done */ 851 852 LIST_FOREACH(pr, &allprocess, ps_list) { 853 struct unveil * uv; 854 855 if ((uv = unveil_lookup(vp, pr, NULL)) != NULL && 856 uv->uv_vp != NULL) { 857 uv->uv_vp = NULL; 858 uv->uv_flags = 0; 859 #ifdef DEBUG_UNVEIL 860 printf("unveil_removevnode vnode %p now count %d\n", 861 vp, vp->v_uvcount); 862 #endif 863 if (vp->v_uvcount > 0) { 864 vrele(vp); 865 vp->v_uvcount--; 866 } else 867 panic("vp %p, v_uvcount of %d should be 0", 868 vp, vp->v_uvcount); 869 } 870 } 871 KASSERT(vp->v_uvcount == 0); 872 873 vrele(vp); /* release our ref */ 874 } 875