1 /* $OpenBSD: kern_unveil.c,v 1.50 2021/09/02 12:35:23 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 child->ps_uvdone = parent->ps_uvdone; 209 if (parent->ps_uvvcount == 0) 210 return; 211 212 child->ps_uvpaths = mallocarray(UNVEIL_MAX_VNODES, 213 sizeof(struct unveil), M_PROC, M_WAITOK|M_ZERO); 214 215 child->ps_uvncount = 0; 216 for (i = 0; parent->ps_uvpaths != NULL && i < parent->ps_uvvcount; 217 i++) { 218 struct unveil *from = parent->ps_uvpaths + i; 219 struct unveil *to = child->ps_uvpaths + i; 220 struct unvname *unvn, *next; 221 222 to->uv_vp = from->uv_vp; 223 if (to->uv_vp != NULL) { 224 vref(to->uv_vp); 225 to->uv_vp->v_uvcount++; 226 } 227 rw_init(&to->uv_lock, "unveil"); 228 RBT_INIT(unvname_rbt, &to->uv_names); 229 rw_enter_read(&from->uv_lock); 230 RBT_FOREACH_SAFE(unvn, unvname_rbt, &from->uv_names, next) { 231 if (unveil_add_name_unlocked(&child->ps_uvpaths[i], 232 unvn->un_name, unvn->un_flags)) 233 child->ps_uvncount++; 234 } 235 rw_exit_read(&from->uv_lock); 236 to->uv_flags = from->uv_flags; 237 to->uv_cover = from->uv_cover; 238 } 239 child->ps_uvvcount = parent->ps_uvvcount; 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 return 0; 562 } 563 } 564 if (ni->ni_unveil & UNVEIL_WRITE) { 565 if ((flags & UNVEIL_WRITE) == 0) { 566 #ifdef DEBUG_UNVEIL 567 printf("unveil lacks UNVEIL_WRITE\n"); 568 #endif 569 return 0; 570 } 571 } 572 if (ni->ni_unveil & UNVEIL_EXEC) { 573 if ((flags & UNVEIL_EXEC) == 0) { 574 #ifdef DEBUG_UNVEIL 575 printf("unveil lacks UNVEIL_EXEC\n"); 576 #endif 577 return 0; 578 } 579 } 580 if (ni->ni_unveil & UNVEIL_CREATE) { 581 if ((flags & UNVEIL_CREATE) == 0) { 582 #ifdef DEBUG_UNVEIL 583 printf("unveil lacks UNVEIL_CREATE\n"); 584 #endif 585 return 0; 586 } 587 } 588 return 1; 589 } 590 591 /* 592 * When traversing up towards the root figure out the proper unveil for 593 * the parent directory. 594 */ 595 struct unveil * 596 unveil_covered(struct unveil *uv, struct vnode *dvp, struct proc *p) 597 { 598 if (uv && uv->uv_vp == dvp) { 599 /* if at the root, chrooted or not, return the current uv */ 600 if (dvp == (p->p_fd->fd_rdir ? p->p_fd->fd_rdir : rootvnode)) 601 return uv; 602 if (uv->uv_cover >=0) { 603 KASSERT(uv->uv_cover < p->p_p->ps_uvvcount); 604 return &p->p_p->ps_uvpaths[uv->uv_cover]; 605 } 606 return NULL; 607 } 608 return uv; 609 } 610 611 612 /* 613 * Start a relative path lookup. Ensure we find whatever unveil covered 614 * where we start from, either by having a saved current working directory 615 * unveil, or by walking up and finding a cover the hard way if we are 616 * doing a non AT_FDCWD relative lookup. Caller passes a NULL dp 617 * if we are using AT_FDCWD. 618 */ 619 void 620 unveil_start_relative(struct proc *p, struct nameidata *ni, struct vnode *dp) 621 { 622 struct process *pr = p->p_p; 623 struct unveil *uv = NULL; 624 ssize_t uvi; 625 626 if (pr->ps_uvpaths == NULL) 627 return; 628 629 uv = unveil_lookup(dp, pr, NULL); 630 if (uv == NULL) { 631 uvi = unveil_find_cover(dp, p); 632 if (uvi >= 0) { 633 KASSERT(uvi < pr->ps_uvvcount); 634 uv = &pr->ps_uvpaths[uvi]; 635 } 636 } 637 638 /* 639 * Store this match for later use. Flags are checked at the end. 640 */ 641 if (uv) { 642 #ifdef DEBUG_UNVEIL 643 printf("unveil: %s(%d): relative unveil at %p matches", 644 pr->ps_comm, pr->ps_pid, uv); 645 #endif 646 ni->ni_unveil_match = uv; 647 } 648 } 649 650 /* 651 * unveil checking - for component directories in a namei lookup. 652 */ 653 void 654 unveil_check_component(struct proc *p, struct nameidata *ni, struct vnode *dp) 655 { 656 struct process *pr = p->p_p; 657 struct unveil *uv = NULL; 658 659 if (ni->ni_pledge == PLEDGE_UNVEIL || pr->ps_uvpaths == NULL) 660 return; 661 if (ni->ni_cnd.cn_flags & BYPASSUNVEIL) 662 return; 663 664 if (ni->ni_cnd.cn_flags & ISDOTDOT) { 665 /* 666 * adjust unveil match as necessary 667 */ 668 uv = unveil_covered(ni->ni_unveil_match, dp, p); 669 670 /* clear the match when we DOTDOT above it */ 671 if (ni->ni_unveil_match && ni->ni_unveil_match->uv_vp == dp) 672 ni->ni_unveil_match = NULL; 673 } else 674 uv = unveil_lookup(dp, pr, NULL); 675 676 if (uv != NULL) { 677 /* update match */ 678 ni->ni_unveil_match = uv; 679 #ifdef DEBUG_UNVEIL 680 printf("unveil: %s(%d): component directory match for " 681 "vnode %p\n", pr->ps_comm, pr->ps_pid, dp); 682 #endif 683 } 684 } 685 686 /* 687 * unveil checking - only done after namei lookup has succeeded on 688 * the last component of a namei lookup. 689 */ 690 int 691 unveil_check_final(struct proc *p, struct nameidata *ni) 692 { 693 struct process *pr = p->p_p; 694 struct unveil *uv = NULL, *nuv = NULL; 695 struct unvname *tname = NULL; 696 697 if (ni->ni_pledge == PLEDGE_UNVEIL || pr->ps_uvpaths == NULL) 698 return (0); 699 700 if (ni->ni_cnd.cn_flags & BYPASSUNVEIL) { 701 #ifdef DEBUG_UNVEIL 702 printf("unveil: %s(%d): BYPASSUNVEIL.\n", 703 pr->ps_comm, pr->ps_pid); 704 #endif 705 return (0); 706 } 707 708 if (ni->ni_vp != NULL && ni->ni_vp->v_type == VDIR) { 709 /* We are matching a directory terminal component */ 710 uv = unveil_lookup(ni->ni_vp, pr, NULL); 711 if (uv == NULL) { 712 #ifdef DEBUG_UNVEIL 713 printf("unveil: %s(%d) no match for vnode %p\n", 714 pr->ps_comm, pr->ps_pid, ni->ni_vp); 715 #endif 716 goto done; 717 } 718 if (!unveil_flagmatch(ni, uv->uv_flags)) { 719 #ifdef DEBUG_UNVEIL 720 printf("unveil: %s(%d) flag mismatch for directory" 721 " vnode %p\n", 722 pr->ps_comm, pr->ps_pid, ni->ni_vp); 723 #endif 724 pr->ps_acflag |= AUNVEIL; 725 if (uv->uv_flags & UNVEIL_USERSET) 726 return EACCES; 727 else 728 return ENOENT; 729 730 } 731 /* directory and flags match, success */ 732 #ifdef DEBUG_UNVEIL 733 printf("unveil: %s(%d): matched directory \"%s\" at vnode %p\n", 734 pr->ps_comm, pr->ps_pid, ni->ni_cnd.cn_nameptr, 735 uv->uv_vp); 736 #endif 737 return (0); 738 } 739 740 /* Otherwise, we are matching a non-terminal component */ 741 uv = unveil_lookup(ni->ni_dvp, pr, NULL); 742 if (uv == NULL) { 743 #ifdef DEBUG_UNVEIL 744 printf("unveil: %s(%d) no match for directory vnode %p\n", 745 pr->ps_comm, pr->ps_pid, ni->ni_dvp); 746 #endif 747 goto done; 748 } 749 if ((tname = unveil_namelookup(uv, ni->ni_cnd.cn_nameptr)) == NULL) { 750 #ifdef DEBUG_UNVEIL 751 printf("unveil: %s(%d) no match for terminal '%s' in " 752 "directory vnode %p\n", 753 pr->ps_comm, pr->ps_pid, 754 ni->ni_cnd.cn_nameptr, ni->ni_dvp); 755 #endif 756 /* no specific name, so check unveil directory flags */ 757 if (!unveil_flagmatch(ni, uv->uv_flags)) { 758 #ifdef DEBUG_UNVEIL 759 printf("unveil: %s(%d) terminal " 760 "'%s' flags mismatch in directory " 761 "vnode %p\n", 762 pr->ps_comm, pr->ps_pid, 763 ni->ni_cnd.cn_nameptr, ni->ni_dvp); 764 #endif 765 /* 766 * If dir has user set restrictions fail with 767 * EACCES. Otherwise, use any covering match 768 * that we found above this dir. 769 */ 770 if (uv->uv_flags & UNVEIL_USERSET) { 771 pr->ps_acflag |= AUNVEIL; 772 return EACCES; 773 } 774 /* start backtrack from this node */ 775 ni->ni_unveil_match = uv; 776 goto done; 777 } 778 /* directory flags match, success */ 779 #ifdef DEBUG_UNVEIL 780 printf("unveil: %s(%d): matched \"%s\" underneath vnode %p\n", 781 pr->ps_comm, pr->ps_pid, ni->ni_cnd.cn_nameptr, 782 uv->uv_vp); 783 #endif 784 return (0); 785 } 786 if (!unveil_flagmatch(ni, tname->un_flags)) { 787 /* do flags match for matched name */ 788 #ifdef DEBUG_UNVEIL 789 printf("unveil: %s(%d) flag mismatch for terminal '%s'\n", 790 pr->ps_comm, pr->ps_pid, tname->un_name); 791 #endif 792 pr->ps_acflag |= AUNVEIL; 793 return EACCES; 794 } 795 /* name and flags match. success */ 796 #ifdef DEBUG_UNVEIL 797 printf("unveil: %s(%d) matched terminal '%s'\n", 798 pr->ps_comm, pr->ps_pid, tname->un_name); 799 #endif 800 return (0); 801 802 done: 803 /* 804 * last component did not match, check previous matches if 805 * access is allowed or not. 806 */ 807 for (uv = ni->ni_unveil_match; uv != NULL; uv = nuv) { 808 if (unveil_flagmatch(ni, uv->uv_flags)) { 809 #ifdef DEBUG_UNVEIL 810 printf("unveil: %s(%d): matched \"%s\" underneath/at " 811 "vnode %p\n", pr->ps_comm, pr->ps_pid, 812 ni->ni_cnd.cn_nameptr, uv->uv_vp); 813 #endif 814 return (0); 815 } 816 /* if node has any flags set then this is an access violation */ 817 if (uv->uv_flags & UNVEIL_USERSET) { 818 #ifdef DEBUG_UNVEIL 819 printf("unveil: %s(%d) flag mismatch for vnode %p\n", 820 pr->ps_comm, pr->ps_pid, uv->uv_vp); 821 #endif 822 pr->ps_acflag |= AUNVEIL; 823 return EACCES; 824 } 825 #ifdef DEBUG_UNVEIL 826 printf("unveil: %s(%d) check cover for vnode %p, uv_cover %zd\n", 827 pr->ps_comm, pr->ps_pid, uv->uv_vp, uv->uv_cover); 828 #endif 829 nuv = unveil_covered(uv, uv->uv_vp, p); 830 if (nuv == uv) 831 break; 832 } 833 pr->ps_acflag |= AUNVEIL; 834 return ENOENT; 835 } 836 837 /* 838 * Scan all active processes to see if any of them have a unveil 839 * to this vnode. If so, NULL the vnode in their unveil list, 840 * vrele, drop the reference, and mark their unveil list 841 * as needing to have the hole shrunk the next time the process 842 * uses it for lookup. 843 */ 844 void 845 unveil_removevnode(struct vnode *vp) 846 { 847 struct process *pr; 848 849 if (vp->v_uvcount == 0) 850 return; 851 852 #ifdef DEBUG_UNVEIL 853 printf("unveil_removevnode found vnode %p with count %d\n", 854 vp, vp->v_uvcount); 855 #endif 856 vref(vp); /* make sure it is held till we are done */ 857 858 LIST_FOREACH(pr, &allprocess, ps_list) { 859 struct unveil * uv; 860 861 if ((uv = unveil_lookup(vp, pr, NULL)) != NULL && 862 uv->uv_vp != NULL) { 863 uv->uv_vp = NULL; 864 uv->uv_flags = 0; 865 #ifdef DEBUG_UNVEIL 866 printf("unveil_removevnode vnode %p now count %d\n", 867 vp, vp->v_uvcount); 868 #endif 869 if (vp->v_uvcount > 0) { 870 vrele(vp); 871 vp->v_uvcount--; 872 } else 873 panic("vp %p, v_uvcount of %d should be 0", 874 vp, vp->v_uvcount); 875 } 876 } 877 KASSERT(vp->v_uvcount == 0); 878 879 vrele(vp); /* release our ref */ 880 } 881