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