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