xref: /openbsd-src/sys/kern/kern_pledge.c (revision fb8aa7497fded39583f40e800732f9c046411717)
1 /*	$OpenBSD: kern_pledge.c,v 1.173 2016/06/28 04:27:58 semarie Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5  * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/types.h>
22 
23 #include <sys/mount.h>
24 #include <sys/proc.h>
25 #include <sys/fcntl.h>
26 #include <sys/file.h>
27 #include <sys/filedesc.h>
28 #include <sys/namei.h>
29 #include <sys/socketvar.h>
30 #include <sys/vnode.h>
31 #include <sys/mbuf.h>
32 #include <sys/mman.h>
33 #include <sys/sysctl.h>
34 #include <sys/ktrace.h>
35 
36 #include <sys/ioctl.h>
37 #include <sys/termios.h>
38 #include <sys/tty.h>
39 #include <sys/device.h>
40 #include <sys/disklabel.h>
41 #include <sys/dkio.h>
42 #include <sys/mtio.h>
43 #include <sys/audioio.h>
44 #include <net/bpf.h>
45 #include <net/route.h>
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <netinet/in.h>
49 #include <netinet6/in6_var.h>
50 #include <netinet6/nd6.h>
51 #include <netinet/tcp.h>
52 #include <net/pfvar.h>
53 
54 #include <sys/conf.h>
55 #include <sys/specdev.h>
56 #include <sys/signal.h>
57 #include <sys/signalvar.h>
58 #include <sys/syscall.h>
59 #include <sys/syscallargs.h>
60 #include <sys/systm.h>
61 
62 #include <dev/biovar.h>
63 
64 #define PLEDGENAMES
65 #include <sys/pledge.h>
66 
67 #include "audio.h"
68 #include "pty.h"
69 
70 #if defined(__amd64__)
71 #include "vmm.h"
72 #if NVMM > 0
73 #include <machine/conf.h>
74 #endif
75 #endif
76 
77 #if defined(__amd64__) || defined(__i386__) || \
78     defined(__macppc__) || defined(__sparc64__)
79 #include "drm.h"
80 #endif
81 
82 int pledgereq_flags(const char *req);
83 int canonpath(const char *input, char *buf, size_t bufsize);
84 int substrcmp(const char *p1, size_t s1, const char *p2, size_t s2);
85 int resolvpath(struct proc *p, char **rdir, size_t *rdirlen, char **cwd,
86     size_t *cwdlen, char *path, size_t pathlen, char **resolved,
87     size_t *resolvedlen);
88 
89 /* #define DEBUG_PLEDGE */
90 #ifdef DEBUG_PLEDGE
91 int debug_pledge = 1;
92 #define DPRINTF(x...)    do { if (debug_pledge) printf(x); } while (0)
93 #define DNPRINTF(n,x...) do { if (debug_pledge >= (n)) printf(x); } while (0)
94 #else
95 #define DPRINTF(x...)
96 #define DNPRINTF(n,x...)
97 #endif
98 
99 /*
100  * Ordered in blocks starting with least risky and most required.
101  */
102 const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = {
103 	/*
104 	 * Minimum required
105 	 */
106 	[SYS_exit] = PLEDGE_ALWAYS,
107 	[SYS_kbind] = PLEDGE_ALWAYS,
108 	[SYS___get_tcb] = PLEDGE_ALWAYS,
109 	[SYS_pledge] = PLEDGE_ALWAYS,
110 	[SYS_sendsyslog] = PLEDGE_ALWAYS,	/* stack protector reporting */
111 	[SYS_thrkill] = PLEDGE_ALWAYS,		/* raise, abort, stack pro */
112 	[SYS_utrace] = PLEDGE_ALWAYS,		/* ltrace(1) from ld.so */
113 
114 	/* "getting" information about self is considered safe */
115 	[SYS_getuid] = PLEDGE_STDIO,
116 	[SYS_geteuid] = PLEDGE_STDIO,
117 	[SYS_getresuid] = PLEDGE_STDIO,
118 	[SYS_getgid] = PLEDGE_STDIO,
119 	[SYS_getegid] = PLEDGE_STDIO,
120 	[SYS_getresgid] = PLEDGE_STDIO,
121 	[SYS_getgroups] = PLEDGE_STDIO,
122 	[SYS_getlogin59] = PLEDGE_STDIO,
123 	[SYS_getlogin_r] = PLEDGE_STDIO,
124 	[SYS_getpgrp] = PLEDGE_STDIO,
125 	[SYS_getpgid] = PLEDGE_STDIO,
126 	[SYS_getppid] = PLEDGE_STDIO,
127 	[SYS_getsid] = PLEDGE_STDIO,
128 	[SYS_getthrid] = PLEDGE_STDIO,
129 	[SYS_getrlimit] = PLEDGE_STDIO,
130 	[SYS_gettimeofday] = PLEDGE_STDIO,
131 	[SYS_getdtablecount] = PLEDGE_STDIO,
132 	[SYS_getrusage] = PLEDGE_STDIO,
133 	[SYS_issetugid] = PLEDGE_STDIO,
134 	[SYS_clock_getres] = PLEDGE_STDIO,
135 	[SYS_clock_gettime] = PLEDGE_STDIO,
136 	[SYS_getpid] = PLEDGE_STDIO,
137 
138 	/*
139 	 * Almost exclusively read-only, Very narrow subset.
140 	 * Use of "route", "inet", "dns", "ps", or "vminfo"
141 	 * expands access.
142 	 */
143 	[SYS_sysctl] = PLEDGE_STDIO,
144 
145 	/* Support for malloc(3) family of operations */
146 	[SYS_getentropy] = PLEDGE_STDIO,
147 	[SYS_madvise] = PLEDGE_STDIO,
148 	[SYS_minherit] = PLEDGE_STDIO,
149 	[SYS_mmap] = PLEDGE_STDIO,
150 	[SYS_mprotect] = PLEDGE_STDIO,
151 	[SYS_mquery] = PLEDGE_STDIO,
152 	[SYS_munmap] = PLEDGE_STDIO,
153 	[SYS_msync] = PLEDGE_STDIO,
154 	[SYS_break] = PLEDGE_STDIO,
155 
156 	[SYS_umask] = PLEDGE_STDIO,
157 
158 	/* read/write operations */
159 	[SYS_read] = PLEDGE_STDIO,
160 	[SYS_readv] = PLEDGE_STDIO,
161 	[SYS_pread] = PLEDGE_STDIO,
162 	[SYS_preadv] = PLEDGE_STDIO,
163 	[SYS_write] = PLEDGE_STDIO,
164 	[SYS_writev] = PLEDGE_STDIO,
165 	[SYS_pwrite] = PLEDGE_STDIO,
166 	[SYS_pwritev] = PLEDGE_STDIO,
167 	[SYS_recvmsg] = PLEDGE_STDIO,
168 	[SYS_recvfrom] = PLEDGE_STDIO | PLEDGE_YPACTIVE,
169 	[SYS_ftruncate] = PLEDGE_STDIO,
170 	[SYS_lseek] = PLEDGE_STDIO,
171 	[SYS_fpathconf] = PLEDGE_STDIO,
172 
173 	/*
174 	 * Address selection required a network pledge ("inet",
175 	 * "unix", "dns".
176 	 */
177 	[SYS_sendto] = PLEDGE_STDIO | PLEDGE_YPACTIVE,
178 
179 	/*
180 	 * Address specification required a network pledge ("inet",
181 	 * "unix", "dns".  SCM_RIGHTS requires "sendfd" or "recvfd".
182 	 */
183 	[SYS_sendmsg] = PLEDGE_STDIO,
184 
185 	/* Common signal operations */
186 	[SYS_nanosleep] = PLEDGE_STDIO,
187 	[SYS_sigaltstack] = PLEDGE_STDIO,
188 	[SYS_sigprocmask] = PLEDGE_STDIO,
189 	[SYS_sigsuspend] = PLEDGE_STDIO,
190 	[SYS_sigaction] = PLEDGE_STDIO,
191 	[SYS_sigreturn] = PLEDGE_STDIO,
192 	[SYS_sigpending] = PLEDGE_STDIO,
193 	[SYS_getitimer] = PLEDGE_STDIO,
194 	[SYS_setitimer] = PLEDGE_STDIO,
195 
196 	/*
197 	 * To support event driven programming.
198 	 */
199 	[SYS_poll] = PLEDGE_STDIO,
200 	[SYS_ppoll] = PLEDGE_STDIO,
201 	[SYS_kevent] = PLEDGE_STDIO,
202 	[SYS_kqueue] = PLEDGE_STDIO,
203 	[SYS_select] = PLEDGE_STDIO,
204 	[SYS_pselect] = PLEDGE_STDIO,
205 
206 	[SYS_fstat] = PLEDGE_STDIO,
207 	[SYS_fsync] = PLEDGE_STDIO,
208 
209 	[SYS_setsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
210 	[SYS_getsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
211 
212 	/* F_SETOWN requires PLEDGE_PROC */
213 	[SYS_fcntl] = PLEDGE_STDIO,
214 
215 	[SYS_close] = PLEDGE_STDIO,
216 	[SYS_dup] = PLEDGE_STDIO,
217 	[SYS_dup2] = PLEDGE_STDIO,
218 	[SYS_dup3] = PLEDGE_STDIO,
219 	[SYS_closefrom] = PLEDGE_STDIO,
220 	[SYS_shutdown] = PLEDGE_STDIO,
221 	[SYS_fchdir] = PLEDGE_STDIO,	/* XXX consider tightening */
222 
223 	[SYS_pipe] = PLEDGE_STDIO,
224 	[SYS_pipe2] = PLEDGE_STDIO,
225 	[SYS_socketpair] = PLEDGE_STDIO,
226 
227 	[SYS_wait4] = PLEDGE_STDIO,
228 
229 	/*
230 	 * Can kill self with "stdio".  Killing another pid
231 	 * requires "proc"
232 	 */
233 	[SYS_o58_kill] = PLEDGE_STDIO,
234 	[SYS_kill] = PLEDGE_STDIO,
235 
236 	/*
237 	 * FIONREAD/FIONBIO for "stdio"
238 	 * A few non-tty ioctl available using "ioctl"
239 	 * tty-centric ioctl available using "tty"
240 	 */
241 	[SYS_ioctl] = PLEDGE_STDIO,
242 
243 	/*
244 	 * Path access/creation calls encounter many extensive
245 	 * checks are done during namei()
246 	 */
247 	[SYS_open] = PLEDGE_STDIO,
248 	[SYS_stat] = PLEDGE_STDIO,
249 	[SYS_access] = PLEDGE_STDIO,
250 	[SYS_readlink] = PLEDGE_STDIO,
251 
252 	[SYS_adjtime] = PLEDGE_STDIO,   /* setting requires "settime" */
253 	[SYS_adjfreq] = PLEDGE_SETTIME,
254 	[SYS_settimeofday] = PLEDGE_SETTIME,
255 
256 	/*
257 	 * Needed by threaded programs
258 	 * XXX should we have a new "threads"?
259 	 */
260 	[SYS___tfork] = PLEDGE_STDIO,
261 	[SYS_sched_yield] = PLEDGE_STDIO,
262 	[SYS___thrsleep] = PLEDGE_STDIO,
263 	[SYS___thrwakeup] = PLEDGE_STDIO,
264 	[SYS___threxit] = PLEDGE_STDIO,
265 	[SYS___thrsigdivert] = PLEDGE_STDIO,
266 
267 	[SYS_fork] = PLEDGE_PROC,
268 	[SYS_vfork] = PLEDGE_PROC,
269 	[SYS_setpgid] = PLEDGE_PROC,
270 	[SYS_setsid] = PLEDGE_PROC,
271 
272 	[SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
273 	[SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
274 
275 	[SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
276 
277 	[SYS_setuid] = PLEDGE_ID,
278 	[SYS_seteuid] = PLEDGE_ID,
279 	[SYS_setreuid] = PLEDGE_ID,
280 	[SYS_setresuid] = PLEDGE_ID,
281 	[SYS_setgid] = PLEDGE_ID,
282 	[SYS_setegid] = PLEDGE_ID,
283 	[SYS_setregid] = PLEDGE_ID,
284 	[SYS_setresgid] = PLEDGE_ID,
285 	[SYS_setgroups] = PLEDGE_ID,
286 	[SYS_setlogin] = PLEDGE_ID,
287 
288 	[SYS_execve] = PLEDGE_EXEC,
289 
290 	[SYS_chdir] = PLEDGE_RPATH,
291 	[SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
292 	[SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
293 	[SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
294 	[SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
295 	[SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
296 	[SYS_truncate] = PLEDGE_WPATH,
297 	[SYS_rename] = PLEDGE_RPATH | PLEDGE_CPATH,
298 	[SYS_rmdir] = PLEDGE_CPATH,
299 	[SYS_renameat] = PLEDGE_CPATH,
300 	[SYS_link] = PLEDGE_CPATH,
301 	[SYS_linkat] = PLEDGE_CPATH,
302 	[SYS_symlink] = PLEDGE_CPATH,
303 	[SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
304 	[SYS_unlinkat] = PLEDGE_CPATH,
305 	[SYS_mkdir] = PLEDGE_CPATH,
306 	[SYS_mkdirat] = PLEDGE_CPATH,
307 
308 	[SYS_mkfifo] = PLEDGE_DPATH,
309 	[SYS_mknod] = PLEDGE_DPATH,
310 
311 	[SYS_revoke] = PLEDGE_TTY,	/* also requires PLEDGE_RPATH */
312 
313 	/*
314 	 * Classify as RPATH|WPATH, because of path information leakage.
315 	 * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
316 	 */
317 	[SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
318 
319 	/* Classify as RPATH, because these leak path information */
320 	[SYS_getdents] = PLEDGE_RPATH,
321 	[SYS_getfsstat] = PLEDGE_RPATH,
322 	[SYS_statfs] = PLEDGE_RPATH,
323 	[SYS_fstatfs] = PLEDGE_RPATH,
324 	[SYS_pathconf] = PLEDGE_RPATH,
325 
326 	[SYS_utimes] = PLEDGE_FATTR,
327 	[SYS_futimes] = PLEDGE_FATTR,
328 	[SYS_utimensat] = PLEDGE_FATTR,
329 	[SYS_futimens] = PLEDGE_FATTR,
330 	[SYS_chmod] = PLEDGE_FATTR,
331 	[SYS_fchmod] = PLEDGE_FATTR,
332 	[SYS_fchmodat] = PLEDGE_FATTR,
333 	[SYS_chflags] = PLEDGE_FATTR,
334 	[SYS_chflagsat] = PLEDGE_FATTR,
335 	[SYS_fchflags] = PLEDGE_FATTR,
336 	[SYS_chown] = PLEDGE_FATTR,
337 	[SYS_fchownat] = PLEDGE_FATTR,
338 	[SYS_lchown] = PLEDGE_FATTR,
339 	[SYS_fchown] = PLEDGE_FATTR,
340 
341 	[SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
342 	[SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
343 	[SYS_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
344 	[SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
345 
346 	[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
347 	[SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
348 	[SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
349 	[SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
350 
351 	[SYS_flock] = PLEDGE_FLOCK | PLEDGE_YPACTIVE,
352 
353 	[SYS_swapctl] = PLEDGE_VMINFO,	/* XXX should limit to "get" operations */
354 };
355 
356 static const struct {
357 	char *name;
358 	uint64_t flags;
359 } pledgereq[] = {
360 	{ "audio",		PLEDGE_AUDIO },
361 	{ "cpath",		PLEDGE_CPATH },
362 	{ "disklabel",		PLEDGE_DISKLABEL },
363 	{ "dns",		PLEDGE_DNS },
364 	{ "dpath",		PLEDGE_DPATH },
365 	{ "drm",		PLEDGE_DRM },
366 	{ "exec",		PLEDGE_EXEC },
367 	{ "fattr",		PLEDGE_FATTR },
368 	{ "flock",		PLEDGE_FLOCK },
369 	{ "getpw",		PLEDGE_GETPW },
370 	{ "id",			PLEDGE_ID },
371 	{ "inet",		PLEDGE_INET },
372 	{ "ioctl",		PLEDGE_IOCTL },
373 	{ "mcast",		PLEDGE_MCAST },
374 	{ "pf",			PLEDGE_PF },
375 	{ "proc",		PLEDGE_PROC },
376 	{ "prot_exec",		PLEDGE_PROTEXEC },
377 	{ "ps",			PLEDGE_PS },
378 	{ "recvfd",		PLEDGE_RECVFD },
379 	{ "route",		PLEDGE_ROUTE },
380 	{ "rpath",		PLEDGE_RPATH },
381 	{ "sendfd",		PLEDGE_SENDFD },
382 	{ "settime",		PLEDGE_SETTIME },
383 	{ "stdio",		PLEDGE_STDIO },
384 	{ "tmppath",		PLEDGE_TMPPATH },
385 	{ "tty",		PLEDGE_TTY },
386 	{ "unix",		PLEDGE_UNIX },
387 	{ "vminfo",		PLEDGE_VMINFO },
388 	{ "vmm",		PLEDGE_VMM },
389 	{ "wpath",		PLEDGE_WPATH },
390 };
391 
392 int
393 sys_pledge(struct proc *p, void *v, register_t *retval)
394 {
395 	struct sys_pledge_args /* {
396 		syscallarg(const char *)request;
397 		syscallarg(const char **)paths;
398 	} */	*uap = v;
399 	uint64_t flags = 0;
400 	int error;
401 
402 	if (SCARG(uap, request)) {
403 		size_t rbuflen;
404 		char *rbuf, *rp, *pn;
405 		int f;
406 
407 		rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
408 		error = copyinstr(SCARG(uap, request), rbuf, MAXPATHLEN,
409 		    &rbuflen);
410 		if (error) {
411 			free(rbuf, M_TEMP, MAXPATHLEN);
412 			return (error);
413 		}
414 #ifdef KTRACE
415 		if (KTRPOINT(p, KTR_STRUCT))
416 			ktrstruct(p, "pledgereq", rbuf, rbuflen-1);
417 #endif
418 
419 		for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
420 			pn = strchr(rp, ' ');	/* find terminator */
421 			if (pn) {
422 				while (*pn == ' ')
423 					*pn++ = '\0';
424 			}
425 
426 			if ((f = pledgereq_flags(rp)) == 0) {
427 				free(rbuf, M_TEMP, MAXPATHLEN);
428 				return (EINVAL);
429 			}
430 			flags |= f;
431 		}
432 		free(rbuf, M_TEMP, MAXPATHLEN);
433 
434 		/*
435 		 * if we are already pledged, allow only promises reductions.
436 		 * flags doesn't contain flags outside _USERSET: they will be
437 		 * relearned.
438 		 */
439 		if (ISSET(p->p_p->ps_flags, PS_PLEDGE) &&
440 		    (((flags | p->p_p->ps_pledge) != p->p_p->ps_pledge)))
441 			return (EPERM);
442 	}
443 
444 	if (SCARG(uap, paths)) {
445 #if 1
446 		return (EINVAL);
447 #else
448 		const char **u = SCARG(uap, paths), *sp;
449 		struct whitepaths *wl;
450 		char *path, *rdir = NULL, *cwd = NULL;
451 		size_t pathlen, rdirlen, cwdlen;
452 
453 		size_t maxargs = 0;
454 		int i, error;
455 
456 		if (p->p_p->ps_pledgepaths)
457 			return (EPERM);
458 
459 		/* Count paths */
460 		for (i = 0; i < PLEDGE_MAXPATHS; i++) {
461 			if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
462 				return (error);
463 			if (sp == NULL)
464 				break;
465 		}
466 		if (i == PLEDGE_MAXPATHS)
467 			return (E2BIG);
468 
469 		wl = malloc(sizeof *wl + sizeof(struct whitepath) * (i+1),
470 		    M_TEMP, M_WAITOK | M_ZERO);
471 		wl->wl_size = sizeof *wl + sizeof(struct whitepath) * (i+1);
472 		wl->wl_count = i;
473 		wl->wl_ref = 1;
474 
475 		path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
476 
477 		/* Copy in */
478 		for (i = 0; i < wl->wl_count; i++) {
479 			char *resolved = NULL;
480 			size_t resolvedlen;
481 
482 			if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
483 				break;
484 			if (sp == NULL)
485 				break;
486 			if ((error = copyinstr(sp, path, MAXPATHLEN, &pathlen)) != 0)
487 				break;
488 #ifdef KTRACE
489 			if (KTRPOINT(p, KTR_STRUCT))
490 				ktrstruct(p, "pledgepath", path, pathlen-1);
491 #endif
492 
493 			error = resolvpath(p, &rdir, &rdirlen, &cwd, &cwdlen,
494 			    path, pathlen, &resolved, &resolvedlen);
495 
496 			if (error != 0)
497 				/* resolved is allocated only if !error */
498 				break;
499 
500 			maxargs += resolvedlen;
501 			if (maxargs > ARG_MAX) {
502 				error = E2BIG;
503 				free(resolved, M_TEMP, resolvedlen);
504 				break;
505 			}
506 			wl->wl_paths[i].name = resolved;
507 			wl->wl_paths[i].len = resolvedlen;
508 		}
509 		free(rdir, M_TEMP, rdirlen);
510 		free(cwd, M_TEMP, cwdlen);
511 		free(path, M_TEMP, MAXPATHLEN);
512 
513 		if (error) {
514 			for (i = 0; i < wl->wl_count; i++)
515 				free(wl->wl_paths[i].name,
516 				    M_TEMP, wl->wl_paths[i].len);
517 			free(wl, M_TEMP, wl->wl_size);
518 			return (error);
519 		}
520 		p->p_p->ps_pledgepaths = wl;
521 
522 #ifdef DEBUG_PLEDGE
523 		/* print paths registered as whilelisted (viewed as without chroot) */
524 		DNPRINTF(1, "pledge: %s(%d): paths loaded:\n", p->p_comm,
525 		    p->p_pid);
526 		for (i = 0; i < wl->wl_count; i++)
527 			if (wl->wl_paths[i].name)
528 				DNPRINTF(1, "pledge: %d=\"%s\" [%lld]\n", i,
529 				    wl->wl_paths[i].name,
530 				    (long long)wl->wl_paths[i].len);
531 #endif
532 #endif
533 	}
534 
535 	if (SCARG(uap, request)) {
536 		p->p_p->ps_pledge = flags;
537 		p->p_p->ps_flags |= PS_PLEDGE;
538 	}
539 
540 	return (0);
541 }
542 
543 int
544 pledge_syscall(struct proc *p, int code, int *tval)
545 {
546 	p->p_pledge_syscall = code;
547 	*tval = 0;
548 
549 	if (code < 0 || code > SYS_MAXSYSCALL - 1)
550 		return (EINVAL);
551 
552 	if (pledge_syscalls[code] == PLEDGE_ALWAYS)
553 		return (0);
554 
555 	if (p->p_p->ps_pledge & pledge_syscalls[code])
556 		return (0);
557 
558 	*tval = pledge_syscalls[code];
559 	return (EPERM);
560 }
561 
562 int
563 pledge_fail(struct proc *p, int error, uint64_t code)
564 {
565 	char *codes = "";
566 	int i;
567 	struct sigaction sa;
568 
569 	/* Print first matching pledge */
570 	for (i = 0; code && pledgenames[i].bits != 0; i++)
571 		if (pledgenames[i].bits & code) {
572 			codes = pledgenames[i].name;
573 			break;
574 		}
575 	printf("%s(%d): syscall %d \"%s\"\n", p->p_comm, p->p_pid,
576 	    p->p_pledge_syscall, codes);
577 #ifdef KTRACE
578 	ktrpledge(p, error, code, p->p_pledge_syscall);
579 #endif
580 	/* Send uncatchable SIGABRT for coredump */
581 	memset(&sa, 0, sizeof sa);
582 	sa.sa_handler = SIG_DFL;
583 	setsigvec(p, SIGABRT, &sa);
584 	psignal(p, SIGABRT);
585 
586 	p->p_p->ps_pledge = 0;		/* Disable all PLEDGE_ flags */
587 	return (error);
588 }
589 
590 /*
591  * Need to make it more obvious that one cannot get through here
592  * without the right flags set
593  */
594 int
595 pledge_namei(struct proc *p, struct nameidata *ni, char *origpath)
596 {
597 	char path[PATH_MAX];
598 	int error;
599 
600 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0 ||
601 	    (p->p_p->ps_flags & PS_COREDUMP))
602 		return (0);
603 
604 	if (!ni || (ni->ni_pledge == 0))
605 		panic("ni_pledge");
606 
607 	/* Doing a permitted execve() */
608 	if ((ni->ni_pledge & PLEDGE_EXEC) &&
609 	    (p->p_p->ps_pledge & PLEDGE_EXEC))
610 		return (0);
611 
612 	error = canonpath(origpath, path, sizeof(path));
613 	if (error)
614 		return (error);
615 
616 	/* Detect what looks like a mkstemp(3) family operation */
617 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
618 	    (p->p_pledge_syscall == SYS_open) &&
619 	    (ni->ni_pledge & PLEDGE_CPATH) &&
620 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
621 		return (0);
622 	}
623 
624 	/* Allow unlinking of a mkstemp(3) file...
625 	 * Good opportunity for strict checks here.
626 	 */
627 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
628 	    (p->p_pledge_syscall == SYS_unlink) &&
629 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
630 		return (0);
631 	}
632 
633 	/* Whitelisted paths */
634 	switch (p->p_pledge_syscall) {
635 	case SYS_access:
636 		/* tzset() needs this. */
637 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
638 		    strcmp(path, "/etc/localtime") == 0)
639 			return (0);
640 
641 		/* when avoiding YP mode, getpw* functions touch this */
642 		if (ni->ni_pledge == PLEDGE_RPATH &&
643 		    strcmp(path, "/var/run/ypbind.lock") == 0) {
644 			if (p->p_p->ps_pledge & PLEDGE_GETPW)
645 				return (0);
646 			else
647 				return (pledge_fail(p, error, PLEDGE_GETPW));
648 		}
649 		break;
650 	case SYS_open:
651 		/* daemon(3) or other such functions */
652 		if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
653 		    strcmp(path, "/dev/null") == 0) {
654 			return (0);
655 		}
656 
657 		/* readpassphrase(3), getpass(3) */
658 		if ((p->p_p->ps_pledge & PLEDGE_TTY) &&
659 		    (ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
660 		    strcmp(path, "/dev/tty") == 0) {
661 			return (0);
662 		}
663 
664 		/* getpw* and friends need a few files */
665 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
666 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
667 			if (strcmp(path, "/etc/spwd.db") == 0)
668 				return (EPERM); /* don't call pledge_fail */
669 			if (strcmp(path, "/etc/pwd.db") == 0)
670 				return (0);
671 			if (strcmp(path, "/etc/group") == 0)
672 				return (0);
673 			if (strcmp(path, "/etc/netid") == 0)
674 				return (0);
675 		}
676 
677 		/* DNS needs /etc/{resolv.conf,hosts,services}. */
678 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
679 		    (p->p_p->ps_pledge & PLEDGE_DNS)) {
680 			if (strcmp(path, "/etc/resolv.conf") == 0)
681 				return (0);
682 			if (strcmp(path, "/etc/hosts") == 0)
683 				return (0);
684 			if (strcmp(path, "/etc/services") == 0)
685 				return (0);
686 		}
687 
688 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
689 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
690 			if (strcmp(path, "/var/run/ypbind.lock") == 0) {
691 				/*
692 				 * XXX
693 				 * The current hack for YP support in "getpw"
694 				 * is to enable some "inet" features until
695 				 * next pledge call.  This is not considered
696 				 * worse than pre-pledge, but is a work in
697 				 * progress, needing a clever design.
698 				 */
699 				p->p_p->ps_pledge |= PLEDGE_YPACTIVE;
700 				return (0);
701 			}
702 			if (strncmp(path, "/var/yp/binding/",
703 			    sizeof("/var/yp/binding/") - 1) == 0)
704 				return (0);
705 		}
706 
707 		/* tzset() needs these. */
708 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
709 		    strncmp(path, "/usr/share/zoneinfo/",
710 		    sizeof("/usr/share/zoneinfo/") - 1) == 0)
711 			return (0);
712 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
713 		    strcmp(path, "/etc/localtime") == 0)
714 			return (0);
715 
716 		break;
717 	case SYS_readlink:
718 		/* Allow /etc/malloc.conf for malloc(3). */
719 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
720 		    strcmp(path, "/etc/malloc.conf") == 0)
721 			return (0);
722 		break;
723 	case SYS_stat:
724 		/* DNS needs /etc/resolv.conf. */
725 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
726 		    (p->p_p->ps_pledge & PLEDGE_DNS) &&
727 		    strcmp(path, "/etc/resolv.conf") == 0)
728 			return (0);
729 		break;
730 	}
731 
732 	/*
733 	 * Ensure each flag of p_pledgenote has counterpart allowing it in
734 	 * ps_pledge
735 	 */
736 	if (ni->ni_pledge & ~p->p_p->ps_pledge)
737 		return (pledge_fail(p, EPERM, (ni->ni_pledge & ~p->p_p->ps_pledge)));
738 
739 	return (0);
740 }
741 
742 /*
743  * wlpath lookup - only done after namei lookup has succeeded on the last compoent of
744  * a namei lookup, with a possibly non-canonicalized path given in "origpath" from namei.
745  */
746 int
747 pledge_namei_wlpath(struct proc *p, struct nameidata *ni)
748 {
749 	struct whitepaths *wl = p->p_p->ps_pledgepaths;
750 	char *rdir = NULL, *cwd = NULL, *resolved = NULL;
751 	size_t rdirlen, cwdlen, resolvedlen;
752 	int i, error, pardir_found;
753 
754 	/*
755 	 * If a whitelist is set, compare canonical paths.  Anything
756 	 * not on the whitelist gets ENOENT.
757 	 */
758 	if (ni->ni_p_path == NULL)
759 		return(0);
760 
761 	KASSERT(p->p_p->ps_pledgepaths);
762 
763 	// XXX change later or more help from namei?
764 	error = resolvpath(p, &rdir, &rdirlen, &cwd, &cwdlen,
765 	    ni->ni_p_path, ni->ni_p_length+1, &resolved, &resolvedlen);
766 
767 	free(rdir, M_TEMP, rdirlen);
768 	free(cwd, M_TEMP, cwdlen);
769 
770 	if (error != 0)
771 		/* resolved is allocated only if !error */
772 		return (error);
773 
774 	/* print resolved path (viewed as without chroot) */
775 	DNPRINTF(2, "pledge_namei: resolved=\"%s\" [%lld] strlen=%lld\n",
776 	    resolved, (long long)resolvedlen,
777 	    (long long)strlen(resolved));
778 
779 	error = ENOENT;
780 	pardir_found = 0;
781 	for (i = 0; i < wl->wl_count && wl->wl_paths[i].name && error; i++) {
782 		int substr = substrcmp(wl->wl_paths[i].name,
783 		    wl->wl_paths[i].len - 1, resolved, resolvedlen - 1);
784 
785 		/* print check between registered wl_path and resolved */
786 		DNPRINTF(3,
787 		    "pledge: check: \"%s\" (%ld) \"%s\" (%ld) = %d\n",
788 		    wl->wl_paths[i].name, wl->wl_paths[i].len - 1,
789 		    resolved, resolvedlen - 1,
790 		    substr);
791 
792 		/* wl_paths[i].name is a substring of resolved */
793 		if (substr == 1) {
794 			u_char term = resolved[wl->wl_paths[i].len - 1];
795 
796 			if (term == '\0' || term == '/' ||
797 			    wl->wl_paths[i].name[1] == '\0')
798 				error = 0;
799 
800 			/* resolved is a substring of wl_paths[i].name */
801 		} else if (substr == 2) {
802 			u_char term = wl->wl_paths[i].name[resolvedlen - 1];
803 
804 			if (resolved[1] == '\0' || term == '/')
805 				pardir_found = 1;
806 		}
807 	}
808 	if (pardir_found)
809 		switch (p->p_pledge_syscall) {
810 		case SYS_stat:
811 		case SYS_lstat:
812 		case SYS_fstatat:
813 		case SYS_fstat:
814 			ni->ni_pledge |= PLEDGE_STATLIE;
815 			error = 0;
816 		}
817 
818 #ifdef DEBUG_PLEDGE
819 	if (error == ENOENT)
820 		/* print the path that is reported as ENOENT */
821 		DNPRINTF(1, "pledge: %s(%d): wl_path ENOENT: \"%s\"\n",
822 		    p->p_comm, p->p_pid, resolved);
823 #endif
824 
825 	free(resolved, M_TEMP, resolvedlen);
826 	return (error);			/* Don't hint why it failed */
827 }
828 
829 /*
830  * Only allow reception of safe file descriptors.
831  */
832 int
833 pledge_recvfd(struct proc *p, struct file *fp)
834 {
835 	struct vnode *vp = NULL;
836 	char *vtypes[] = { VTYPE_NAMES };
837 
838 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
839 		return (0);
840 	if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0) {
841 		printf("recvmsg not allowed\n");
842 		return pledge_fail(p, EPERM, PLEDGE_RECVFD);
843 	}
844 
845 	switch (fp->f_type) {
846 	case DTYPE_SOCKET:
847 	case DTYPE_PIPE:
848 		return (0);
849 	case DTYPE_VNODE:
850 		vp = fp->f_data;
851 
852 		if (vp->v_type != VDIR)
853 			return (0);
854 		break;
855 	}
856 	printf("recvfd type %d %s\n", fp->f_type, vp ? vtypes[vp->v_type] : "");
857 	return pledge_fail(p, EINVAL, PLEDGE_RECVFD);
858 }
859 
860 /*
861  * Only allow sending of safe file descriptors.
862  */
863 int
864 pledge_sendfd(struct proc *p, struct file *fp)
865 {
866 	struct vnode *vp = NULL;
867 	char *vtypes[] = { VTYPE_NAMES };
868 
869 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
870 		return (0);
871 
872 	if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0) {
873 		printf("sendmsg not allowed\n");
874 		return pledge_fail(p, EPERM, PLEDGE_SENDFD);
875 	}
876 
877 	switch (fp->f_type) {
878 	case DTYPE_SOCKET:
879 	case DTYPE_PIPE:
880 		return (0);
881 	case DTYPE_VNODE:
882 		vp = fp->f_data;
883 
884 		if (vp->v_type != VDIR)
885 			return (0);
886 		break;
887 	}
888 	printf("sendfd type %d %s\n", fp->f_type, vp ? vtypes[vp->v_type] : "");
889 	return pledge_fail(p, EINVAL, PLEDGE_SENDFD);
890 }
891 
892 int
893 pledge_sysctl(struct proc *p, int miblen, int *mib, void *new)
894 {
895 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
896 		return (0);
897 
898 	if (new)
899 		return pledge_fail(p, EFAULT, 0);
900 
901 	/* routing table observation */
902 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
903 		if ((miblen == 6 || miblen == 7) &&
904 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
905 		    mib[2] == 0 &&
906 		    mib[4] == NET_RT_DUMP)
907 			return (0);
908 
909 		if (miblen == 6 &&
910 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
911 		    mib[2] == 0 &&
912 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
913 		    mib[4] == NET_RT_TABLE)
914 			return (0);
915 
916 		if (miblen == 7 &&		/* exposes MACs */
917 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
918 		    mib[2] == 0 &&
919 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
920 		    mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
921 			return (0);
922 	}
923 
924 	if (p->p_p->ps_pledge & (PLEDGE_PS | PLEDGE_VMINFO)) {
925 		if (miblen == 2 &&		/* kern.fscale */
926 		    mib[0] == CTL_KERN && mib[1] == KERN_FSCALE)
927 			return (0);
928 		if (miblen == 2 &&		/* kern.boottime */
929 		    mib[0] == CTL_KERN && mib[1] == KERN_BOOTTIME)
930 			return (0);
931 		if (miblen == 2 &&		/* kern.consdev */
932 		    mib[0] == CTL_KERN && mib[1] == KERN_CONSDEV)
933 			return (0);
934 		if (miblen == 2 &&			/* kern.cptime */
935 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME)
936 			return (0);
937 		if (miblen == 3 &&			/* kern.cptime2 */
938 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME2)
939 			return (0);
940 	}
941 
942 	if ((p->p_p->ps_pledge & PLEDGE_PS)) {
943 		if (miblen == 4 &&		/* kern.procargs.* */
944 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_ARGS &&
945 		    (mib[3] == KERN_PROC_ARGV || mib[3] == KERN_PROC_ENV))
946 			return (0);
947 		if (miblen == 6 &&		/* kern.proc.* */
948 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC)
949 			return (0);
950 		if (miblen == 3 &&		/* kern.proc_cwd.* */
951 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_CWD)
952 			return (0);
953 		if (miblen == 2 &&		/* hw.physmem */
954 		    mib[0] == CTL_HW && mib[1] == HW_PHYSMEM64)
955 			return (0);
956 		if (miblen == 2 &&		/* kern.ccpu */
957 		    mib[0] == CTL_KERN && mib[1] == KERN_CCPU)
958 			return (0);
959 		if (miblen == 2 &&		/* vm.maxslp */
960 		    mib[0] == CTL_VM && mib[1] == VM_MAXSLP)
961 			return (0);
962 	}
963 
964 	if ((p->p_p->ps_pledge & PLEDGE_VMINFO)) {
965 		if (miblen == 2 &&		/* vm.uvmexp */
966 		    mib[0] == CTL_VM && mib[1] == VM_UVMEXP)
967 			return (0);
968 		if (miblen == 3 &&		/* vfs.generic.bcachestat */
969 		    mib[0] == CTL_VFS && mib[1] == VFS_GENERIC &&
970 		    mib[2] == VFS_BCACHESTAT)
971 			return (0);
972 	}
973 
974 	if ((p->p_p->ps_pledge & (PLEDGE_ROUTE | PLEDGE_INET | PLEDGE_DNS))) {
975 		if (miblen == 6 &&		/* getifaddrs() */
976 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
977 		    mib[2] == 0 &&
978 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
979 		    mib[4] == NET_RT_IFLIST)
980 			return (0);
981 	}
982 
983 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
984 		if (miblen == 2 &&		/* kern.rawpartition */
985 		    mib[0] == CTL_KERN &&
986 		    mib[1] == KERN_RAWPARTITION)
987 			return (0);
988 		if (miblen == 2 &&		/* kern.maxpartitions */
989 		    mib[0] == CTL_KERN &&
990 		    mib[1] == KERN_MAXPARTITIONS)
991 			return (0);
992 #ifdef CPU_CHR2BLK
993 		if (miblen == 3 &&		/* machdep.chr2blk */
994 		    mib[0] == CTL_MACHDEP &&
995 		    mib[1] == CPU_CHR2BLK)
996 			return (0);
997 #endif /* CPU_CHR2BLK */
998 	}
999 
1000 	if (miblen >= 3 &&			/* ntpd(8) to read sensors */
1001 	    mib[0] == CTL_HW && mib[1] == HW_SENSORS)
1002 		return (0);
1003 
1004 	if (miblen == 2 &&		/* getdomainname() */
1005 	    mib[0] == CTL_KERN && mib[1] == KERN_DOMAINNAME)
1006 		return (0);
1007 	if (miblen == 2 &&		/* gethostname() */
1008 	    mib[0] == CTL_KERN && mib[1] == KERN_HOSTNAME)
1009 		return (0);
1010 	if (miblen == 6 &&		/* if_nameindex() */
1011 	    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
1012 	    mib[2] == 0 && mib[3] == 0 && mib[4] == NET_RT_IFNAMES)
1013 		return (0);
1014 	if (miblen == 2 &&		/* uname() */
1015 	    mib[0] == CTL_KERN && mib[1] == KERN_OSTYPE)
1016 		return (0);
1017 	if (miblen == 2 &&		/* uname() */
1018 	    mib[0] == CTL_KERN && mib[1] == KERN_OSRELEASE)
1019 		return (0);
1020 	if (miblen == 2 &&		/* uname() */
1021 	    mib[0] == CTL_KERN && mib[1] == KERN_OSVERSION)
1022 		return (0);
1023 	if (miblen == 2 &&		/* uname() */
1024 	    mib[0] == CTL_KERN && mib[1] == KERN_VERSION)
1025 		return (0);
1026 	if (miblen == 2 &&		/* kern.clockrate */
1027 	    mib[0] == CTL_KERN && mib[1] == KERN_CLOCKRATE)
1028 		return (0);
1029 	if (miblen == 2 &&		/* kern.argmax */
1030 	    mib[0] == CTL_KERN && mib[1] == KERN_ARGMAX)
1031 		return (0);
1032 	if (miblen == 2 &&		/* kern.ngroups */
1033 	    mib[0] == CTL_KERN && mib[1] == KERN_NGROUPS)
1034 		return (0);
1035 	if (miblen == 2 &&		/* kern.sysvshm */
1036 	    mib[0] == CTL_KERN && mib[1] == KERN_SYSVSHM)
1037 		return (0);
1038 	if (miblen == 2 &&		/* kern.posix1version */
1039 	    mib[0] == CTL_KERN && mib[1] == KERN_POSIX1)
1040 		return (0);
1041 	if (miblen == 2 &&		/* uname() */
1042 	    mib[0] == CTL_HW && mib[1] == HW_MACHINE)
1043 		return (0);
1044 	if (miblen == 2 &&		/* getpagesize() */
1045 	    mib[0] == CTL_HW && mib[1] == HW_PAGESIZE)
1046 		return (0);
1047 	if (miblen == 2 &&		/* setproctitle() */
1048 	    mib[0] == CTL_VM && mib[1] == VM_PSSTRINGS)
1049 		return (0);
1050 	if (miblen == 2 &&		/* hw.ncpu */
1051 	    mib[0] == CTL_HW && mib[1] == HW_NCPU)
1052 		return (0);
1053 	if (miblen == 2 &&		/* kern.loadavg / getloadavg(3) */
1054 	    mib[0] == CTL_VM && mib[1] == VM_LOADAVG)
1055 		return (0);
1056 
1057 	printf("%s(%d): sysctl %d: %d %d %d %d %d %d\n",
1058 	    p->p_comm, p->p_pid, miblen, mib[0], mib[1],
1059 	    mib[2], mib[3], mib[4], mib[5]);
1060 	return pledge_fail(p, EINVAL, 0);
1061 }
1062 
1063 int
1064 pledge_chown(struct proc *p, uid_t uid, gid_t gid)
1065 {
1066 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1067 		return (0);
1068 
1069 	if (uid != -1 && uid != p->p_ucred->cr_uid)
1070 		return (EPERM);
1071 	if (gid != -1 && !groupmember(gid, p->p_ucred))
1072 		return (EPERM);
1073 	return (0);
1074 }
1075 
1076 int
1077 pledge_adjtime(struct proc *p, const void *v)
1078 {
1079 	const struct timeval *delta = v;
1080 
1081 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1082 		return (0);
1083 
1084 	if ((p->p_p->ps_pledge & PLEDGE_SETTIME))
1085 		return (0);
1086 	if (delta)
1087 		return (EPERM);
1088 	return (0);
1089 }
1090 
1091 int
1092 pledge_sendit(struct proc *p, const void *to)
1093 {
1094 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1095 		return (0);
1096 
1097 	if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE)))
1098 		return (0);		/* may use address */
1099 	if (to == NULL)
1100 		return (0);		/* behaves just like write */
1101 	return pledge_fail(p, EPERM, PLEDGE_INET);
1102 }
1103 
1104 int
1105 pledge_ioctl(struct proc *p, long com, struct file *fp)
1106 {
1107 	struct vnode *vp = NULL;
1108 	int error = EPERM;
1109 
1110 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1111 		return (0);
1112 
1113 	/*
1114 	 * The ioctl's which are always allowed.
1115 	 */
1116 	switch (com) {
1117 	case FIONREAD:
1118 	case FIONBIO:
1119 	case FIOCLEX:
1120 	case FIONCLEX:
1121 		return (0);
1122 	}
1123 
1124 	/* fp != NULL was already checked */
1125 	if (fp->f_type == DTYPE_VNODE) {
1126 		vp = fp->f_data;
1127 		if (vp->v_type == VBAD)
1128 			return (ENOTTY);
1129 	}
1130 
1131 	/*
1132 	 * Further sets of ioctl become available, but are checked a
1133 	 * bit more carefully against the vnode.
1134 	 */
1135 	if ((p->p_p->ps_pledge & PLEDGE_IOCTL)) {
1136 		switch (com) {
1137 		case TIOCGETA:
1138 		case TIOCGPGRP:
1139 		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
1140 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1141 				return (0);
1142 			return (ENOTTY);
1143 		case BIOCGSTATS:	/* bpf: tcpdump privsep on ^C */
1144 			if (fp->f_type == DTYPE_VNODE &&
1145 			    fp->f_ops->fo_ioctl == vn_ioctl)
1146 				return (0);
1147 			break;
1148 		case MTIOCGET:
1149 		case MTIOCTOP:
1150 			/* for pax(1) and such, checking tapes... */
1151 			if (fp->f_type == DTYPE_VNODE &&
1152 			    (vp->v_type == VCHR || vp->v_type == VBLK))
1153 				return (0);
1154 			break;
1155 		case SIOCGIFGROUP:
1156 			if ((p->p_p->ps_pledge & PLEDGE_INET) &&
1157 			    fp->f_type == DTYPE_SOCKET)
1158 				return (0);
1159 			break;
1160 		}
1161 	}
1162 
1163 	if ((p->p_p->ps_pledge & PLEDGE_DRM)) {
1164 #if NDRM > 0
1165 		if ((fp->f_type == DTYPE_VNODE) &&
1166 		    (vp->v_type == VCHR) &&
1167 		    (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
1168 			error = pledge_ioctl_drm(p, com, vp->v_rdev);
1169 			if (error == 0)
1170 				return 0;
1171 		}
1172 #endif /* NDRM > 0 */
1173 	}
1174 
1175 	if ((p->p_p->ps_pledge & PLEDGE_AUDIO)) {
1176 #if NAUDIO > 0
1177 		switch (com) {
1178 		case AUDIO_GETPOS:
1179 		case AUDIO_GETPAR:
1180 		case AUDIO_SETPAR:
1181 		case AUDIO_START:
1182 		case AUDIO_STOP:
1183 		case AUDIO_SETINFO:
1184 		case AUDIO_GETINFO:
1185 		case AUDIO_GETENC:
1186 		case AUDIO_SETFD:
1187 		case AUDIO_GETPROPS:
1188 			if (fp->f_type == DTYPE_VNODE &&
1189 			    vp->v_type == VCHR &&
1190 			    cdevsw[major(vp->v_rdev)].d_open == audioopen)
1191 				return (0);
1192 		}
1193 #endif /* NAUDIO > 0 */
1194 	}
1195 
1196 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
1197 		switch (com) {
1198 		case DIOCGDINFO:
1199 		case DIOCGPDINFO:
1200 		case DIOCRLDINFO:
1201 		case DIOCWDINFO:
1202 		case BIOCDISK:
1203 		case BIOCINQ:
1204 		case BIOCINSTALLBOOT:
1205 		case BIOCVOL:
1206 			if (fp->f_type == DTYPE_VNODE &&
1207 			    ((vp->v_type == VCHR &&
1208 			    cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
1209 			    (vp->v_type == VBLK &&
1210 			    bdevsw[major(vp->v_rdev)].d_type == D_DISK)))
1211 				return (0);
1212 			break;
1213 		case DIOCMAP:
1214 			if (fp->f_type == DTYPE_VNODE &&
1215 			    vp->v_type == VCHR &&
1216 			    cdevsw[major(vp->v_rdev)].d_ioctl == diskmapioctl)
1217 				return (0);
1218 			break;
1219 		}
1220 	}
1221 
1222 	if ((p->p_p->ps_pledge & PLEDGE_PF)) {
1223 #ifndef SMALL_KERNEL
1224 		switch (com) {
1225 		case DIOCADDRULE:
1226 		case DIOCGETSTATUS:
1227 		case DIOCNATLOOK:
1228 		case DIOCRADDTABLES:
1229 		case DIOCRCLRADDRS:
1230 		case DIOCRCLRTABLES:
1231 		case DIOCRCLRTSTATS:
1232 		case DIOCRGETTSTATS:
1233 		case DIOCRSETADDRS:
1234 		case DIOCXBEGIN:
1235 		case DIOCXCOMMIT:
1236 		case DIOCKILLSRCNODES:
1237 			if ((fp->f_type == DTYPE_VNODE) &&
1238 			    (vp->v_type == VCHR) &&
1239 			    (cdevsw[major(vp->v_rdev)].d_open == pfopen))
1240 				return (0);
1241 			break;
1242 		}
1243 #endif /* !SMALL_KERNEL */
1244 	}
1245 
1246 	if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
1247 		switch (com) {
1248 #if NPTY > 0
1249 		case PTMGET:
1250 			if ((p->p_p->ps_pledge & PLEDGE_RPATH) == 0)
1251 				break;
1252 			if ((p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
1253 				break;
1254 			if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
1255 				break;
1256 			if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
1257 				break;
1258 			return (0);
1259 #endif /* NPTY > 0 */
1260 		case TIOCSTI:		/* ksh? csh? */
1261 			if ((p->p_p->ps_pledge & PLEDGE_PROC) &&
1262 			    fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1263 				return (0);
1264 			break;
1265 		case TIOCSPGRP:
1266 			if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
1267 				break;
1268 			/* FALLTHROUGH */
1269 		case TIOCFLUSH:		/* getty, telnet */
1270 		case TIOCGPGRP:
1271 		case TIOCGETA:
1272 		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
1273 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1274 				return (0);
1275 			return (ENOTTY);
1276 		case TIOCSWINSZ:
1277 		case TIOCEXT:		/* mail, libedit .. */
1278 		case TIOCCBRK:		/* cu */
1279 		case TIOCSBRK:		/* cu */
1280 		case TIOCCDTR:		/* cu */
1281 		case TIOCSDTR:		/* cu */
1282 		case TIOCEXCL:		/* cu */
1283 		case TIOCSETA:		/* cu, ... */
1284 		case TIOCSETAW:		/* cu, ... */
1285 		case TIOCSETAF:		/* tcsetattr TCSAFLUSH, script */
1286 		case TIOCSCTTY:		/* forkpty(3), login_tty(3), ... */
1287 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1288 				return (0);
1289 			break;
1290 		}
1291 	}
1292 
1293 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
1294 		switch (com) {
1295 		case SIOCGIFADDR:
1296 		case SIOCGIFFLAGS:
1297 		case SIOCGIFMETRIC:
1298 		case SIOCGIFGMEMB:
1299 		case SIOCGIFRDOMAIN:
1300 		case SIOCGIFDSTADDR_IN6:
1301 		case SIOCGIFNETMASK_IN6:
1302 		case SIOCGNBRINFO_IN6:
1303 		case SIOCGIFINFO_IN6:
1304 		case SIOCGIFMEDIA:
1305 			if (fp->f_type == DTYPE_SOCKET)
1306 				return (0);
1307 			break;
1308 		}
1309 	}
1310 
1311 	if ((p->p_p->ps_pledge & PLEDGE_VMM)) {
1312 #if NVMM > 0
1313 		if ((fp->f_type == DTYPE_VNODE) &&
1314 		    (vp->v_type == VCHR) &&
1315 		    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
1316 			error = pledge_ioctl_vmm(p, com);
1317 			if (error == 0)
1318 				return 0;
1319 		}
1320 #endif
1321 	}
1322 
1323 	return pledge_fail(p, error, PLEDGE_IOCTL);
1324 }
1325 
1326 int
1327 pledge_sockopt(struct proc *p, int set, int level, int optname)
1328 {
1329 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1330 		return (0);
1331 
1332 	/* Always allow these, which are too common to reject */
1333 	switch (level) {
1334 	case SOL_SOCKET:
1335 		switch (optname) {
1336 		case SO_RCVBUF:
1337 		case SO_ERROR:
1338 			return 0;
1339 		}
1340 		break;
1341 	}
1342 
1343 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS|PLEDGE_YPACTIVE)) == 0)
1344 		return pledge_fail(p, EPERM, PLEDGE_INET);
1345 	/* In use by some service libraries */
1346 	switch (level) {
1347 	case SOL_SOCKET:
1348 		switch (optname) {
1349 		case SO_TIMESTAMP:
1350 			return 0;
1351 		}
1352 		break;
1353 	}
1354 
1355 	/* DNS resolver may do these requests */
1356 	if ((p->p_p->ps_pledge & PLEDGE_DNS)) {
1357 		switch (level) {
1358 		case IPPROTO_IPV6:
1359 			switch (optname) {
1360 			case IPV6_RECVPKTINFO:
1361 			case IPV6_USE_MIN_MTU:
1362 				return (0);
1363 			}
1364 		}
1365 	}
1366 
1367 	/* YP may do these requests */
1368 	if (p->p_p->ps_pledge & PLEDGE_YPACTIVE) {
1369 		switch (level) {
1370 		case IPPROTO_IP:
1371 			switch (optname) {
1372 			case IP_PORTRANGE:
1373 				return (0);
1374 			}
1375 			break;
1376 
1377 		case IPPROTO_IPV6:
1378 			switch (optname) {
1379 			case IPV6_PORTRANGE:
1380 				return (0);
1381 			}
1382 			break;
1383 		}
1384 	}
1385 
1386 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
1387 		return pledge_fail(p, EPERM, PLEDGE_INET);
1388 	switch (level) {
1389 	case SOL_SOCKET:
1390 		switch (optname) {
1391 		case SO_RTABLE:
1392 			return pledge_fail(p, EINVAL, PLEDGE_INET);
1393 		}
1394 		return (0);
1395 	}
1396 
1397 	if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
1398 		return pledge_fail(p, EPERM, PLEDGE_INET);
1399 	switch (level) {
1400 	case IPPROTO_TCP:
1401 		switch (optname) {
1402 		case TCP_NODELAY:
1403 		case TCP_MD5SIG:
1404 		case TCP_SACK_ENABLE:
1405 		case TCP_MAXSEG:
1406 		case TCP_NOPUSH:
1407 			return (0);
1408 		}
1409 		break;
1410 	case IPPROTO_IP:
1411 		switch (optname) {
1412 		case IP_OPTIONS:
1413 			if (!set)
1414 				return (0);
1415 			break;
1416 		case IP_TOS:
1417 		case IP_TTL:
1418 		case IP_MINTTL:
1419 		case IP_IPDEFTTL:
1420 		case IP_PORTRANGE:
1421 		case IP_RECVDSTADDR:
1422 		case IP_RECVDSTPORT:
1423 			return (0);
1424 		case IP_MULTICAST_IF:
1425 		case IP_ADD_MEMBERSHIP:
1426 		case IP_DROP_MEMBERSHIP:
1427 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1428 				return (0);
1429 			break;
1430 		}
1431 		break;
1432 	case IPPROTO_ICMP:
1433 		break;
1434 	case IPPROTO_IPV6:
1435 		switch (optname) {
1436 		case IPV6_TCLASS:
1437 		case IPV6_UNICAST_HOPS:
1438 		case IPV6_MINHOPCOUNT:
1439 		case IPV6_RECVHOPLIMIT:
1440 		case IPV6_PORTRANGE:
1441 		case IPV6_RECVPKTINFO:
1442 		case IPV6_RECVDSTPORT:
1443 #ifdef notyet
1444 		case IPV6_V6ONLY:
1445 #endif
1446 			return (0);
1447 		case IPV6_MULTICAST_IF:
1448 		case IPV6_JOIN_GROUP:
1449 		case IPV6_LEAVE_GROUP:
1450 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1451 				return (0);
1452 			break;
1453 		}
1454 		break;
1455 	case IPPROTO_ICMPV6:
1456 		break;
1457 	}
1458 	return pledge_fail(p, EPERM, PLEDGE_INET);
1459 }
1460 
1461 int
1462 pledge_socket(struct proc *p, int domain, int state)
1463 {
1464 	if (! ISSET(p->p_p->ps_flags, PS_PLEDGE))
1465 		return 0;
1466 
1467 	if (ISSET(state, SS_DNS)) {
1468 		if (ISSET(p->p_p->ps_pledge, PLEDGE_DNS))
1469 			return 0;
1470 		return pledge_fail(p, EPERM, PLEDGE_DNS);
1471 	}
1472 
1473 	switch (domain) {
1474 	case -1:		/* accept on any domain */
1475 		return (0);
1476 	case AF_INET:
1477 	case AF_INET6:
1478 		if (ISSET(p->p_p->ps_pledge, PLEDGE_INET) ||
1479 		    ISSET(p->p_p->ps_pledge, PLEDGE_YPACTIVE))
1480 			return 0;
1481 		return pledge_fail(p, EPERM, PLEDGE_INET);
1482 
1483 	case AF_UNIX:
1484 		if (ISSET(p->p_p->ps_pledge, PLEDGE_UNIX))
1485 			return 0;
1486 		return pledge_fail(p, EPERM, PLEDGE_UNIX);
1487 	}
1488 
1489 	return pledge_fail(p, EINVAL, PLEDGE_INET);
1490 }
1491 
1492 int
1493 pledge_flock(struct proc *p)
1494 {
1495 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1496 		return (0);
1497 
1498 	if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
1499 		return (0);
1500 	return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
1501 }
1502 
1503 int
1504 pledge_swapctl(struct proc *p)
1505 {
1506 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1507 		return (0);
1508 	return (EPERM);
1509 }
1510 
1511 /* bsearch over pledgereq. return flags value if found, 0 else */
1512 int
1513 pledgereq_flags(const char *req_name)
1514 {
1515 	int base = 0, cmp, i, lim;
1516 
1517 	for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
1518 		i = base + (lim >> 1);
1519 		cmp = strcmp(req_name, pledgereq[i].name);
1520 		if (cmp == 0)
1521 			return (pledgereq[i].flags);
1522 		if (cmp > 0) { /* not found before, move right */
1523 			base = i + 1;
1524 			lim--;
1525 		} /* else move left */
1526 	}
1527 	return (0);
1528 }
1529 
1530 int
1531 pledge_fcntl(struct proc *p, int cmd)
1532 {
1533 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1534 		return (0);
1535 	if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0 && cmd == F_SETOWN)
1536 		return pledge_fail(p, EPERM, PLEDGE_PROC);
1537 	return (0);
1538 }
1539 
1540 int
1541 pledge_kill(struct proc *p, pid_t pid)
1542 {
1543 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1544 		return 0;
1545 	if (p->p_p->ps_pledge & PLEDGE_PROC)
1546 		return 0;
1547 	if (pid == 0 || pid == p->p_p->ps_pid)
1548 		return 0;
1549 	return pledge_fail(p, EPERM, PLEDGE_PROC);
1550 }
1551 
1552 int
1553 pledge_protexec(struct proc *p, int prot)
1554 {
1555 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1556 		return 0;
1557 	if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
1558 		return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
1559 	return 0;
1560 }
1561 
1562 void
1563 pledge_dropwpaths(struct process *pr)
1564 {
1565 	if (pr->ps_pledgepaths && --pr->ps_pledgepaths->wl_ref == 0) {
1566 		struct whitepaths *wl = pr->ps_pledgepaths;
1567 		int i;
1568 
1569 		for (i = 0; i < wl->wl_count; i++)
1570 			free(wl->wl_paths[i].name, M_TEMP, wl->wl_paths[i].len);
1571 		free(wl, M_TEMP, wl->wl_size);
1572 	}
1573 	pr->ps_pledgepaths = NULL;
1574 }
1575 
1576 int
1577 canonpath(const char *input, char *buf, size_t bufsize)
1578 {
1579 	const char *p;
1580 	char *q;
1581 
1582 	/* can't canon relative paths, don't bother */
1583 	if (input[0] != '/') {
1584 		if (strlcpy(buf, input, bufsize) >= bufsize)
1585 			return ENAMETOOLONG;
1586 		return 0;
1587 	}
1588 
1589 	p = input;
1590 	q = buf;
1591 	while (*p && (q - buf < bufsize)) {
1592 		if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
1593 			p += 1;
1594 
1595 		} else if (p[0] == '/' && p[1] == '.' &&
1596 		    (p[2] == '/' || p[2] == '\0')) {
1597 			p += 2;
1598 
1599 		} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
1600 		    (p[3] == '/' || p[3] == '\0')) {
1601 			p += 3;
1602 			if (q != buf)	/* "/../" at start of buf */
1603 				while (*--q != '/')
1604 					continue;
1605 
1606 		} else {
1607 			*q++ = *p++;
1608 		}
1609 	}
1610         if ((*p == '\0') && (q - buf < bufsize)) {
1611                 *q = 0;
1612                 return 0;
1613         } else
1614                 return ENAMETOOLONG;
1615 }
1616 
1617 int
1618 substrcmp(const char *p1, size_t s1, const char *p2, size_t s2)
1619 {
1620 	size_t i;
1621 	for (i = 0; i < s1 || i < s2; i++) {
1622 		if (p1[i] != p2[i])
1623 			break;
1624 	}
1625 	if (i == s1) {
1626 		return (1);	/* string1 is a subpath of string2 */
1627 	} else if (i == s2)
1628 		return (2);	/* string2 is a subpath of string1 */
1629 	else
1630 		return (0);	/* no subpath */
1631 }
1632 
1633 int
1634 resolvpath(struct proc *p,
1635     char **rdir, size_t *rdirlen,
1636     char **cwd, size_t *cwdlen,
1637     char *path, size_t pathlen,
1638     char **resolved, size_t *resolvedlen)
1639 {
1640 	int error;
1641 	char *abspath = NULL, *canopath = NULL, *fullpath = NULL;
1642 	size_t abspathlen, canopathlen = 0, fullpathlen = 0, canopathlen_exact;
1643 
1644 	/* 1. get an absolute path (inside any chroot) : path -> abspath */
1645 	if (path[0] != '/') {
1646 		/* path is relative: prepend cwd */
1647 
1648 		/* get cwd first (if needed) */
1649 		if (*cwd == NULL) {
1650 			char *rawcwd, *bp, *bpend;
1651 			size_t rawcwdlen = MAXPATHLEN * 4;
1652 
1653 			rawcwd = malloc(rawcwdlen, M_TEMP, M_WAITOK);
1654 			bp = &rawcwd[rawcwdlen];
1655 			bpend = bp;
1656 			*(--bp) = '\0';
1657 
1658 			error = vfs_getcwd_common(p->p_fd->fd_cdir,
1659 			    NULL, &bp, rawcwd, rawcwdlen/2,
1660 			    GETCWD_CHECK_ACCESS, p);
1661 			if (error) {
1662 				free(rawcwd, M_TEMP, rawcwdlen);
1663 				goto out;
1664 			}
1665 
1666 			/* NUL is included */
1667 			*cwdlen = (bpend - bp);
1668 			*cwd = malloc(*cwdlen, M_TEMP, M_WAITOK);
1669 			memcpy(*cwd, bp, *cwdlen);
1670 
1671 			free(rawcwd, M_TEMP, rawcwdlen);
1672 		}
1673 
1674 		/* NUL included in *cwdlen and pathlen */
1675 		abspathlen = *cwdlen + pathlen;
1676 		abspath = malloc(abspathlen, M_TEMP, M_WAITOK);
1677 		snprintf(abspath, abspathlen, "%s/%s", *cwd, path);
1678 
1679 	} else {
1680 		/* path is absolute */
1681 		abspathlen = pathlen;
1682 		abspath = malloc(abspathlen, M_TEMP, M_WAITOK);
1683 		memcpy(abspath, path, pathlen);
1684 	}
1685 
1686 	/* 2. canonization: abspath -> canopath */
1687 	canopathlen = abspathlen;
1688 	canopath = malloc(canopathlen, M_TEMP, M_WAITOK);
1689 	error = canonpath(abspath, canopath, canopathlen);
1690 
1691 	/* free abspath now as we don't need it after */
1692 	free(abspath, M_TEMP, abspathlen);
1693 
1694 	/* error in canonpath() call (should not happen, but keep safe) */
1695 	if (error != 0)
1696 		goto out;
1697 
1698 	/* check the canopath size */
1699 	canopathlen_exact = strlen(canopath) + 1;
1700 	if (canopathlen_exact > MAXPATHLEN) {
1701 		error = ENAMETOOLONG;
1702 		goto out;
1703 	}
1704 
1705 	/* 3. preprend *rdir if chrooted : canonpath -> fullpath */
1706 	if (p->p_fd->fd_rdir != NULL) {
1707 		if (*rdir == NULL) {
1708 			char *rawrdir, *bp, *bpend;
1709 			size_t rawrdirlen = MAXPATHLEN * 4;
1710 
1711 			rawrdir = malloc(rawrdirlen, M_TEMP, M_WAITOK);
1712 			bp = &rawrdir[rawrdirlen];
1713 			bpend = bp;
1714 			*(--bp) = '\0';
1715 
1716 			error = vfs_getcwd_common(p->p_fd->fd_rdir,
1717 			    rootvnode, &bp, rawrdir, rawrdirlen/2,
1718 			    GETCWD_CHECK_ACCESS, p);
1719 			if (error) {
1720 				free(rawrdir, M_TEMP, rawrdirlen);
1721 				goto out;
1722 			}
1723 
1724 			/* NUL is included */
1725 			*rdirlen = (bpend - bp);
1726 			*rdir = malloc(*rdirlen, M_TEMP, M_WAITOK);
1727 			memcpy(*rdir, bp, *rdirlen);
1728 
1729 			free(rawrdir, M_TEMP, rawrdirlen);
1730 		}
1731 
1732 		/*
1733 		 * NUL is included in *rdirlen and canopathlen_exact.
1734 		 * doesn't add "/" between them, as canopath is absolute.
1735 		 */
1736 		fullpathlen = *rdirlen + canopathlen_exact - 1;
1737 		fullpath = malloc(fullpathlen, M_TEMP, M_WAITOK);
1738 		snprintf(fullpath, fullpathlen, "%s%s", *rdir, canopath);
1739 
1740 	} else {
1741 		/* not chrooted: only reduce canopath to exact length */
1742 		fullpathlen = canopathlen_exact;
1743 		fullpath = malloc(fullpathlen, M_TEMP, M_WAITOK);
1744 		memcpy(fullpath, canopath, fullpathlen);
1745 	}
1746 
1747 	*resolvedlen = fullpathlen;
1748 	*resolved = fullpath;
1749 
1750 out:
1751 	free(canopath, M_TEMP, canopathlen);
1752 	if (error != 0)
1753 		free(fullpath, M_TEMP, fullpathlen);
1754 	return error;
1755 }
1756