xref: /openbsd-src/sys/kern/kern_pledge.c (revision c0dd97bfcad3dab6c31ec12b9de1274fd2d2f993)
1 /*	$OpenBSD: kern_pledge.c,v 1.223 2017/10/12 15:04:33 bluhm 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 
22 #include <sys/mount.h>
23 #include <sys/proc.h>
24 #include <sys/fcntl.h>
25 #include <sys/file.h>
26 #include <sys/filedesc.h>
27 #include <sys/namei.h>
28 #include <sys/socketvar.h>
29 #include <sys/vnode.h>
30 #include <sys/mbuf.h>
31 #include <sys/mman.h>
32 #include <sys/sysctl.h>
33 #include <sys/syslog.h>
34 #include <sys/ktrace.h>
35 #include <sys/acct.h>
36 
37 #include <sys/ioctl.h>
38 #include <sys/termios.h>
39 #include <sys/tty.h>
40 #include <sys/device.h>
41 #include <sys/disklabel.h>
42 #include <sys/dkio.h>
43 #include <sys/mtio.h>
44 #include <sys/audioio.h>
45 #include <net/bpf.h>
46 #include <net/route.h>
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <netinet/in.h>
50 #include <netinet6/in6_var.h>
51 #include <netinet6/nd6.h>
52 #include <netinet/tcp.h>
53 #include <net/pfvar.h>
54 
55 #include <sys/conf.h>
56 #include <sys/specdev.h>
57 #include <sys/signal.h>
58 #include <sys/signalvar.h>
59 #include <sys/syscall.h>
60 #include <sys/syscallargs.h>
61 #include <sys/systm.h>
62 
63 #include <dev/biovar.h>
64 
65 #define PLEDGENAMES
66 #include <sys/pledge.h>
67 
68 #include "audio.h"
69 #include "bpfilter.h"
70 #include "pf.h"
71 #include "pty.h"
72 
73 #if defined(__amd64__) || defined(__i386__)
74 #include "vmm.h"
75 #if NVMM > 0
76 #include <machine/conf.h>
77 #endif
78 #endif
79 
80 #if defined(__amd64__) || defined(__i386__) || \
81     defined(__loongson__) || defined(__macppc__) || \
82     defined(__sparc64__)
83 #include "drm.h"
84 #endif
85 
86 uint64_t pledgereq_flags(const char *req);
87 int canonpath(const char *input, char *buf, size_t bufsize);
88 
89 /* #define DEBUG_PLEDGE */
90 #ifdef DEBUG_PLEDGE
91 int debug_pledge = 1;
92 #define DPRINTF(x...)    do { if (debug_pledge) printf(x); } while (0)
93 #define DNPRINTF(n,x...) do { if (debug_pledge >= (n)) printf(x); } while (0)
94 #else
95 #define DPRINTF(x...)
96 #define DNPRINTF(n,x...)
97 #endif
98 
99 /*
100  * Ordered in blocks starting with least risky and most required.
101  */
102 const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = {
103 	/*
104 	 * Minimum required
105 	 */
106 	[SYS_exit] = PLEDGE_ALWAYS,
107 	[SYS_kbind] = PLEDGE_ALWAYS,
108 	[SYS___get_tcb] = PLEDGE_ALWAYS,
109 	[SYS___set_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_getlogin_r] = PLEDGE_STDIO,
124 	[SYS_getpgrp] = PLEDGE_STDIO,
125 	[SYS_getpgid] = PLEDGE_STDIO,
126 	[SYS_getppid] = PLEDGE_STDIO,
127 	[SYS_getsid] = PLEDGE_STDIO,
128 	[SYS_getthrid] = PLEDGE_STDIO,
129 	[SYS_getrlimit] = PLEDGE_STDIO,
130 	[SYS_getrtable] = 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_futex] = PLEDGE_STDIO,
262 	[SYS___thrsleep] = PLEDGE_STDIO,
263 	[SYS___thrwakeup] = PLEDGE_STDIO,
264 	[SYS___threxit] = PLEDGE_STDIO,
265 	[SYS___thrsigdivert] = PLEDGE_STDIO,
266 
267 	[SYS_fork] = PLEDGE_PROC,
268 	[SYS_vfork] = PLEDGE_PROC,
269 	[SYS_setpgid] = PLEDGE_PROC,
270 	[SYS_setsid] = PLEDGE_PROC,
271 
272 	[SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
273 	[SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
274 
275 	[SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
276 
277 	[SYS_setuid] = PLEDGE_ID,
278 	[SYS_seteuid] = PLEDGE_ID,
279 	[SYS_setreuid] = PLEDGE_ID,
280 	[SYS_setresuid] = PLEDGE_ID,
281 	[SYS_setgid] = PLEDGE_ID,
282 	[SYS_setegid] = PLEDGE_ID,
283 	[SYS_setregid] = PLEDGE_ID,
284 	[SYS_setresgid] = PLEDGE_ID,
285 	[SYS_setgroups] = PLEDGE_ID,
286 	[SYS_setlogin] = PLEDGE_ID,
287 
288 	[SYS_execve] = PLEDGE_EXEC,
289 
290 	[SYS_chdir] = PLEDGE_RPATH,
291 	[SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
292 	[SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
293 	[SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
294 	[SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
295 	[SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
296 	[SYS_truncate] = PLEDGE_WPATH,
297 	[SYS_rename] = PLEDGE_RPATH | PLEDGE_CPATH,
298 	[SYS_rmdir] = PLEDGE_CPATH,
299 	[SYS_renameat] = PLEDGE_CPATH,
300 	[SYS_link] = PLEDGE_CPATH,
301 	[SYS_linkat] = PLEDGE_CPATH,
302 	[SYS_symlink] = PLEDGE_CPATH,
303 	[SYS_symlinkat] = PLEDGE_CPATH,
304 	[SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
305 	[SYS_unlinkat] = PLEDGE_CPATH,
306 	[SYS_mkdir] = PLEDGE_CPATH,
307 	[SYS_mkdirat] = PLEDGE_CPATH,
308 
309 	[SYS_mkfifo] = PLEDGE_DPATH,
310 	[SYS_mknod] = PLEDGE_DPATH,
311 
312 	[SYS_revoke] = PLEDGE_TTY,	/* also requires PLEDGE_RPATH */
313 
314 	/*
315 	 * Classify as RPATH|WPATH, because of path information leakage.
316 	 * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
317 	 */
318 	[SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
319 
320 	/* Classify as RPATH, because these leak path information */
321 	[SYS_getdents] = PLEDGE_RPATH,
322 	[SYS_getfsstat] = PLEDGE_RPATH,
323 	[SYS_statfs] = PLEDGE_RPATH,
324 	[SYS_fstatfs] = PLEDGE_RPATH,
325 	[SYS_pathconf] = PLEDGE_RPATH,
326 
327 	[SYS_utimes] = PLEDGE_FATTR,
328 	[SYS_futimes] = PLEDGE_FATTR,
329 	[SYS_utimensat] = PLEDGE_FATTR,
330 	[SYS_futimens] = PLEDGE_FATTR,
331 	[SYS_chmod] = PLEDGE_FATTR,
332 	[SYS_fchmod] = PLEDGE_FATTR,
333 	[SYS_fchmodat] = PLEDGE_FATTR,
334 	[SYS_chflags] = PLEDGE_FATTR,
335 	[SYS_chflagsat] = PLEDGE_FATTR,
336 	[SYS_fchflags] = PLEDGE_FATTR,
337 
338 	[SYS_chown] = PLEDGE_CHOWN,
339 	[SYS_fchownat] = PLEDGE_CHOWN,
340 	[SYS_lchown] = PLEDGE_CHOWN,
341 	[SYS_fchown] = PLEDGE_CHOWN,
342 
343 	[SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
344 	[SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
345 	[SYS_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
346 	[SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
347 
348 	[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
349 	[SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
350 	[SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
351 	[SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
352 
353 	[SYS_flock] = PLEDGE_FLOCK | PLEDGE_YPACTIVE,
354 
355 	[SYS_swapctl] = PLEDGE_VMINFO,	/* XXX should limit to "get" operations */
356 };
357 
358 static const struct {
359 	char *name;
360 	uint64_t flags;
361 } pledgereq[] = {
362 	{ "audio",		PLEDGE_AUDIO },
363 	{ "bpf",		PLEDGE_BPF },
364 	{ "chown",		PLEDGE_CHOWN | PLEDGE_CHOWNUID },
365 	{ "cpath",		PLEDGE_CPATH },
366 	{ "disklabel",		PLEDGE_DISKLABEL },
367 	{ "dns",		PLEDGE_DNS },
368 	{ "dpath",		PLEDGE_DPATH },
369 	{ "drm",		PLEDGE_DRM },
370 	{ "exec",		PLEDGE_EXEC },
371 	{ "fattr",		PLEDGE_FATTR | PLEDGE_CHOWN },
372 	{ "flock",		PLEDGE_FLOCK },
373 	{ "getpw",		PLEDGE_GETPW },
374 	{ "id",			PLEDGE_ID },
375 	{ "inet",		PLEDGE_INET },
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 		return (EINVAL);
451 
452 	if (SCARG(uap, request)) {
453 		pr->ps_pledge = flags;
454 		pr->ps_flags |= PS_PLEDGE;
455 	}
456 
457 	return (0);
458 }
459 
460 int
461 pledge_syscall(struct proc *p, int code, uint64_t *tval)
462 {
463 	p->p_pledge_syscall = code;
464 	*tval = 0;
465 
466 	if (code < 0 || code > SYS_MAXSYSCALL - 1)
467 		return (EINVAL);
468 
469 	if (pledge_syscalls[code] == PLEDGE_ALWAYS)
470 		return (0);
471 
472 	if (p->p_p->ps_pledge & pledge_syscalls[code])
473 		return (0);
474 
475 	*tval = pledge_syscalls[code];
476 	return (EPERM);
477 }
478 
479 int
480 pledge_fail(struct proc *p, int error, uint64_t code)
481 {
482 	char *codes = "";
483 	int i;
484 	struct sigaction sa;
485 
486 	/* Print first matching pledge */
487 	for (i = 0; code && pledgenames[i].bits != 0; i++)
488 		if (pledgenames[i].bits & code) {
489 			codes = pledgenames[i].name;
490 			break;
491 		}
492 	log(LOG_ERR, "%s[%d]: pledge \"%s\", syscall %d\n",
493 	    p->p_p->ps_comm, p->p_p->ps_pid, codes, p->p_pledge_syscall);
494 	p->p_p->ps_acflag |= APLEDGE;
495 #ifdef KTRACE
496 	if (KTRPOINT(p, KTR_PLEDGE))
497 		ktrpledge(p, error, code, p->p_pledge_syscall);
498 #endif
499 	/* Send uncatchable SIGABRT for coredump */
500 	memset(&sa, 0, sizeof sa);
501 	sa.sa_handler = SIG_DFL;
502 	setsigvec(p, SIGABRT, &sa);
503 	psignal(p, SIGABRT);
504 
505 	p->p_p->ps_pledge = 0;		/* Disable all PLEDGE_ flags */
506 	return (error);
507 }
508 
509 /*
510  * Need to make it more obvious that one cannot get through here
511  * without the right flags set
512  */
513 int
514 pledge_namei(struct proc *p, struct nameidata *ni, char *origpath)
515 {
516 	char path[PATH_MAX];
517 	int error;
518 
519 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0 ||
520 	    (p->p_p->ps_flags & PS_COREDUMP))
521 		return (0);
522 
523 	if (!ni || (ni->ni_pledge == 0))
524 		panic("ni_pledge");
525 
526 	/* Doing a permitted execve() */
527 	if ((ni->ni_pledge & PLEDGE_EXEC) &&
528 	    (p->p_p->ps_pledge & PLEDGE_EXEC))
529 		return (0);
530 
531 	error = canonpath(origpath, path, sizeof(path));
532 	if (error)
533 		return (error);
534 
535 	/* Detect what looks like a mkstemp(3) family operation */
536 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
537 	    (p->p_pledge_syscall == SYS_open) &&
538 	    (ni->ni_pledge & PLEDGE_CPATH) &&
539 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
540 		return (0);
541 	}
542 
543 	/* Allow unlinking of a mkstemp(3) file...
544 	 * Good opportunity for strict checks here.
545 	 */
546 	if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
547 	    (p->p_pledge_syscall == SYS_unlink) &&
548 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
549 		return (0);
550 	}
551 
552 	/* Whitelisted paths */
553 	switch (p->p_pledge_syscall) {
554 	case SYS_access:
555 		/* tzset() needs this. */
556 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
557 		    strcmp(path, "/etc/localtime") == 0)
558 			return (0);
559 
560 		/* when avoiding YP mode, getpw* functions touch this */
561 		if (ni->ni_pledge == PLEDGE_RPATH &&
562 		    strcmp(path, "/var/run/ypbind.lock") == 0) {
563 			if (p->p_p->ps_pledge & PLEDGE_GETPW)
564 				return (0);
565 			else
566 				return (pledge_fail(p, error, PLEDGE_GETPW));
567 		}
568 		break;
569 	case SYS_open:
570 		/* daemon(3) or other such functions */
571 		if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
572 		    strcmp(path, "/dev/null") == 0) {
573 			return (0);
574 		}
575 
576 		/* readpassphrase(3), getpass(3) */
577 		if ((p->p_p->ps_pledge & PLEDGE_TTY) &&
578 		    (ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
579 		    strcmp(path, "/dev/tty") == 0) {
580 			return (0);
581 		}
582 
583 		/* getpw* and friends need a few files */
584 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
585 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
586 			if (strcmp(path, "/etc/spwd.db") == 0)
587 				return (EPERM); /* don't call pledge_fail */
588 			if (strcmp(path, "/etc/pwd.db") == 0)
589 				return (0);
590 			if (strcmp(path, "/etc/group") == 0)
591 				return (0);
592 			if (strcmp(path, "/etc/netid") == 0)
593 				return (0);
594 		}
595 
596 		/* DNS needs /etc/{resolv.conf,hosts,services}. */
597 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
598 		    (p->p_p->ps_pledge & PLEDGE_DNS)) {
599 			if (strcmp(path, "/etc/resolv.conf") == 0)
600 				return (0);
601 			if (strcmp(path, "/etc/hosts") == 0)
602 				return (0);
603 			if (strcmp(path, "/etc/services") == 0)
604 				return (0);
605 		}
606 
607 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
608 		    (p->p_p->ps_pledge & PLEDGE_GETPW)) {
609 			if (strcmp(path, "/var/run/ypbind.lock") == 0) {
610 				/*
611 				 * XXX
612 				 * The current hack for YP support in "getpw"
613 				 * is to enable some "inet" features until
614 				 * next pledge call.  This is not considered
615 				 * worse than pre-pledge, but is a work in
616 				 * progress, needing a clever design.
617 				 */
618 				p->p_p->ps_pledge |= PLEDGE_YPACTIVE;
619 				return (0);
620 			}
621 			if (strncmp(path, "/var/yp/binding/",
622 			    sizeof("/var/yp/binding/") - 1) == 0)
623 				return (0);
624 		}
625 
626 		/* tzset() needs these. */
627 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
628 		    strncmp(path, "/usr/share/zoneinfo/",
629 		    sizeof("/usr/share/zoneinfo/") - 1) == 0)
630 			return (0);
631 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
632 		    strcmp(path, "/etc/localtime") == 0)
633 			return (0);
634 
635 		break;
636 	case SYS_readlink:
637 		/* Allow /etc/malloc.conf for malloc(3). */
638 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
639 		    strcmp(path, "/etc/malloc.conf") == 0)
640 			return (0);
641 		break;
642 	case SYS_stat:
643 		/* DNS needs /etc/resolv.conf. */
644 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
645 		    (p->p_p->ps_pledge & PLEDGE_DNS) &&
646 		    strcmp(path, "/etc/resolv.conf") == 0)
647 			return (0);
648 		break;
649 	}
650 
651 	/*
652 	 * Ensure each flag of p_pledgenote has counterpart allowing it in
653 	 * ps_pledge
654 	 */
655 	if (ni->ni_pledge & ~p->p_p->ps_pledge)
656 		return (pledge_fail(p, EPERM, (ni->ni_pledge & ~p->p_p->ps_pledge)));
657 
658 	return (0);
659 }
660 
661 /*
662  * Only allow reception of safe file descriptors.
663  */
664 int
665 pledge_recvfd(struct proc *p, struct file *fp)
666 {
667 	struct vnode *vp;
668 
669 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
670 		return (0);
671 	if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
672 		return pledge_fail(p, EPERM, PLEDGE_RECVFD);
673 
674 	switch (fp->f_type) {
675 	case DTYPE_SOCKET:
676 	case DTYPE_PIPE:
677 		return (0);
678 	case DTYPE_VNODE:
679 		vp = fp->f_data;
680 
681 		if (vp->v_type != VDIR)
682 			return (0);
683 		break;
684 	}
685 	return pledge_fail(p, EINVAL, PLEDGE_RECVFD);
686 }
687 
688 /*
689  * Only allow sending of safe file descriptors.
690  */
691 int
692 pledge_sendfd(struct proc *p, struct file *fp)
693 {
694 	struct vnode *vp;
695 
696 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
697 		return (0);
698 	if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
699 		return pledge_fail(p, EPERM, PLEDGE_SENDFD);
700 
701 	switch (fp->f_type) {
702 	case DTYPE_SOCKET:
703 	case DTYPE_PIPE:
704 		return (0);
705 	case DTYPE_VNODE:
706 		vp = fp->f_data;
707 
708 		if (vp->v_type != VDIR)
709 			return (0);
710 		break;
711 	}
712 	return pledge_fail(p, EINVAL, PLEDGE_SENDFD);
713 }
714 
715 int
716 pledge_sysctl(struct proc *p, int miblen, int *mib, void *new)
717 {
718 	char	buf[80];
719 	int	i;
720 
721 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
722 		return (0);
723 
724 	if (new)
725 		return pledge_fail(p, EFAULT, 0);
726 
727 	/* routing table observation */
728 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
729 		if ((miblen == 6 || miblen == 7) &&
730 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
731 		    mib[2] == 0 &&
732 		    mib[4] == NET_RT_DUMP)
733 			return (0);
734 
735 		if (miblen == 6 &&
736 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
737 		    mib[2] == 0 &&
738 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
739 		    mib[4] == NET_RT_TABLE)
740 			return (0);
741 
742 		if (miblen == 7 &&		/* exposes MACs */
743 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
744 		    mib[2] == 0 &&
745 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
746 		    mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
747 			return (0);
748 	}
749 
750 	if (p->p_p->ps_pledge & (PLEDGE_PS | PLEDGE_VMINFO)) {
751 		if (miblen == 2 &&		/* kern.fscale */
752 		    mib[0] == CTL_KERN && mib[1] == KERN_FSCALE)
753 			return (0);
754 		if (miblen == 2 &&		/* kern.boottime */
755 		    mib[0] == CTL_KERN && mib[1] == KERN_BOOTTIME)
756 			return (0);
757 		if (miblen == 2 &&		/* kern.consdev */
758 		    mib[0] == CTL_KERN && mib[1] == KERN_CONSDEV)
759 			return (0);
760 		if (miblen == 2 &&			/* kern.cptime */
761 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME)
762 			return (0);
763 		if (miblen == 3 &&			/* kern.cptime2 */
764 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME2)
765 			return (0);
766 	}
767 
768 	if ((p->p_p->ps_pledge & PLEDGE_PS)) {
769 		if (miblen == 4 &&		/* kern.procargs.* */
770 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_ARGS &&
771 		    (mib[3] == KERN_PROC_ARGV || mib[3] == KERN_PROC_ENV))
772 			return (0);
773 		if (miblen == 6 &&		/* kern.proc.* */
774 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC)
775 			return (0);
776 		if (miblen == 3 &&		/* kern.proc_cwd.* */
777 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_CWD)
778 			return (0);
779 		if (miblen == 2 &&		/* hw.physmem */
780 		    mib[0] == CTL_HW && mib[1] == HW_PHYSMEM64)
781 			return (0);
782 		if (miblen == 2 &&		/* kern.ccpu */
783 		    mib[0] == CTL_KERN && mib[1] == KERN_CCPU)
784 			return (0);
785 		if (miblen == 2 &&		/* vm.maxslp */
786 		    mib[0] == CTL_VM && mib[1] == VM_MAXSLP)
787 			return (0);
788 	}
789 
790 	if ((p->p_p->ps_pledge & PLEDGE_VMINFO)) {
791 		if (miblen == 2 &&		/* vm.uvmexp */
792 		    mib[0] == CTL_VM && mib[1] == VM_UVMEXP)
793 			return (0);
794 		if (miblen == 3 &&		/* vfs.generic.bcachestat */
795 		    mib[0] == CTL_VFS && mib[1] == VFS_GENERIC &&
796 		    mib[2] == VFS_BCACHESTAT)
797 			return (0);
798 	}
799 
800 	if ((p->p_p->ps_pledge & (PLEDGE_ROUTE | PLEDGE_INET | PLEDGE_DNS))) {
801 		if (miblen == 6 &&		/* getifaddrs() */
802 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
803 		    mib[2] == 0 &&
804 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
805 		    mib[4] == NET_RT_IFLIST)
806 			return (0);
807 	}
808 
809 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
810 		if (miblen == 2 &&		/* kern.rawpartition */
811 		    mib[0] == CTL_KERN &&
812 		    mib[1] == KERN_RAWPARTITION)
813 			return (0);
814 		if (miblen == 2 &&		/* kern.maxpartitions */
815 		    mib[0] == CTL_KERN &&
816 		    mib[1] == KERN_MAXPARTITIONS)
817 			return (0);
818 #ifdef CPU_CHR2BLK
819 		if (miblen == 3 &&		/* machdep.chr2blk */
820 		    mib[0] == CTL_MACHDEP &&
821 		    mib[1] == CPU_CHR2BLK)
822 			return (0);
823 #endif /* CPU_CHR2BLK */
824 	}
825 
826 	if (miblen >= 3 &&			/* ntpd(8) to read sensors */
827 	    mib[0] == CTL_HW && mib[1] == HW_SENSORS)
828 		return (0);
829 
830 	if (miblen == 2 &&		/* getdomainname() */
831 	    mib[0] == CTL_KERN && mib[1] == KERN_DOMAINNAME)
832 		return (0);
833 	if (miblen == 2 &&		/* gethostname() */
834 	    mib[0] == CTL_KERN && mib[1] == KERN_HOSTNAME)
835 		return (0);
836 	if (miblen == 6 &&		/* if_nameindex() */
837 	    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
838 	    mib[2] == 0 && mib[3] == 0 && mib[4] == NET_RT_IFNAMES)
839 		return (0);
840 	if (miblen == 2 &&		/* uname() */
841 	    mib[0] == CTL_KERN && mib[1] == KERN_OSTYPE)
842 		return (0);
843 	if (miblen == 2 &&		/* uname() */
844 	    mib[0] == CTL_KERN && mib[1] == KERN_OSRELEASE)
845 		return (0);
846 	if (miblen == 2 &&		/* uname() */
847 	    mib[0] == CTL_KERN && mib[1] == KERN_OSVERSION)
848 		return (0);
849 	if (miblen == 2 &&		/* uname() */
850 	    mib[0] == CTL_KERN && mib[1] == KERN_VERSION)
851 		return (0);
852 	if (miblen == 2 &&		/* kern.clockrate */
853 	    mib[0] == CTL_KERN && mib[1] == KERN_CLOCKRATE)
854 		return (0);
855 	if (miblen == 2 &&		/* kern.argmax */
856 	    mib[0] == CTL_KERN && mib[1] == KERN_ARGMAX)
857 		return (0);
858 	if (miblen == 2 &&		/* kern.ngroups */
859 	    mib[0] == CTL_KERN && mib[1] == KERN_NGROUPS)
860 		return (0);
861 	if (miblen == 2 &&		/* kern.sysvshm */
862 	    mib[0] == CTL_KERN && mib[1] == KERN_SYSVSHM)
863 		return (0);
864 	if (miblen == 2 &&		/* kern.posix1version */
865 	    mib[0] == CTL_KERN && mib[1] == KERN_POSIX1)
866 		return (0);
867 	if (miblen == 2 &&		/* uname() */
868 	    mib[0] == CTL_HW && mib[1] == HW_MACHINE)
869 		return (0);
870 	if (miblen == 2 &&		/* getpagesize() */
871 	    mib[0] == CTL_HW && mib[1] == HW_PAGESIZE)
872 		return (0);
873 	if (miblen == 2 &&		/* setproctitle() */
874 	    mib[0] == CTL_VM && mib[1] == VM_PSSTRINGS)
875 		return (0);
876 	if (miblen == 2 &&		/* hw.ncpu */
877 	    mib[0] == CTL_HW && mib[1] == HW_NCPU)
878 		return (0);
879 	if (miblen == 2 &&		/* vm.loadavg / getloadavg(3) */
880 	    mib[0] == CTL_VM && mib[1] == VM_LOADAVG)
881 		return (0);
882 
883 	snprintf(buf, sizeof(buf), "%s(%d): sysctl %d:",
884 	    p->p_p->ps_comm, p->p_p->ps_pid, miblen);
885 	for (i = 0; i < miblen; i++) {
886 		char *p = buf + strlen(buf);
887 		snprintf(p, sizeof(buf) - (p - buf), " %d", mib[i]);
888 	}
889 	log(LOG_ERR, "%s\n", buf);
890 
891 	return pledge_fail(p, EINVAL, 0);
892 }
893 
894 int
895 pledge_chown(struct proc *p, uid_t uid, gid_t gid)
896 {
897 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
898 		return (0);
899 
900 	if (p->p_p->ps_pledge & PLEDGE_CHOWNUID)
901 		return (0);
902 
903 	if (uid != -1 && uid != p->p_ucred->cr_uid)
904 		return (EPERM);
905 	if (gid != -1 && !groupmember(gid, p->p_ucred))
906 		return (EPERM);
907 	return (0);
908 }
909 
910 int
911 pledge_adjtime(struct proc *p, const void *v)
912 {
913 	const struct timeval *delta = v;
914 
915 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
916 		return (0);
917 
918 	if ((p->p_p->ps_pledge & PLEDGE_SETTIME))
919 		return (0);
920 	if (delta)
921 		return (EPERM);
922 	return (0);
923 }
924 
925 int
926 pledge_sendit(struct proc *p, const void *to)
927 {
928 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
929 		return (0);
930 
931 	if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE)))
932 		return (0);		/* may use address */
933 	if (to == NULL)
934 		return (0);		/* behaves just like write */
935 	return pledge_fail(p, EPERM, PLEDGE_INET);
936 }
937 
938 int
939 pledge_ioctl(struct proc *p, long com, struct file *fp)
940 {
941 	struct vnode *vp = NULL;
942 	int error = EPERM;
943 
944 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
945 		return (0);
946 
947 	/*
948 	 * The ioctl's which are always allowed.
949 	 */
950 	switch (com) {
951 	case FIONREAD:
952 	case FIONBIO:
953 	case FIOCLEX:
954 	case FIONCLEX:
955 		return (0);
956 	}
957 
958 	/* fp != NULL was already checked */
959 	if (fp->f_type == DTYPE_VNODE) {
960 		vp = fp->f_data;
961 		if (vp->v_type == VBAD)
962 			return (ENOTTY);
963 	}
964 
965 	if ((p->p_p->ps_pledge & PLEDGE_INET)) {
966 		switch (com) {
967 		case SIOCATMARK:
968 		case SIOCGIFGROUP:
969 			if (fp->f_type == DTYPE_SOCKET)
970 				return (0);
971 			break;
972 		}
973 	}
974 
975 #if NBPFILTER > 0
976 	if ((p->p_p->ps_pledge & PLEDGE_BPF)) {
977 		switch (com) {
978 		case BIOCGSTATS:	/* bpf: tcpdump privsep on ^C */
979 			if (fp->f_type == DTYPE_VNODE &&
980 			    fp->f_ops->fo_ioctl == vn_ioctl &&
981 			    vp->v_type == VCHR &&
982 			    cdevsw[major(vp->v_rdev)].d_open == bpfopen)
983 				return (0);
984 			break;
985 		}
986 	}
987 #endif /* NBPFILTER > 0 */
988 
989 	if ((p->p_p->ps_pledge & PLEDGE_TAPE)) {
990 		switch (com) {
991 		case MTIOCGET:
992 		case MTIOCTOP:
993 			/* for pax(1) and such, checking tapes... */
994 			if (fp->f_type == DTYPE_VNODE &&
995 			    vp->v_type == VCHR) {
996 				if (vp->v_flag & VISTTY)
997 					return (ENOTTY);
998 				else
999 					return (0);
1000 			}
1001 			break;
1002 		}
1003 	}
1004 
1005 #if NDRM > 0
1006 	if ((p->p_p->ps_pledge & PLEDGE_DRM)) {
1007 		if ((fp->f_type == DTYPE_VNODE) &&
1008 		    (vp->v_type == VCHR) &&
1009 		    (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
1010 			error = pledge_ioctl_drm(p, com, vp->v_rdev);
1011 			if (error == 0)
1012 				return 0;
1013 		}
1014 	}
1015 #endif /* NDRM > 0 */
1016 
1017 #if NAUDIO > 0
1018 	if ((p->p_p->ps_pledge & PLEDGE_AUDIO)) {
1019 		switch (com) {
1020 		case AUDIO_GETPOS:
1021 		case AUDIO_GETPAR:
1022 		case AUDIO_SETPAR:
1023 		case AUDIO_START:
1024 		case AUDIO_STOP:
1025 			if (fp->f_type == DTYPE_VNODE &&
1026 			    vp->v_type == VCHR &&
1027 			    cdevsw[major(vp->v_rdev)].d_open == audioopen)
1028 				return (0);
1029 		}
1030 	}
1031 #endif /* NAUDIO > 0 */
1032 
1033 	if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
1034 		switch (com) {
1035 		case DIOCGDINFO:
1036 		case DIOCGPDINFO:
1037 		case DIOCRLDINFO:
1038 		case DIOCWDINFO:
1039 		case BIOCDISK:
1040 		case BIOCINQ:
1041 		case BIOCINSTALLBOOT:
1042 		case BIOCVOL:
1043 			if (fp->f_type == DTYPE_VNODE &&
1044 			    ((vp->v_type == VCHR &&
1045 			    cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
1046 			    (vp->v_type == VBLK &&
1047 			    bdevsw[major(vp->v_rdev)].d_type == D_DISK)))
1048 				return (0);
1049 			break;
1050 		case DIOCMAP:
1051 			if (fp->f_type == DTYPE_VNODE &&
1052 			    vp->v_type == VCHR &&
1053 			    cdevsw[major(vp->v_rdev)].d_ioctl == diskmapioctl)
1054 				return (0);
1055 			break;
1056 		}
1057 	}
1058 
1059 #if NPF > 0
1060 	if ((p->p_p->ps_pledge & PLEDGE_PF)) {
1061 		switch (com) {
1062 		case DIOCADDRULE:
1063 		case DIOCGETSTATUS:
1064 		case DIOCNATLOOK:
1065 		case DIOCRADDTABLES:
1066 		case DIOCRCLRADDRS:
1067 		case DIOCRCLRTABLES:
1068 		case DIOCRCLRTSTATS:
1069 		case DIOCRGETTSTATS:
1070 		case DIOCRSETADDRS:
1071 		case DIOCXBEGIN:
1072 		case DIOCXCOMMIT:
1073 		case DIOCKILLSRCNODES:
1074 			if ((fp->f_type == DTYPE_VNODE) &&
1075 			    (vp->v_type == VCHR) &&
1076 			    (cdevsw[major(vp->v_rdev)].d_open == pfopen))
1077 				return (0);
1078 			break;
1079 		}
1080 	}
1081 #endif
1082 
1083 	if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
1084 		switch (com) {
1085 #if NPTY > 0
1086 		case PTMGET:
1087 			if ((p->p_p->ps_pledge & PLEDGE_RPATH) == 0)
1088 				break;
1089 			if ((p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
1090 				break;
1091 			if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
1092 				break;
1093 			if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
1094 				break;
1095 			return (0);
1096 #endif /* NPTY > 0 */
1097 		case TIOCSPGRP:
1098 			if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
1099 				break;
1100 			/* FALLTHROUGH */
1101 		case TIOCFLUSH:		/* getty, telnet */
1102 		case TIOCSTART:		/* emacs, etc */
1103 		case TIOCGPGRP:
1104 		case TIOCGETA:
1105 		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
1106 		case TIOCSTAT:		/* csh */
1107 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1108 				return (0);
1109 			return (ENOTTY);
1110 		case TIOCSWINSZ:
1111 		case TIOCEXT:		/* mail, libedit .. */
1112 		case TIOCCBRK:		/* cu */
1113 		case TIOCSBRK:		/* cu */
1114 		case TIOCCDTR:		/* cu */
1115 		case TIOCSDTR:		/* cu */
1116 		case TIOCEXCL:		/* cu */
1117 		case TIOCSETA:		/* cu, ... */
1118 		case TIOCSETAW:		/* cu, ... */
1119 		case TIOCSETAF:		/* tcsetattr TCSAFLUSH, script */
1120 		case TIOCSCTTY:		/* forkpty(3), login_tty(3), ... */
1121 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1122 				return (0);
1123 			break;
1124 		}
1125 	}
1126 
1127 	if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
1128 		switch (com) {
1129 		case SIOCGIFADDR:
1130 		case SIOCGIFAFLAG_IN6:
1131 		case SIOCGIFALIFETIME_IN6:
1132 		case SIOCGIFDESCR:
1133 		case SIOCGIFFLAGS:
1134 		case SIOCGIFMETRIC:
1135 		case SIOCGIFGMEMB:
1136 		case SIOCGIFRDOMAIN:
1137 		case SIOCGIFDSTADDR_IN6:
1138 		case SIOCGIFNETMASK_IN6:
1139 		case SIOCGIFXFLAGS:
1140 		case SIOCGNBRINFO_IN6:
1141 		case SIOCGIFINFO_IN6:
1142 		case SIOCGIFMEDIA:
1143 			if (fp->f_type == DTYPE_SOCKET)
1144 				return (0);
1145 			break;
1146 		}
1147 	}
1148 
1149 #if NVMM > 0
1150 	if ((p->p_p->ps_pledge & PLEDGE_VMM)) {
1151 		if ((fp->f_type == DTYPE_VNODE) &&
1152 		    (vp->v_type == VCHR) &&
1153 		    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
1154 			error = pledge_ioctl_vmm(p, com);
1155 			if (error == 0)
1156 				return 0;
1157 		}
1158 	}
1159 #endif
1160 
1161 	return pledge_fail(p, error, PLEDGE_TTY);
1162 }
1163 
1164 int
1165 pledge_sockopt(struct proc *p, int set, int level, int optname)
1166 {
1167 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1168 		return (0);
1169 
1170 	/* Always allow these, which are too common to reject */
1171 	switch (level) {
1172 	case SOL_SOCKET:
1173 		switch (optname) {
1174 		case SO_RCVBUF:
1175 		case SO_ERROR:
1176 			return 0;
1177 		}
1178 		break;
1179 	}
1180 
1181 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS|PLEDGE_YPACTIVE)) == 0)
1182 		return pledge_fail(p, EPERM, PLEDGE_INET);
1183 	/* In use by some service libraries */
1184 	switch (level) {
1185 	case SOL_SOCKET:
1186 		switch (optname) {
1187 		case SO_TIMESTAMP:
1188 			return 0;
1189 		}
1190 		break;
1191 	}
1192 
1193 	/* DNS resolver may do these requests */
1194 	if ((p->p_p->ps_pledge & PLEDGE_DNS)) {
1195 		switch (level) {
1196 		case IPPROTO_IPV6:
1197 			switch (optname) {
1198 			case IPV6_RECVPKTINFO:
1199 			case IPV6_USE_MIN_MTU:
1200 				return (0);
1201 			}
1202 		}
1203 	}
1204 
1205 	/* YP may do these requests */
1206 	if (p->p_p->ps_pledge & PLEDGE_YPACTIVE) {
1207 		switch (level) {
1208 		case IPPROTO_IP:
1209 			switch (optname) {
1210 			case IP_PORTRANGE:
1211 				return (0);
1212 			}
1213 			break;
1214 
1215 		case IPPROTO_IPV6:
1216 			switch (optname) {
1217 			case IPV6_PORTRANGE:
1218 				return (0);
1219 			}
1220 			break;
1221 		}
1222 	}
1223 
1224 	if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
1225 		return pledge_fail(p, EPERM, PLEDGE_INET);
1226 	switch (level) {
1227 	case SOL_SOCKET:
1228 		switch (optname) {
1229 		case SO_RTABLE:
1230 			return pledge_fail(p, EINVAL, PLEDGE_INET);
1231 		}
1232 		return (0);
1233 	}
1234 
1235 	if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
1236 		return pledge_fail(p, EPERM, PLEDGE_INET);
1237 	switch (level) {
1238 	case IPPROTO_TCP:
1239 		switch (optname) {
1240 		case TCP_NODELAY:
1241 		case TCP_MD5SIG:
1242 		case TCP_SACK_ENABLE:
1243 		case TCP_MAXSEG:
1244 		case TCP_NOPUSH:
1245 			return (0);
1246 		}
1247 		break;
1248 	case IPPROTO_IP:
1249 		switch (optname) {
1250 		case IP_OPTIONS:
1251 			if (!set)
1252 				return (0);
1253 			break;
1254 		case IP_TOS:
1255 		case IP_TTL:
1256 		case IP_MINTTL:
1257 		case IP_IPDEFTTL:
1258 		case IP_PORTRANGE:
1259 		case IP_RECVDSTADDR:
1260 		case IP_RECVDSTPORT:
1261 			return (0);
1262 		case IP_MULTICAST_IF:
1263 		case IP_MULTICAST_TTL:
1264 		case IP_MULTICAST_LOOP:
1265 		case IP_ADD_MEMBERSHIP:
1266 		case IP_DROP_MEMBERSHIP:
1267 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1268 				return (0);
1269 			break;
1270 		}
1271 		break;
1272 	case IPPROTO_ICMP:
1273 		break;
1274 	case IPPROTO_IPV6:
1275 		switch (optname) {
1276 		case IPV6_TCLASS:
1277 		case IPV6_UNICAST_HOPS:
1278 		case IPV6_MINHOPCOUNT:
1279 		case IPV6_RECVHOPLIMIT:
1280 		case IPV6_PORTRANGE:
1281 		case IPV6_RECVPKTINFO:
1282 		case IPV6_RECVDSTPORT:
1283 #ifdef notyet
1284 		case IPV6_V6ONLY:
1285 #endif
1286 			return (0);
1287 		case IPV6_MULTICAST_IF:
1288 		case IPV6_MULTICAST_HOPS:
1289 		case IPV6_MULTICAST_LOOP:
1290 		case IPV6_JOIN_GROUP:
1291 		case IPV6_LEAVE_GROUP:
1292 			if (p->p_p->ps_pledge & PLEDGE_MCAST)
1293 				return (0);
1294 			break;
1295 		}
1296 		break;
1297 	case IPPROTO_ICMPV6:
1298 		break;
1299 	}
1300 	return pledge_fail(p, EPERM, PLEDGE_INET);
1301 }
1302 
1303 int
1304 pledge_socket(struct proc *p, int domain, int state)
1305 {
1306 	if (! ISSET(p->p_p->ps_flags, PS_PLEDGE))
1307 		return 0;
1308 
1309 	if (ISSET(state, SS_DNS)) {
1310 		if (ISSET(p->p_p->ps_pledge, PLEDGE_DNS))
1311 			return 0;
1312 		return pledge_fail(p, EPERM, PLEDGE_DNS);
1313 	}
1314 
1315 	switch (domain) {
1316 	case -1:		/* accept on any domain */
1317 		return (0);
1318 	case AF_INET:
1319 	case AF_INET6:
1320 		if (ISSET(p->p_p->ps_pledge, PLEDGE_INET) ||
1321 		    ISSET(p->p_p->ps_pledge, PLEDGE_YPACTIVE))
1322 			return 0;
1323 		return pledge_fail(p, EPERM, PLEDGE_INET);
1324 
1325 	case AF_UNIX:
1326 		if (ISSET(p->p_p->ps_pledge, PLEDGE_UNIX))
1327 			return 0;
1328 		return pledge_fail(p, EPERM, PLEDGE_UNIX);
1329 	}
1330 
1331 	return pledge_fail(p, EINVAL, PLEDGE_INET);
1332 }
1333 
1334 int
1335 pledge_flock(struct proc *p)
1336 {
1337 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1338 		return (0);
1339 
1340 	if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
1341 		return (0);
1342 	return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
1343 }
1344 
1345 int
1346 pledge_swapctl(struct proc *p)
1347 {
1348 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1349 		return (0);
1350 	return (EPERM);
1351 }
1352 
1353 /* bsearch over pledgereq. return flags value if found, 0 else */
1354 uint64_t
1355 pledgereq_flags(const char *req_name)
1356 {
1357 	int base = 0, cmp, i, lim;
1358 
1359 	for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
1360 		i = base + (lim >> 1);
1361 		cmp = strcmp(req_name, pledgereq[i].name);
1362 		if (cmp == 0)
1363 			return (pledgereq[i].flags);
1364 		if (cmp > 0) { /* not found before, move right */
1365 			base = i + 1;
1366 			lim--;
1367 		} /* else move left */
1368 	}
1369 	return (0);
1370 }
1371 
1372 int
1373 pledge_fcntl(struct proc *p, int cmd)
1374 {
1375 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1376 		return (0);
1377 	if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0 && cmd == F_SETOWN)
1378 		return pledge_fail(p, EPERM, PLEDGE_PROC);
1379 	return (0);
1380 }
1381 
1382 int
1383 pledge_kill(struct proc *p, pid_t pid)
1384 {
1385 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1386 		return 0;
1387 	if (p->p_p->ps_pledge & PLEDGE_PROC)
1388 		return 0;
1389 	if (pid == 0 || pid == p->p_p->ps_pid)
1390 		return 0;
1391 	return pledge_fail(p, EPERM, PLEDGE_PROC);
1392 }
1393 
1394 int
1395 pledge_protexec(struct proc *p, int prot)
1396 {
1397 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1398 		return 0;
1399 	if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
1400 		return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
1401 	return 0;
1402 }
1403 
1404 int
1405 canonpath(const char *input, char *buf, size_t bufsize)
1406 {
1407 	const char *p;
1408 	char *q;
1409 
1410 	/* can't canon relative paths, don't bother */
1411 	if (input[0] != '/') {
1412 		if (strlcpy(buf, input, bufsize) >= bufsize)
1413 			return ENAMETOOLONG;
1414 		return 0;
1415 	}
1416 
1417 	p = input;
1418 	q = buf;
1419 	while (*p && (q - buf < bufsize)) {
1420 		if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
1421 			p += 1;
1422 
1423 		} else if (p[0] == '/' && p[1] == '.' &&
1424 		    (p[2] == '/' || p[2] == '\0')) {
1425 			p += 2;
1426 
1427 		} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
1428 		    (p[3] == '/' || p[3] == '\0')) {
1429 			p += 3;
1430 			if (q != buf)	/* "/../" at start of buf */
1431 				while (*--q != '/')
1432 					continue;
1433 
1434 		} else {
1435 			*q++ = *p++;
1436 		}
1437 	}
1438 	if ((*p == '\0') && (q - buf < bufsize)) {
1439 		*q = 0;
1440 		return 0;
1441 	} else
1442 		return ENAMETOOLONG;
1443 }
1444