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