xref: /openbsd-src/sys/kern/kern_unveil.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
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