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