xref: /openbsd-src/sys/kern/kern_pledge.c (revision d59bb9942320b767f2a19aaa7690c8c6e30b724c)
1 /*	$OpenBSD: kern_pledge.c,v 1.192 2017/01/23 05:49:24 deraadt 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__) || defined(__i386__)
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 	 * Other ioctl are selectively allowed based upon other pledges.
239 	 */
240 	[SYS_ioctl] = PLEDGE_STDIO,
241 
242 	/*
243 	 * Path access/creation calls encounter many extensive
244 	 * checks are done during namei()
245 	 */
246 	[SYS_open] = PLEDGE_STDIO,
247 	[SYS_stat] = PLEDGE_STDIO,
248 	[SYS_access] = PLEDGE_STDIO,
249 	[SYS_readlink] = PLEDGE_STDIO,
250 
251 	[SYS_adjtime] = PLEDGE_STDIO,   /* setting requires "settime" */
252 	[SYS_adjfreq] = PLEDGE_SETTIME,
253 	[SYS_settimeofday] = PLEDGE_SETTIME,
254 
255 	/*
256 	 * Needed by threaded programs
257 	 * XXX should we have a new "threads"?
258 	 */
259 	[SYS___tfork] = PLEDGE_STDIO,
260 	[SYS_sched_yield] = PLEDGE_STDIO,
261 	[SYS___thrsleep] = PLEDGE_STDIO,
262 	[SYS___thrwakeup] = PLEDGE_STDIO,
263 	[SYS___threxit] = PLEDGE_STDIO,
264 	[SYS___thrsigdivert] = PLEDGE_STDIO,
265 
266 	[SYS_fork] = PLEDGE_PROC,
267 	[SYS_vfork] = PLEDGE_PROC,
268 	[SYS_setpgid] = PLEDGE_PROC,
269 	[SYS_setsid] = PLEDGE_PROC,
270 
271 	[SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
272 	[SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
273 
274 	[SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
275 
276 	[SYS_setuid] = PLEDGE_ID,
277 	[SYS_seteuid] = PLEDGE_ID,
278 	[SYS_setreuid] = PLEDGE_ID,
279 	[SYS_setresuid] = PLEDGE_ID,
280 	[SYS_setgid] = PLEDGE_ID,
281 	[SYS_setegid] = PLEDGE_ID,
282 	[SYS_setregid] = PLEDGE_ID,
283 	[SYS_setresgid] = PLEDGE_ID,
284 	[SYS_setgroups] = PLEDGE_ID,
285 	[SYS_setlogin] = PLEDGE_ID,
286 
287 	[SYS_execve] = PLEDGE_EXEC,
288 
289 	[SYS_chdir] = PLEDGE_RPATH,
290 	[SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
291 	[SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
292 	[SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
293 	[SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
294 	[SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
295 	[SYS_truncate] = PLEDGE_WPATH,
296 	[SYS_rename] = PLEDGE_RPATH | PLEDGE_CPATH,
297 	[SYS_rmdir] = PLEDGE_CPATH,
298 	[SYS_renameat] = PLEDGE_CPATH,
299 	[SYS_link] = PLEDGE_CPATH,
300 	[SYS_linkat] = PLEDGE_CPATH,
301 	[SYS_symlink] = PLEDGE_CPATH,
302 	[SYS_symlinkat] = 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 	{ "bpf",		PLEDGE_BPF },
363 	{ "chown",		PLEDGE_CHOWN | PLEDGE_CHOWNUID },
364 	{ "cpath",		PLEDGE_CPATH },
365 	{ "disklabel",		PLEDGE_DISKLABEL },
366 	{ "dns",		PLEDGE_DNS },
367 	{ "dpath",		PLEDGE_DPATH },
368 	{ "drm",		PLEDGE_DRM },
369 	{ "exec",		PLEDGE_EXEC },
370 	{ "fattr",		PLEDGE_FATTR | PLEDGE_CHOWN },
371 	{ "flock",		PLEDGE_FLOCK },
372 	{ "getpw",		PLEDGE_GETPW },
373 	{ "id",			PLEDGE_ID },
374 	{ "inet",		PLEDGE_INET },
375 	{ "ioctl",		PLEDGE_TAPE },		/* Remove Feb 1 2017 */
376 	{ "mcast",		PLEDGE_MCAST },
377 	{ "pf",			PLEDGE_PF },
378 	{ "proc",		PLEDGE_PROC },
379 	{ "prot_exec",		PLEDGE_PROTEXEC },
380 	{ "ps",			PLEDGE_PS },
381 	{ "recvfd",		PLEDGE_RECVFD },
382 	{ "route",		PLEDGE_ROUTE },
383 	{ "rpath",		PLEDGE_RPATH },
384 	{ "sendfd",		PLEDGE_SENDFD },
385 	{ "settime",		PLEDGE_SETTIME },
386 	{ "stdio",		PLEDGE_STDIO },
387 	{ "tape",		PLEDGE_TAPE },
388 	{ "tmppath",		PLEDGE_TMPPATH },
389 	{ "tty",		PLEDGE_TTY },
390 	{ "unix",		PLEDGE_UNIX },
391 	{ "vminfo",		PLEDGE_VMINFO },
392 	{ "vmm",		PLEDGE_VMM },
393 	{ "wpath",		PLEDGE_WPATH },
394 };
395 
396 int
397 sys_pledge(struct proc *p, void *v, register_t *retval)
398 {
399 	struct sys_pledge_args /* {
400 		syscallarg(const char *)request;
401 		syscallarg(const char **)paths;
402 	} */	*uap = v;
403 	struct process *pr = p->p_p;
404 	uint64_t flags = 0;
405 	int error;
406 
407 	if (SCARG(uap, request)) {
408 		size_t rbuflen;
409 		char *rbuf, *rp, *pn;
410 		uint64_t f;
411 
412 		rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
413 		error = copyinstr(SCARG(uap, request), rbuf, MAXPATHLEN,
414 		    &rbuflen);
415 		if (error) {
416 			free(rbuf, M_TEMP, MAXPATHLEN);
417 			return (error);
418 		}
419 #ifdef KTRACE
420 		if (KTRPOINT(p, KTR_STRUCT))
421 			ktrstruct(p, "pledgereq", rbuf, rbuflen-1);
422 #endif
423 
424 		for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
425 			pn = strchr(rp, ' ');	/* find terminator */
426 			if (pn) {
427 				while (*pn == ' ')
428 					*pn++ = '\0';
429 			}
430 
431 			if ((f = pledgereq_flags(rp)) == 0) {
432 				free(rbuf, M_TEMP, MAXPATHLEN);
433 				return (EINVAL);
434 			}
435 			flags |= f;
436 		}
437 		free(rbuf, M_TEMP, MAXPATHLEN);
438 
439 		/*
440 		 * if we are already pledged, allow only promises reductions.
441 		 * flags doesn't contain flags outside _USERSET: they will be
442 		 * relearned.
443 		 */
444 		if (ISSET(pr->ps_flags, PS_PLEDGE) &&
445 		    (((flags | pr->ps_pledge) != pr->ps_pledge)))
446 			return (EPERM);
447 	}
448 
449 	if (SCARG(uap, paths)) {
450 #if 1
451 		return (EINVAL);
452 #else
453 		const char **u = SCARG(uap, paths), *sp;
454 		struct whitepaths *wl;
455 		char *path, *rdir = NULL, *cwd = NULL;
456 		size_t pathlen, rdirlen, cwdlen;
457 
458 		size_t maxargs = 0;
459 		int i, error;
460 
461 		if (pr->ps_pledgepaths)
462 			return (EPERM);
463 
464 		/* Count paths */
465 		for (i = 0; i < PLEDGE_MAXPATHS; i++) {
466 			if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
467 				return (error);
468 			if (sp == NULL)
469 				break;
470 		}
471 		if (i == PLEDGE_MAXPATHS)
472 			return (E2BIG);
473 
474 		wl = malloc(sizeof *wl + sizeof(struct whitepath) * (i+1),
475 		    M_TEMP, M_WAITOK | M_ZERO);
476 		wl->wl_size = sizeof *wl + sizeof(struct whitepath) * (i+1);
477 		wl->wl_count = i;
478 		wl->wl_ref = 1;
479 
480 		path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
481 
482 		/* Copy in */
483 		for (i = 0; i < wl->wl_count; i++) {
484 			char *resolved = NULL;
485 			size_t resolvedlen;
486 
487 			if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
488 				break;
489 			if (sp == NULL)
490 				break;
491 			if ((error = copyinstr(sp, path, MAXPATHLEN, &pathlen)) != 0)
492 				break;
493 #ifdef KTRACE
494 			if (KTRPOINT(p, KTR_STRUCT))
495 				ktrstruct(p, "pledgepath", path, pathlen-1);
496 #endif
497 
498 			error = resolvpath(p, &rdir, &rdirlen, &cwd, &cwdlen,
499 			    path, pathlen, &resolved, &resolvedlen);
500 
501 			if (error != 0)
502 				/* resolved is allocated only if !error */
503 				break;
504 
505 			maxargs += resolvedlen;
506 			if (maxargs > ARG_MAX) {
507 				error = E2BIG;
508 				free(resolved, M_TEMP, resolvedlen);
509 				break;
510 			}
511 			wl->wl_paths[i].name = resolved;
512 			wl->wl_paths[i].len = resolvedlen;
513 		}
514 		free(rdir, M_TEMP, rdirlen);
515 		free(cwd, M_TEMP, cwdlen);
516 		free(path, M_TEMP, MAXPATHLEN);
517 
518 		if (error) {
519 			for (i = 0; i < wl->wl_count; i++)
520 				free(wl->wl_paths[i].name,
521 				    M_TEMP, wl->wl_paths[i].len);
522 			free(wl, M_TEMP, wl->wl_size);
523 			return (error);
524 		}
525 		pr->ps_pledgepaths = wl;
526 
527 #ifdef DEBUG_PLEDGE
528 		/* print paths registered as whilelisted (viewed as without chroot) */
529 		DNPRINTF(1, "pledge: %s(%d): paths loaded:\n", pr->ps_comm,
530 		    pr->ps_pid);
531 		for (i = 0; i < wl->wl_count; i++)
532 			if (wl->wl_paths[i].name)
533 				DNPRINTF(1, "pledge: %d=\"%s\" [%lld]\n", i,
534 				    wl->wl_paths[i].name,
535 				    (long long)wl->wl_paths[i].len);
536 #endif
537 #endif
538 	}
539 
540 	if (SCARG(uap, request)) {
541 		pr->ps_pledge = flags;
542 		pr->ps_flags |= PS_PLEDGE;
543 	}
544 
545 	return (0);
546 }
547 
548 int
549 pledge_syscall(struct proc *p, int code, int *tval)
550 {
551 	p->p_pledge_syscall = code;
552 	*tval = 0;
553 
554 	if (code < 0 || code > SYS_MAXSYSCALL - 1)
555 		return (EINVAL);
556 
557 	if (pledge_syscalls[code] == PLEDGE_ALWAYS)
558 		return (0);
559 
560 	if (p->p_p->ps_pledge & pledge_syscalls[code])
561 		return (0);
562 
563 	*tval = pledge_syscalls[code];
564 	return (EPERM);
565 }
566 
567 int
568 pledge_fail(struct proc *p, int error, uint64_t code)
569 {
570 	char *codes = "";
571 	int i;
572 	struct sigaction sa;
573 
574 	/* Print first matching pledge */
575 	for (i = 0; code && pledgenames[i].bits != 0; i++)
576 		if (pledgenames[i].bits & code) {
577 			codes = pledgenames[i].name;
578 			break;
579 		}
580 	printf("%s(%d): syscall %d \"%s\"\n", p->p_p->ps_comm, p->p_p->ps_pid,
581 	    p->p_pledge_syscall, codes);
582 #ifdef KTRACE
583 	if (KTRPOINT(p, KTR_PLEDGE))
584 		ktrpledge(p, error, code, p->p_pledge_syscall);
585 #endif
586 	/* Send uncatchable SIGABRT for coredump */
587 	memset(&sa, 0, sizeof sa);
588 	sa.sa_handler = SIG_DFL;
589 	setsigvec(p, SIGABRT, &sa);
590 	psignal(p, SIGABRT);
591 
592 	p->p_p->ps_pledge = 0;		/* Disable all PLEDGE_ flags */
593 	return (error);
594 }
595 
596 /*
597  * Need to make it more obvious that one cannot get through here
598  * without the right flags set
599  */
600 int
601 pledge_namei(struct proc *p, struct nameidata *ni, char *origpath)
602 {
603 	char path[PATH_MAX];
604 	int error;
605 
606 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0 ||
607 	    (p->p_p->ps_flags & PS_COREDUMP))
608 		return (0);
609 
610 	if (!ni || (ni->ni_pledge == 0))
611 		panic("ni_pledge");
612 
613 	/* Doing a permitted execve() */
614 	if ((ni->ni_pledge & PLEDGE_EXEC) &&
615 	    (p->p_p->ps_pledge & PLEDGE_EXEC))
616 		return (0);
617 
618 	error = canonpath(origpath, path, sizeof(path));
619 	if (error)
620 		return (error);
621 
622 	/* Detect what looks like a mkstemp(3) family operation */
623 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
624 	    (p->p_pledge_syscall == SYS_open) &&
625 	    (ni->ni_pledge & PLEDGE_CPATH) &&
626 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
627 		return (0);
628 	}
629 
630 	/* Allow unlinking of a mkstemp(3) file...
631 	 * Good opportunity for strict checks here.
632 	 */
633 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
634 	    (p->p_pledge_syscall == SYS_unlink) &&
635 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
636 		return (0);
637 	}
638 
639 	/* Whitelisted paths */
640 	switch (p->p_pledge_syscall) {
641 	case SYS_access:
642 		/* tzset() needs this. */
643 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
644 		    strcmp(path, "/etc/localtime") == 0)
645 			return (0);
646 
647 		/* when avoiding YP mode, getpw* functions touch this */
648 		if (ni->ni_pledge == PLEDGE_RPATH &&
649 		    strcmp(path, "/var/run/ypbind.lock") == 0) {
650 			if (p->p_p->ps_pledge & PLEDGE_GETPW)
651 				return (0);
652 			else
653 				return (pledge_fail(p, error, PLEDGE_GETPW));
654 		}
655 		break;
656 	case SYS_open:
657 		/* daemon(3) or other such functions */
658 		if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
659 		    strcmp(path, "/dev/null") == 0) {
660 			return (0);
661 		}
662 
663 		/* readpassphrase(3), getpass(3) */
664 		if ((p->p_p->ps_pledge & PLEDGE_TTY) &&
665 		    (ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
666 		    strcmp(path, "/dev/tty") == 0) {
667 			return (0);
668 		}
669 
670 		/* getpw* and friends need a few files */
671 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
672 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
673 			if (strcmp(path, "/etc/spwd.db") == 0)
674 				return (EPERM); /* don't call pledge_fail */
675 			if (strcmp(path, "/etc/pwd.db") == 0)
676 				return (0);
677 			if (strcmp(path, "/etc/group") == 0)
678 				return (0);
679 			if (strcmp(path, "/etc/netid") == 0)
680 				return (0);
681 		}
682 
683 		/* DNS needs /etc/{resolv.conf,hosts,services}. */
684 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
685 		    (p->p_p->ps_pledge & PLEDGE_DNS)) {
686 			if (strcmp(path, "/etc/resolv.conf") == 0)
687 				return (0);
688 			if (strcmp(path, "/etc/hosts") == 0)
689 				return (0);
690 			if (strcmp(path, "/etc/services") == 0)
691 				return (0);
692 		}
693 
694 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
695 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
696 			if (strcmp(path, "/var/run/ypbind.lock") == 0) {
697 				/*
698 				 * XXX
699 				 * The current hack for YP support in "getpw"
700 				 * is to enable some "inet" features until
701 				 * next pledge call.  This is not considered
702 				 * worse than pre-pledge, but is a work in
703 				 * progress, needing a clever design.
704 				 */
705 				p->p_p->ps_pledge |= PLEDGE_YPACTIVE;
706 				return (0);
707 			}
708 			if (strncmp(path, "/var/yp/binding/",
709 			    sizeof("/var/yp/binding/") - 1) == 0)
710 				return (0);
711 		}
712 
713 		/* tzset() needs these. */
714 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
715 		    strncmp(path, "/usr/share/zoneinfo/",
716 		    sizeof("/usr/share/zoneinfo/") - 1) == 0)
717 			return (0);
718 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
719 		    strcmp(path, "/etc/localtime") == 0)
720 			return (0);
721 
722 		break;
723 	case SYS_readlink:
724 		/* Allow /etc/malloc.conf for malloc(3). */
725 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
726 		    strcmp(path, "/etc/malloc.conf") == 0)
727 			return (0);
728 		break;
729 	case SYS_stat:
730 		/* DNS needs /etc/resolv.conf. */
731 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
732 		    (p->p_p->ps_pledge & PLEDGE_DNS) &&
733 		    strcmp(path, "/etc/resolv.conf") == 0)
734 			return (0);
735 		break;
736 	}
737 
738 	/*
739 	 * Ensure each flag of p_pledgenote has counterpart allowing it in
740 	 * ps_pledge
741 	 */
742 	if (ni->ni_pledge & ~p->p_p->ps_pledge)
743 		return (pledge_fail(p, EPERM, (ni->ni_pledge & ~p->p_p->ps_pledge)));
744 
745 	return (0);
746 }
747 
748 /*
749  * wlpath lookup - only done after namei lookup has succeeded on the last compoent of
750  * a namei lookup, with a possibly non-canonicalized path given in "origpath" from namei.
751  */
752 int
753 pledge_namei_wlpath(struct proc *p, struct nameidata *ni)
754 {
755 	struct whitepaths *wl = p->p_p->ps_pledgepaths;
756 	char *rdir = NULL, *cwd = NULL, *resolved = NULL;
757 	size_t rdirlen = 0, cwdlen = 0, resolvedlen = 0;
758 	int i, error, pardir_found;
759 
760 	/*
761 	 * If a whitelist is set, compare canonical paths.  Anything
762 	 * not on the whitelist gets ENOENT.
763 	 */
764 	if (ni->ni_p_path == NULL)
765 		return(0);
766 
767 	KASSERT(wl != NULL);
768 
769 	// XXX change later or more help from namei?
770 	error = resolvpath(p, &rdir, &rdirlen, &cwd, &cwdlen,
771 	    ni->ni_p_path, ni->ni_p_length+1, &resolved, &resolvedlen);
772 
773 	free(rdir, M_TEMP, rdirlen);
774 	free(cwd, M_TEMP, cwdlen);
775 
776 	if (error != 0)
777 		/* resolved is allocated only if !error */
778 		return (error);
779 
780 	/* print resolved path (viewed as without chroot) */
781 	DNPRINTF(2, "pledge_namei: resolved=\"%s\" [%lld] strlen=%lld\n",
782 	    resolved, (long long)resolvedlen,
783 	    (long long)strlen(resolved));
784 
785 	error = ENOENT;
786 	pardir_found = 0;
787 	for (i = 0; i < wl->wl_count && wl->wl_paths[i].name && error; i++) {
788 		int substr = substrcmp(wl->wl_paths[i].name,
789 		    wl->wl_paths[i].len - 1, resolved, resolvedlen - 1);
790 
791 		/* print check between registered wl_path and resolved */
792 		DNPRINTF(3,
793 		    "pledge: check: \"%s\" (%ld) \"%s\" (%ld) = %d\n",
794 		    wl->wl_paths[i].name, wl->wl_paths[i].len - 1,
795 		    resolved, resolvedlen - 1,
796 		    substr);
797 
798 		/* wl_paths[i].name is a substring of resolved */
799 		if (substr == 1) {
800 			u_char term = resolved[wl->wl_paths[i].len - 1];
801 
802 			if (term == '\0' || term == '/' ||
803 			    wl->wl_paths[i].name[1] == '\0')
804 				error = 0;
805 
806 			/* resolved is a substring of wl_paths[i].name */
807 		} else if (substr == 2) {
808 			u_char term = wl->wl_paths[i].name[resolvedlen - 1];
809 
810 			if (resolved[1] == '\0' || term == '/')
811 				pardir_found = 1;
812 		}
813 	}
814 	if (pardir_found)
815 		switch (p->p_pledge_syscall) {
816 		case SYS_stat:
817 		case SYS_lstat:
818 		case SYS_fstatat:
819 		case SYS_fstat:
820 			ni->ni_pledge |= PLEDGE_STATLIE;
821 			error = 0;
822 		}
823 
824 #ifdef DEBUG_PLEDGE
825 	if (error == ENOENT)
826 		/* print the path that is reported as ENOENT */
827 		DNPRINTF(1, "pledge: %s(%d): wl_path ENOENT: \"%s\"\n",
828 		    p->p_p->ps_comm, p->p_p->ps_pid, resolved);
829 #endif
830 
831 	free(resolved, M_TEMP, resolvedlen);
832 	return (error);			/* Don't hint why it failed */
833 }
834 
835 /*
836  * Only allow reception of safe file descriptors.
837  */
838 int
839 pledge_recvfd(struct proc *p, struct file *fp)
840 {
841 	struct vnode *vp;
842 
843 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
844 		return (0);
845 	if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
846 		return pledge_fail(p, EPERM, PLEDGE_RECVFD);
847 
848 	switch (fp->f_type) {
849 	case DTYPE_SOCKET:
850 	case DTYPE_PIPE:
851 		return (0);
852 	case DTYPE_VNODE:
853 		vp = fp->f_data;
854 
855 		if (vp->v_type != VDIR)
856 			return (0);
857 		break;
858 	}
859 	return pledge_fail(p, EINVAL, PLEDGE_RECVFD);
860 }
861 
862 /*
863  * Only allow sending of safe file descriptors.
864  */
865 int
866 pledge_sendfd(struct proc *p, struct file *fp)
867 {
868 	struct vnode *vp;
869 
870 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
871 		return (0);
872 	if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
873 		return pledge_fail(p, EPERM, PLEDGE_SENDFD);
874 
875 	switch (fp->f_type) {
876 	case DTYPE_SOCKET:
877 	case DTYPE_PIPE:
878 		return (0);
879 	case DTYPE_VNODE:
880 		vp = fp->f_data;
881 
882 		if (vp->v_type != VDIR)
883 			return (0);
884 		break;
885 	}
886 	return pledge_fail(p, EINVAL, PLEDGE_SENDFD);
887 }
888 
889 int
890 pledge_sysctl(struct proc *p, int miblen, int *mib, void *new)
891 {
892 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
893 		return (0);
894 
895 	if (new)
896 		return pledge_fail(p, EFAULT, 0);
897 
898 	/* routing table observation */
899 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
900 		if ((miblen == 6 || miblen == 7) &&
901 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
902 		    mib[2] == 0 &&
903 		    mib[4] == NET_RT_DUMP)
904 			return (0);
905 
906 		if (miblen == 6 &&
907 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
908 		    mib[2] == 0 &&
909 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
910 		    mib[4] == NET_RT_TABLE)
911 			return (0);
912 
913 		if (miblen == 7 &&		/* exposes MACs */
914 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
915 		    mib[2] == 0 &&
916 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
917 		    mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
918 			return (0);
919 	}
920 
921 	if (p->p_p->ps_pledge & (PLEDGE_PS | PLEDGE_VMINFO)) {
922 		if (miblen == 2 &&		/* kern.fscale */
923 		    mib[0] == CTL_KERN && mib[1] == KERN_FSCALE)
924 			return (0);
925 		if (miblen == 2 &&		/* kern.boottime */
926 		    mib[0] == CTL_KERN && mib[1] == KERN_BOOTTIME)
927 			return (0);
928 		if (miblen == 2 &&		/* kern.consdev */
929 		    mib[0] == CTL_KERN && mib[1] == KERN_CONSDEV)
930 			return (0);
931 		if (miblen == 2 &&			/* kern.cptime */
932 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME)
933 			return (0);
934 		if (miblen == 3 &&			/* kern.cptime2 */
935 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME2)
936 			return (0);
937 	}
938 
939 	if ((p->p_p->ps_pledge & PLEDGE_PS)) {
940 		if (miblen == 4 &&		/* kern.procargs.* */
941 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_ARGS &&
942 		    (mib[3] == KERN_PROC_ARGV || mib[3] == KERN_PROC_ENV))
943 			return (0);
944 		if (miblen == 6 &&		/* kern.proc.* */
945 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC)
946 			return (0);
947 		if (miblen == 3 &&		/* kern.proc_cwd.* */
948 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_CWD)
949 			return (0);
950 		if (miblen == 2 &&		/* hw.physmem */
951 		    mib[0] == CTL_HW && mib[1] == HW_PHYSMEM64)
952 			return (0);
953 		if (miblen == 2 &&		/* kern.ccpu */
954 		    mib[0] == CTL_KERN && mib[1] == KERN_CCPU)
955 			return (0);
956 		if (miblen == 2 &&		/* vm.maxslp */
957 		    mib[0] == CTL_VM && mib[1] == VM_MAXSLP)
958 			return (0);
959 	}
960 
961 	if ((p->p_p->ps_pledge & PLEDGE_VMINFO)) {
962 		if (miblen == 2 &&		/* vm.uvmexp */
963 		    mib[0] == CTL_VM && mib[1] == VM_UVMEXP)
964 			return (0);
965 		if (miblen == 3 &&		/* vfs.generic.bcachestat */
966 		    mib[0] == CTL_VFS && mib[1] == VFS_GENERIC &&
967 		    mib[2] == VFS_BCACHESTAT)
968 			return (0);
969 	}
970 
971 	if ((p->p_p->ps_pledge & (PLEDGE_ROUTE | PLEDGE_INET | PLEDGE_DNS))) {
972 		if (miblen == 6 &&		/* getifaddrs() */
973 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
974 		    mib[2] == 0 &&
975 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
976 		    mib[4] == NET_RT_IFLIST)
977 			return (0);
978 	}
979 
980 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
981 		if (miblen == 2 &&		/* kern.rawpartition */
982 		    mib[0] == CTL_KERN &&
983 		    mib[1] == KERN_RAWPARTITION)
984 			return (0);
985 		if (miblen == 2 &&		/* kern.maxpartitions */
986 		    mib[0] == CTL_KERN &&
987 		    mib[1] == KERN_MAXPARTITIONS)
988 			return (0);
989 #ifdef CPU_CHR2BLK
990 		if (miblen == 3 &&		/* machdep.chr2blk */
991 		    mib[0] == CTL_MACHDEP &&
992 		    mib[1] == CPU_CHR2BLK)
993 			return (0);
994 #endif /* CPU_CHR2BLK */
995 	}
996 
997 	if (miblen >= 3 &&			/* ntpd(8) to read sensors */
998 	    mib[0] == CTL_HW && mib[1] == HW_SENSORS)
999 		return (0);
1000 
1001 	if (miblen == 2 &&		/* getdomainname() */
1002 	    mib[0] == CTL_KERN && mib[1] == KERN_DOMAINNAME)
1003 		return (0);
1004 	if (miblen == 2 &&		/* gethostname() */
1005 	    mib[0] == CTL_KERN && mib[1] == KERN_HOSTNAME)
1006 		return (0);
1007 	if (miblen == 6 &&		/* if_nameindex() */
1008 	    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
1009 	    mib[2] == 0 && mib[3] == 0 && mib[4] == NET_RT_IFNAMES)
1010 		return (0);
1011 	if (miblen == 2 &&		/* uname() */
1012 	    mib[0] == CTL_KERN && mib[1] == KERN_OSTYPE)
1013 		return (0);
1014 	if (miblen == 2 &&		/* uname() */
1015 	    mib[0] == CTL_KERN && mib[1] == KERN_OSRELEASE)
1016 		return (0);
1017 	if (miblen == 2 &&		/* uname() */
1018 	    mib[0] == CTL_KERN && mib[1] == KERN_OSVERSION)
1019 		return (0);
1020 	if (miblen == 2 &&		/* uname() */
1021 	    mib[0] == CTL_KERN && mib[1] == KERN_VERSION)
1022 		return (0);
1023 	if (miblen == 2 &&		/* kern.clockrate */
1024 	    mib[0] == CTL_KERN && mib[1] == KERN_CLOCKRATE)
1025 		return (0);
1026 	if (miblen == 2 &&		/* kern.argmax */
1027 	    mib[0] == CTL_KERN && mib[1] == KERN_ARGMAX)
1028 		return (0);
1029 	if (miblen == 2 &&		/* kern.ngroups */
1030 	    mib[0] == CTL_KERN && mib[1] == KERN_NGROUPS)
1031 		return (0);
1032 	if (miblen == 2 &&		/* kern.sysvshm */
1033 	    mib[0] == CTL_KERN && mib[1] == KERN_SYSVSHM)
1034 		return (0);
1035 	if (miblen == 2 &&		/* kern.posix1version */
1036 	    mib[0] == CTL_KERN && mib[1] == KERN_POSIX1)
1037 		return (0);
1038 	if (miblen == 2 &&		/* uname() */
1039 	    mib[0] == CTL_HW && mib[1] == HW_MACHINE)
1040 		return (0);
1041 	if (miblen == 2 &&		/* getpagesize() */
1042 	    mib[0] == CTL_HW && mib[1] == HW_PAGESIZE)
1043 		return (0);
1044 	if (miblen == 2 &&		/* setproctitle() */
1045 	    mib[0] == CTL_VM && mib[1] == VM_PSSTRINGS)
1046 		return (0);
1047 	if (miblen == 2 &&		/* hw.ncpu */
1048 	    mib[0] == CTL_HW && mib[1] == HW_NCPU)
1049 		return (0);
1050 	if (miblen == 2 &&		/* vm.loadavg / getloadavg(3) */
1051 	    mib[0] == CTL_VM && mib[1] == VM_LOADAVG)
1052 		return (0);
1053 
1054 	printf("%s(%d): sysctl %d: %d %d %d %d %d %d\n",
1055 	    p->p_p->ps_comm, p->p_p->ps_pid, miblen, mib[0], mib[1],
1056 	    mib[2], mib[3], mib[4], mib[5]);
1057 	return pledge_fail(p, EINVAL, 0);
1058 }
1059 
1060 int
1061 pledge_chown(struct proc *p, uid_t uid, gid_t gid)
1062 {
1063 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1064 		return (0);
1065 
1066 	if (p->p_p->ps_pledge & PLEDGE_CHOWNUID)
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 	if ((p->p_p->ps_pledge & PLEDGE_INET)) {
1132 		switch (com) {
1133 		case SIOCGIFGROUP:
1134 			if (fp->f_type == DTYPE_SOCKET)
1135 				return (0);
1136 			break;
1137 		}
1138 	}
1139 
1140 	if ((p->p_p->ps_pledge & PLEDGE_BPF)) {
1141 		switch (com) {
1142 		case BIOCGSTATS:	/* bpf: tcpdump privsep on ^C */
1143 			if (fp->f_type == DTYPE_VNODE &&
1144 			    fp->f_ops->fo_ioctl == vn_ioctl)
1145 				return (0);
1146 			break;
1147 		}
1148 	}
1149 
1150 	if ((p->p_p->ps_pledge & PLEDGE_TAPE)) {
1151 		switch (com) {
1152 		case MTIOCGET:
1153 		case MTIOCTOP:
1154 			/* for pax(1) and such, checking tapes... */
1155 			if (fp->f_type == DTYPE_VNODE &&
1156 			    (vp->v_type == VCHR || vp->v_type == VBLK))
1157 				return (0);
1158 			break;
1159 		}
1160 	}
1161 
1162 	if ((p->p_p->ps_pledge & PLEDGE_DRM)) {
1163 #if NDRM > 0
1164 		if ((fp->f_type == DTYPE_VNODE) &&
1165 		    (vp->v_type == VCHR) &&
1166 		    (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
1167 			error = pledge_ioctl_drm(p, com, vp->v_rdev);
1168 			if (error == 0)
1169 				return 0;
1170 		}
1171 #endif /* NDRM > 0 */
1172 	}
1173 
1174 	if ((p->p_p->ps_pledge & PLEDGE_AUDIO)) {
1175 #if NAUDIO > 0
1176 		switch (com) {
1177 		case AUDIO_GETPOS:
1178 		case AUDIO_GETPAR:
1179 		case AUDIO_SETPAR:
1180 		case AUDIO_START:
1181 		case AUDIO_STOP:
1182 			if (fp->f_type == DTYPE_VNODE &&
1183 			    vp->v_type == VCHR &&
1184 			    cdevsw[major(vp->v_rdev)].d_open == audioopen)
1185 				return (0);
1186 		}
1187 #endif /* NAUDIO > 0 */
1188 	}
1189 
1190 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
1191 		switch (com) {
1192 		case DIOCGDINFO:
1193 		case DIOCGPDINFO:
1194 		case DIOCRLDINFO:
1195 		case DIOCWDINFO:
1196 		case BIOCDISK:
1197 		case BIOCINQ:
1198 		case BIOCINSTALLBOOT:
1199 		case BIOCVOL:
1200 			if (fp->f_type == DTYPE_VNODE &&
1201 			    ((vp->v_type == VCHR &&
1202 			    cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
1203 			    (vp->v_type == VBLK &&
1204 			    bdevsw[major(vp->v_rdev)].d_type == D_DISK)))
1205 				return (0);
1206 			break;
1207 		case DIOCMAP:
1208 			if (fp->f_type == DTYPE_VNODE &&
1209 			    vp->v_type == VCHR &&
1210 			    cdevsw[major(vp->v_rdev)].d_ioctl == diskmapioctl)
1211 				return (0);
1212 			break;
1213 		}
1214 	}
1215 
1216 	if ((p->p_p->ps_pledge & PLEDGE_PF)) {
1217 #if NPF > 0
1218 		switch (com) {
1219 		case DIOCADDRULE:
1220 		case DIOCGETSTATUS:
1221 		case DIOCNATLOOK:
1222 		case DIOCRADDTABLES:
1223 		case DIOCRCLRADDRS:
1224 		case DIOCRCLRTABLES:
1225 		case DIOCRCLRTSTATS:
1226 		case DIOCRGETTSTATS:
1227 		case DIOCRSETADDRS:
1228 		case DIOCXBEGIN:
1229 		case DIOCXCOMMIT:
1230 		case DIOCKILLSRCNODES:
1231 			if ((fp->f_type == DTYPE_VNODE) &&
1232 			    (vp->v_type == VCHR) &&
1233 			    (cdevsw[major(vp->v_rdev)].d_open == pfopen))
1234 				return (0);
1235 			break;
1236 		}
1237 #endif
1238 	}
1239 
1240 	if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
1241 		switch (com) {
1242 #if NPTY > 0
1243 		case PTMGET:
1244 			if ((p->p_p->ps_pledge & PLEDGE_RPATH) == 0)
1245 				break;
1246 			if ((p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
1247 				break;
1248 			if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
1249 				break;
1250 			if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
1251 				break;
1252 			return (0);
1253 #endif /* NPTY > 0 */
1254 		case TIOCSTI:		/* ksh? csh? */
1255 			if ((p->p_p->ps_pledge & PLEDGE_PROC) &&
1256 			    fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1257 				return (0);
1258 			break;
1259 		case TIOCSPGRP:
1260 			if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
1261 				break;
1262 			/* FALLTHROUGH */
1263 		case TIOCFLUSH:		/* getty, telnet */
1264 		case TIOCGPGRP:
1265 		case TIOCGETA:
1266 		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
1267 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1268 				return (0);
1269 			return (ENOTTY);
1270 		case TIOCSWINSZ:
1271 		case TIOCEXT:		/* mail, libedit .. */
1272 		case TIOCCBRK:		/* cu */
1273 		case TIOCSBRK:		/* cu */
1274 		case TIOCCDTR:		/* cu */
1275 		case TIOCSDTR:		/* cu */
1276 		case TIOCEXCL:		/* cu */
1277 		case TIOCSETA:		/* cu, ... */
1278 		case TIOCSETAW:		/* cu, ... */
1279 		case TIOCSETAF:		/* tcsetattr TCSAFLUSH, script */
1280 		case TIOCSCTTY:		/* forkpty(3), login_tty(3), ... */
1281 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1282 				return (0);
1283 			break;
1284 		}
1285 	}
1286 
1287 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
1288 		switch (com) {
1289 		case SIOCGIFADDR:
1290 		case SIOCGIFFLAGS:
1291 		case SIOCGIFMETRIC:
1292 		case SIOCGIFGMEMB:
1293 		case SIOCGIFRDOMAIN:
1294 		case SIOCGIFDSTADDR_IN6:
1295 		case SIOCGIFNETMASK_IN6:
1296 		case SIOCGNBRINFO_IN6:
1297 		case SIOCGIFINFO_IN6:
1298 		case SIOCGIFMEDIA:
1299 			if (fp->f_type == DTYPE_SOCKET)
1300 				return (0);
1301 			break;
1302 		}
1303 	}
1304 
1305 	if ((p->p_p->ps_pledge & PLEDGE_VMM)) {
1306 #if NVMM > 0
1307 		if ((fp->f_type == DTYPE_VNODE) &&
1308 		    (vp->v_type == VCHR) &&
1309 		    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
1310 			error = pledge_ioctl_vmm(p, com);
1311 			if (error == 0)
1312 				return 0;
1313 		}
1314 #endif
1315 	}
1316 
1317 	return pledge_fail(p, error, PLEDGE_TTY);
1318 }
1319 
1320 int
1321 pledge_sockopt(struct proc *p, int set, int level, int optname)
1322 {
1323 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1324 		return (0);
1325 
1326 	/* Always allow these, which are too common to reject */
1327 	switch (level) {
1328 	case SOL_SOCKET:
1329 		switch (optname) {
1330 		case SO_RCVBUF:
1331 		case SO_ERROR:
1332 			return 0;
1333 		}
1334 		break;
1335 	}
1336 
1337 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS|PLEDGE_YPACTIVE)) == 0)
1338 		return pledge_fail(p, EPERM, PLEDGE_INET);
1339 	/* In use by some service libraries */
1340 	switch (level) {
1341 	case SOL_SOCKET:
1342 		switch (optname) {
1343 		case SO_TIMESTAMP:
1344 			return 0;
1345 		}
1346 		break;
1347 	}
1348 
1349 	/* DNS resolver may do these requests */
1350 	if ((p->p_p->ps_pledge & PLEDGE_DNS)) {
1351 		switch (level) {
1352 		case IPPROTO_IPV6:
1353 			switch (optname) {
1354 			case IPV6_RECVPKTINFO:
1355 			case IPV6_USE_MIN_MTU:
1356 				return (0);
1357 			}
1358 		}
1359 	}
1360 
1361 	/* YP may do these requests */
1362 	if (p->p_p->ps_pledge & PLEDGE_YPACTIVE) {
1363 		switch (level) {
1364 		case IPPROTO_IP:
1365 			switch (optname) {
1366 			case IP_PORTRANGE:
1367 				return (0);
1368 			}
1369 			break;
1370 
1371 		case IPPROTO_IPV6:
1372 			switch (optname) {
1373 			case IPV6_PORTRANGE:
1374 				return (0);
1375 			}
1376 			break;
1377 		}
1378 	}
1379 
1380 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
1381 		return pledge_fail(p, EPERM, PLEDGE_INET);
1382 	switch (level) {
1383 	case SOL_SOCKET:
1384 		switch (optname) {
1385 		case SO_RTABLE:
1386 			return pledge_fail(p, EINVAL, PLEDGE_INET);
1387 		}
1388 		return (0);
1389 	}
1390 
1391 	if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
1392 		return pledge_fail(p, EPERM, PLEDGE_INET);
1393 	switch (level) {
1394 	case IPPROTO_TCP:
1395 		switch (optname) {
1396 		case TCP_NODELAY:
1397 		case TCP_MD5SIG:
1398 		case TCP_SACK_ENABLE:
1399 		case TCP_MAXSEG:
1400 		case TCP_NOPUSH:
1401 			return (0);
1402 		}
1403 		break;
1404 	case IPPROTO_IP:
1405 		switch (optname) {
1406 		case IP_OPTIONS:
1407 			if (!set)
1408 				return (0);
1409 			break;
1410 		case IP_TOS:
1411 		case IP_TTL:
1412 		case IP_MINTTL:
1413 		case IP_IPDEFTTL:
1414 		case IP_PORTRANGE:
1415 		case IP_RECVDSTADDR:
1416 		case IP_RECVDSTPORT:
1417 			return (0);
1418 		case IP_MULTICAST_IF:
1419 		case IP_ADD_MEMBERSHIP:
1420 		case IP_DROP_MEMBERSHIP:
1421 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1422 				return (0);
1423 			break;
1424 		}
1425 		break;
1426 	case IPPROTO_ICMP:
1427 		break;
1428 	case IPPROTO_IPV6:
1429 		switch (optname) {
1430 		case IPV6_TCLASS:
1431 		case IPV6_UNICAST_HOPS:
1432 		case IPV6_MINHOPCOUNT:
1433 		case IPV6_RECVHOPLIMIT:
1434 		case IPV6_PORTRANGE:
1435 		case IPV6_RECVPKTINFO:
1436 		case IPV6_RECVDSTPORT:
1437 #ifdef notyet
1438 		case IPV6_V6ONLY:
1439 #endif
1440 			return (0);
1441 		case IPV6_MULTICAST_IF:
1442 		case IPV6_JOIN_GROUP:
1443 		case IPV6_LEAVE_GROUP:
1444 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1445 				return (0);
1446 			break;
1447 		}
1448 		break;
1449 	case IPPROTO_ICMPV6:
1450 		break;
1451 	}
1452 	return pledge_fail(p, EPERM, PLEDGE_INET);
1453 }
1454 
1455 int
1456 pledge_socket(struct proc *p, int domain, int state)
1457 {
1458 	if (! ISSET(p->p_p->ps_flags, PS_PLEDGE))
1459 		return 0;
1460 
1461 	if (ISSET(state, SS_DNS)) {
1462 		if (ISSET(p->p_p->ps_pledge, PLEDGE_DNS))
1463 			return 0;
1464 		return pledge_fail(p, EPERM, PLEDGE_DNS);
1465 	}
1466 
1467 	switch (domain) {
1468 	case -1:		/* accept on any domain */
1469 		return (0);
1470 	case AF_INET:
1471 	case AF_INET6:
1472 		if (ISSET(p->p_p->ps_pledge, PLEDGE_INET) ||
1473 		    ISSET(p->p_p->ps_pledge, PLEDGE_YPACTIVE))
1474 			return 0;
1475 		return pledge_fail(p, EPERM, PLEDGE_INET);
1476 
1477 	case AF_UNIX:
1478 		if (ISSET(p->p_p->ps_pledge, PLEDGE_UNIX))
1479 			return 0;
1480 		return pledge_fail(p, EPERM, PLEDGE_UNIX);
1481 	}
1482 
1483 	return pledge_fail(p, EINVAL, PLEDGE_INET);
1484 }
1485 
1486 int
1487 pledge_flock(struct proc *p)
1488 {
1489 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1490 		return (0);
1491 
1492 	if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
1493 		return (0);
1494 	return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
1495 }
1496 
1497 int
1498 pledge_swapctl(struct proc *p)
1499 {
1500 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1501 		return (0);
1502 	return (EPERM);
1503 }
1504 
1505 /* bsearch over pledgereq. return flags value if found, 0 else */
1506 uint64_t
1507 pledgereq_flags(const char *req_name)
1508 {
1509 	int base = 0, cmp, i, lim;
1510 
1511 	for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
1512 		i = base + (lim >> 1);
1513 		cmp = strcmp(req_name, pledgereq[i].name);
1514 		if (cmp == 0)
1515 			return (pledgereq[i].flags);
1516 		if (cmp > 0) { /* not found before, move right */
1517 			base = i + 1;
1518 			lim--;
1519 		} /* else move left */
1520 	}
1521 	return (0);
1522 }
1523 
1524 int
1525 pledge_fcntl(struct proc *p, int cmd)
1526 {
1527 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1528 		return (0);
1529 	if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0 && cmd == F_SETOWN)
1530 		return pledge_fail(p, EPERM, PLEDGE_PROC);
1531 	return (0);
1532 }
1533 
1534 int
1535 pledge_kill(struct proc *p, pid_t pid)
1536 {
1537 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1538 		return 0;
1539 	if (p->p_p->ps_pledge & PLEDGE_PROC)
1540 		return 0;
1541 	if (pid == 0 || pid == p->p_p->ps_pid)
1542 		return 0;
1543 	return pledge_fail(p, EPERM, PLEDGE_PROC);
1544 }
1545 
1546 int
1547 pledge_protexec(struct proc *p, int prot)
1548 {
1549 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1550 		return 0;
1551 	if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
1552 		return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
1553 	return 0;
1554 }
1555 
1556 void
1557 pledge_dropwpaths(struct process *pr)
1558 {
1559 	if (pr->ps_pledgepaths && --pr->ps_pledgepaths->wl_ref == 0) {
1560 		struct whitepaths *wl = pr->ps_pledgepaths;
1561 		int i;
1562 
1563 		for (i = 0; i < wl->wl_count; i++)
1564 			free(wl->wl_paths[i].name, M_TEMP, wl->wl_paths[i].len);
1565 		free(wl, M_TEMP, wl->wl_size);
1566 	}
1567 	pr->ps_pledgepaths = NULL;
1568 }
1569 
1570 int
1571 canonpath(const char *input, char *buf, size_t bufsize)
1572 {
1573 	const char *p;
1574 	char *q;
1575 
1576 	/* can't canon relative paths, don't bother */
1577 	if (input[0] != '/') {
1578 		if (strlcpy(buf, input, bufsize) >= bufsize)
1579 			return ENAMETOOLONG;
1580 		return 0;
1581 	}
1582 
1583 	p = input;
1584 	q = buf;
1585 	while (*p && (q - buf < bufsize)) {
1586 		if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
1587 			p += 1;
1588 
1589 		} else if (p[0] == '/' && p[1] == '.' &&
1590 		    (p[2] == '/' || p[2] == '\0')) {
1591 			p += 2;
1592 
1593 		} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
1594 		    (p[3] == '/' || p[3] == '\0')) {
1595 			p += 3;
1596 			if (q != buf)	/* "/../" at start of buf */
1597 				while (*--q != '/')
1598 					continue;
1599 
1600 		} else {
1601 			*q++ = *p++;
1602 		}
1603 	}
1604 	if ((*p == '\0') && (q - buf < bufsize)) {
1605 		*q = 0;
1606 		return 0;
1607 	} else
1608 		return ENAMETOOLONG;
1609 }
1610 
1611 int
1612 substrcmp(const char *p1, size_t s1, const char *p2, size_t s2)
1613 {
1614 	size_t i;
1615 	for (i = 0; i < s1 || i < s2; i++) {
1616 		if (p1[i] != p2[i])
1617 			break;
1618 	}
1619 	if (i == s1) {
1620 		return (1);	/* string1 is a subpath of string2 */
1621 	} else if (i == s2)
1622 		return (2);	/* string2 is a subpath of string1 */
1623 	else
1624 		return (0);	/* no subpath */
1625 }
1626 
1627 int
1628 resolvpath(struct proc *p,
1629     char **rdir, size_t *rdirlen,
1630     char **cwd, size_t *cwdlen,
1631     char *path, size_t pathlen,
1632     char **resolved, size_t *resolvedlen)
1633 {
1634 	int error;
1635 	char *abspath = NULL, *canopath = NULL, *fullpath = NULL;
1636 	size_t abspathlen, canopathlen = 0, fullpathlen = 0, canopathlen_exact;
1637 
1638 	/* 1. get an absolute path (inside any chroot) : path -> abspath */
1639 	if (path[0] != '/') {
1640 		/* path is relative: prepend cwd */
1641 
1642 		/* get cwd first (if needed) */
1643 		if (*cwd == NULL) {
1644 			char *rawcwd, *bp, *bpend;
1645 			size_t rawcwdlen = MAXPATHLEN * 4;
1646 
1647 			rawcwd = malloc(rawcwdlen, M_TEMP, M_WAITOK);
1648 			bp = &rawcwd[rawcwdlen];
1649 			bpend = bp;
1650 			*(--bp) = '\0';
1651 
1652 			error = vfs_getcwd_common(p->p_fd->fd_cdir,
1653 			    NULL, &bp, rawcwd, rawcwdlen/2,
1654 			    GETCWD_CHECK_ACCESS, p);
1655 			if (error) {
1656 				free(rawcwd, M_TEMP, rawcwdlen);
1657 				goto out;
1658 			}
1659 
1660 			/* NUL is included */
1661 			*cwdlen = (bpend - bp);
1662 			*cwd = malloc(*cwdlen, M_TEMP, M_WAITOK);
1663 			memcpy(*cwd, bp, *cwdlen);
1664 
1665 			free(rawcwd, M_TEMP, rawcwdlen);
1666 		}
1667 
1668 		/* NUL included in *cwdlen and pathlen */
1669 		abspathlen = *cwdlen + pathlen;
1670 		abspath = malloc(abspathlen, M_TEMP, M_WAITOK);
1671 		snprintf(abspath, abspathlen, "%s/%s", *cwd, path);
1672 
1673 	} else {
1674 		/* path is absolute */
1675 		abspathlen = pathlen;
1676 		abspath = malloc(abspathlen, M_TEMP, M_WAITOK);
1677 		memcpy(abspath, path, pathlen);
1678 	}
1679 
1680 	/* 2. canonization: abspath -> canopath */
1681 	canopathlen = abspathlen;
1682 	canopath = malloc(canopathlen, M_TEMP, M_WAITOK);
1683 	error = canonpath(abspath, canopath, canopathlen);
1684 
1685 	/* free abspath now as we don't need it after */
1686 	free(abspath, M_TEMP, abspathlen);
1687 
1688 	/* error in canonpath() call (should not happen, but keep safe) */
1689 	if (error != 0)
1690 		goto out;
1691 
1692 	/* check the canopath size */
1693 	canopathlen_exact = strlen(canopath) + 1;
1694 	if (canopathlen_exact > MAXPATHLEN) {
1695 		error = ENAMETOOLONG;
1696 		goto out;
1697 	}
1698 
1699 	/* 3. preprend *rdir if chrooted : canonpath -> fullpath */
1700 	if (p->p_fd->fd_rdir != NULL) {
1701 		if (*rdir == NULL) {
1702 			char *rawrdir, *bp, *bpend;
1703 			size_t rawrdirlen = MAXPATHLEN * 4;
1704 
1705 			rawrdir = malloc(rawrdirlen, M_TEMP, M_WAITOK);
1706 			bp = &rawrdir[rawrdirlen];
1707 			bpend = bp;
1708 			*(--bp) = '\0';
1709 
1710 			error = vfs_getcwd_common(p->p_fd->fd_rdir,
1711 			    rootvnode, &bp, rawrdir, rawrdirlen/2,
1712 			    GETCWD_CHECK_ACCESS, p);
1713 			if (error) {
1714 				free(rawrdir, M_TEMP, rawrdirlen);
1715 				goto out;
1716 			}
1717 
1718 			/* NUL is included */
1719 			*rdirlen = (bpend - bp);
1720 			*rdir = malloc(*rdirlen, M_TEMP, M_WAITOK);
1721 			memcpy(*rdir, bp, *rdirlen);
1722 
1723 			free(rawrdir, M_TEMP, rawrdirlen);
1724 		}
1725 
1726 		/*
1727 		 * NUL is included in *rdirlen and canopathlen_exact.
1728 		 * doesn't add "/" between them, as canopath is absolute.
1729 		 */
1730 		fullpathlen = *rdirlen + canopathlen_exact - 1;
1731 		fullpath = malloc(fullpathlen, M_TEMP, M_WAITOK);
1732 		snprintf(fullpath, fullpathlen, "%s%s", *rdir, canopath);
1733 
1734 	} else {
1735 		/* not chrooted: only reduce canopath to exact length */
1736 		fullpathlen = canopathlen_exact;
1737 		fullpath = malloc(fullpathlen, M_TEMP, M_WAITOK);
1738 		memcpy(fullpath, canopath, fullpathlen);
1739 	}
1740 
1741 	*resolvedlen = fullpathlen;
1742 	*resolved = fullpath;
1743 
1744 out:
1745 	free(canopath, M_TEMP, canopathlen);
1746 	if (error != 0)
1747 		free(fullpath, M_TEMP, fullpathlen);
1748 	return error;
1749 }
1750