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