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