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