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