xref: /openbsd-src/sys/kern/kern_pledge.c (revision a704a667956955560432e63e1e235a2fd6664315)
1*a704a667Sjsg /*	$OpenBSD: kern_pledge.c,v 1.321 2024/10/06 23:39:24 jsg Exp $	*/
2350b464cSderaadt 
3350b464cSderaadt /*
4350b464cSderaadt  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5350b464cSderaadt  * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
6350b464cSderaadt  *
7350b464cSderaadt  * Permission to use, copy, modify, and distribute this software for any
8350b464cSderaadt  * purpose with or without fee is hereby granted, provided that the above
9350b464cSderaadt  * copyright notice and this permission notice appear in all copies.
10350b464cSderaadt  *
11350b464cSderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12350b464cSderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13350b464cSderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14350b464cSderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15350b464cSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16350b464cSderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17350b464cSderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18350b464cSderaadt  */
19350b464cSderaadt 
20350b464cSderaadt #include <sys/param.h>
21350b464cSderaadt #include <sys/mount.h>
22350b464cSderaadt #include <sys/proc.h>
23b20cffafSjca #include <sys/mutex.h>
24350b464cSderaadt #include <sys/fcntl.h>
25350b464cSderaadt #include <sys/file.h>
26345a92b4Ssemarie #include <sys/namei.h>
27e29e7853Sderaadt #include <sys/socketvar.h>
28350b464cSderaadt #include <sys/vnode.h>
29a48a073bSsemarie #include <sys/mman.h>
30350b464cSderaadt #include <sys/sysctl.h>
311b2e2cb7Sderaadt #include <sys/syslog.h>
32350b464cSderaadt #include <sys/ktrace.h>
33696e0573Sbluhm #include <sys/acct.h>
3409de7c43Sjca #include <sys/swap.h>
35350b464cSderaadt 
36350b464cSderaadt #include <sys/ioctl.h>
37350b464cSderaadt #include <sys/termios.h>
387064a666Snicm #include <sys/tty.h>
396556479dSderaadt #include <sys/device.h>
402579b71cSderaadt #include <sys/disklabel.h>
412579b71cSderaadt #include <sys/dkio.h>
42350b464cSderaadt #include <sys/mtio.h>
43e48418c3Sratchov #include <sys/audioio.h>
443ec81e34Slandry #include <sys/videoio.h>
45350b464cSderaadt #include <net/bpf.h>
46350b464cSderaadt #include <net/route.h>
47350b464cSderaadt #include <net/if.h>
4870325c08Sderaadt #include <net/if_var.h>
49350b464cSderaadt #include <netinet/in.h>
5070325c08Sderaadt #include <netinet6/in6_var.h>
5170325c08Sderaadt #include <netinet6/nd6.h>
52350b464cSderaadt #include <netinet/tcp.h>
532119862cSbenno #include <net/pfvar.h>
54350b464cSderaadt 
557064a666Snicm #include <sys/conf.h>
567064a666Snicm #include <sys/specdev.h>
57350b464cSderaadt #include <sys/signal.h>
58350b464cSderaadt #include <sys/signalvar.h>
59350b464cSderaadt #include <sys/syscall.h>
60350b464cSderaadt #include <sys/syscallargs.h>
61350b464cSderaadt #include <sys/systm.h>
622c12dca0Sderaadt 
632c12dca0Sderaadt #include <dev/biovar.h>
642c12dca0Sderaadt 
6591bc69b8Sderaadt #define PLEDGENAMES
66350b464cSderaadt #include <sys/pledge.h>
67350b464cSderaadt 
682f3f751fStb #include "audio.h"
6998d0bc2dSderaadt #include "bpfilter.h"
702009fb49Stedu #include "pf.h"
712b0927afSderaadt #include "video.h"
7239b22fbbSderaadt #include "pty.h"
73c975014eSderaadt 
7481b71fafSpd #if defined(__amd64__)
758bc79b23Sreyk #include "vmm.h"
768eadc5ecSjsg #include "psp.h"
77b0c499e2Sjsg #include <machine/conf.h>
788bc79b23Sreyk #endif
798bc79b23Sreyk 
80f6b590bcSkettenis #include "drm.h"
81f6b590bcSkettenis 
826aabbe27Ssemarie uint64_t pledgereq_flags(const char *req);
834ea7ed56Sderaadt int	 parsepledges(struct proc *p, const char *kname,
844ea7ed56Sderaadt 	    const char *promises, u_int64_t *fp);
85350b464cSderaadt int	 canonpath(const char *input, char *buf, size_t bufsize);
868b23add8Sbeck void	 unveil_destroy(struct process *ps);
87350b464cSderaadt 
88f9f6a434Sderaadt /*
89f9f6a434Sderaadt  * Ordered in blocks starting with least risky and most required.
90f9f6a434Sderaadt  */
91fe2523afSderaadt const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = {
92f9f6a434Sderaadt 	/*
93f9f6a434Sderaadt 	 * Minimum required
94f9f6a434Sderaadt 	 */
9505fcf4a9Ssemarie 	[SYS_exit] = PLEDGE_ALWAYS,
9605fcf4a9Ssemarie 	[SYS_kbind] = PLEDGE_ALWAYS,
9705fcf4a9Ssemarie 	[SYS___get_tcb] = PLEDGE_ALWAYS,
984648449fSderaadt 	[SYS___set_tcb] = PLEDGE_ALWAYS,
9905fcf4a9Ssemarie 	[SYS_pledge] = PLEDGE_ALWAYS,
10005fcf4a9Ssemarie 	[SYS_sendsyslog] = PLEDGE_ALWAYS,	/* stack protector reporting */
10160d49506Sguenther 	[SYS_thrkill] = PLEDGE_ALWAYS,		/* raise, abort, stack pro */
1028fd02d5bSderaadt 	[SYS_utrace] = PLEDGE_ALWAYS,		/* ltrace(1) from ld.so */
103b87515deSderaadt 	[SYS_pinsyscalls] = PLEDGE_ALWAYS,
104350b464cSderaadt 
105f9f6a434Sderaadt 	/* "getting" information about self is considered safe */
10691bc69b8Sderaadt 	[SYS_getuid] = PLEDGE_STDIO,
10791bc69b8Sderaadt 	[SYS_geteuid] = PLEDGE_STDIO,
10891bc69b8Sderaadt 	[SYS_getresuid] = PLEDGE_STDIO,
10991bc69b8Sderaadt 	[SYS_getgid] = PLEDGE_STDIO,
11091bc69b8Sderaadt 	[SYS_getegid] = PLEDGE_STDIO,
11191bc69b8Sderaadt 	[SYS_getresgid] = PLEDGE_STDIO,
11291bc69b8Sderaadt 	[SYS_getgroups] = PLEDGE_STDIO,
11365648e5fSguenther 	[SYS_getlogin_r] = PLEDGE_STDIO,
11491bc69b8Sderaadt 	[SYS_getpgrp] = PLEDGE_STDIO,
11591bc69b8Sderaadt 	[SYS_getpgid] = PLEDGE_STDIO,
11691bc69b8Sderaadt 	[SYS_getppid] = PLEDGE_STDIO,
11791bc69b8Sderaadt 	[SYS_getsid] = PLEDGE_STDIO,
11891bc69b8Sderaadt 	[SYS_getthrid] = PLEDGE_STDIO,
11991bc69b8Sderaadt 	[SYS_getrlimit] = PLEDGE_STDIO,
12011430c74Sderaadt 	[SYS_getrtable] = PLEDGE_STDIO,
12191bc69b8Sderaadt 	[SYS_gettimeofday] = PLEDGE_STDIO,
12291bc69b8Sderaadt 	[SYS_getdtablecount] = PLEDGE_STDIO,
12391bc69b8Sderaadt 	[SYS_getrusage] = PLEDGE_STDIO,
12491bc69b8Sderaadt 	[SYS_issetugid] = PLEDGE_STDIO,
12591bc69b8Sderaadt 	[SYS_clock_getres] = PLEDGE_STDIO,
12691bc69b8Sderaadt 	[SYS_clock_gettime] = PLEDGE_STDIO,
12791bc69b8Sderaadt 	[SYS_getpid] = PLEDGE_STDIO,
128f9f6a434Sderaadt 
129f9f6a434Sderaadt 	/*
130f9f6a434Sderaadt 	 * Almost exclusively read-only, Very narrow subset.
131f9f6a434Sderaadt 	 * Use of "route", "inet", "dns", "ps", or "vminfo"
132f9f6a434Sderaadt 	 * expands access.
133f9f6a434Sderaadt 	 */
134f9f6a434Sderaadt 	[SYS_sysctl] = PLEDGE_STDIO,
135f9f6a434Sderaadt 
136b7a7cb6aScheloha 	/* For moncontrol(3).  Only allowed to disable profiling. */
137b7a7cb6aScheloha 	[SYS_profil] = PLEDGE_STDIO,
138b7a7cb6aScheloha 
139f9f6a434Sderaadt 	/* Support for malloc(3) family of operations */
140f9f6a434Sderaadt 	[SYS_getentropy] = PLEDGE_STDIO,
141f9f6a434Sderaadt 	[SYS_madvise] = PLEDGE_STDIO,
142f9f6a434Sderaadt 	[SYS_minherit] = PLEDGE_STDIO,
143f9f6a434Sderaadt 	[SYS_mmap] = PLEDGE_STDIO,
144f9f6a434Sderaadt 	[SYS_mprotect] = PLEDGE_STDIO,
1458c7187e8Sderaadt 	[SYS_mimmutable] = PLEDGE_STDIO,
146f9f6a434Sderaadt 	[SYS_mquery] = PLEDGE_STDIO,
147f9f6a434Sderaadt 	[SYS_munmap] = PLEDGE_STDIO,
148f30b507aSderaadt 	[SYS_msync] = PLEDGE_STDIO,
149ec4f8960Ssthen 	[SYS_break] = PLEDGE_STDIO,
150f9f6a434Sderaadt 
15191bc69b8Sderaadt 	[SYS_umask] = PLEDGE_STDIO,
152350b464cSderaadt 
153f9f6a434Sderaadt 	/* read/write operations */
154f9f6a434Sderaadt 	[SYS_read] = PLEDGE_STDIO,
155f9f6a434Sderaadt 	[SYS_readv] = PLEDGE_STDIO,
156f9f6a434Sderaadt 	[SYS_pread] = PLEDGE_STDIO,
157f9f6a434Sderaadt 	[SYS_preadv] = PLEDGE_STDIO,
158f9f6a434Sderaadt 	[SYS_write] = PLEDGE_STDIO,
159f9f6a434Sderaadt 	[SYS_writev] = PLEDGE_STDIO,
160f9f6a434Sderaadt 	[SYS_pwrite] = PLEDGE_STDIO,
161f9f6a434Sderaadt 	[SYS_pwritev] = PLEDGE_STDIO,
162f9f6a434Sderaadt 	[SYS_recvmsg] = PLEDGE_STDIO,
163680e6520Smbuhl 	[SYS_recvmmsg] = PLEDGE_STDIO,
1645c5d7832Sderaadt 	[SYS_recvfrom] = PLEDGE_STDIO,
165f9f6a434Sderaadt 	[SYS_ftruncate] = PLEDGE_STDIO,
166f9f6a434Sderaadt 	[SYS_lseek] = PLEDGE_STDIO,
1673b2f8dedSderaadt 	[SYS_fpathconf] = PLEDGE_STDIO,
1687ba9c3ebSderaadt 
169f9f6a434Sderaadt 	/*
170f9f6a434Sderaadt 	 * Address selection required a network pledge ("inet",
171f9f6a434Sderaadt 	 * "unix", "dns".
172f9f6a434Sderaadt 	 */
1735c5d7832Sderaadt 	[SYS_sendto] = PLEDGE_STDIO,
174350b464cSderaadt 
175f9f6a434Sderaadt 	/*
176f9f6a434Sderaadt 	 * Address specification required a network pledge ("inet",
177f9f6a434Sderaadt 	 * "unix", "dns".  SCM_RIGHTS requires "sendfd" or "recvfd".
178f9f6a434Sderaadt 	 */
179f9f6a434Sderaadt 	[SYS_sendmsg] = PLEDGE_STDIO,
180680e6520Smbuhl 	[SYS_sendmmsg] = PLEDGE_STDIO,
181350b464cSderaadt 
182f9f6a434Sderaadt 	/* Common signal operations */
18391bc69b8Sderaadt 	[SYS_nanosleep] = PLEDGE_STDIO,
18491bc69b8Sderaadt 	[SYS_sigaltstack] = PLEDGE_STDIO,
18591bc69b8Sderaadt 	[SYS_sigprocmask] = PLEDGE_STDIO,
18691bc69b8Sderaadt 	[SYS_sigsuspend] = PLEDGE_STDIO,
18791bc69b8Sderaadt 	[SYS_sigaction] = PLEDGE_STDIO,
18891bc69b8Sderaadt 	[SYS_sigreturn] = PLEDGE_STDIO,
18991bc69b8Sderaadt 	[SYS_sigpending] = PLEDGE_STDIO,
19091bc69b8Sderaadt 	[SYS_getitimer] = PLEDGE_STDIO,
19191bc69b8Sderaadt 	[SYS_setitimer] = PLEDGE_STDIO,
192350b464cSderaadt 
193f9f6a434Sderaadt 	/*
194f9f6a434Sderaadt 	 * To support event driven programming.
195f9f6a434Sderaadt 	 */
19691bc69b8Sderaadt 	[SYS_poll] = PLEDGE_STDIO,
197986abd2aSderaadt 	[SYS_ppoll] = PLEDGE_STDIO,
19891bc69b8Sderaadt 	[SYS_kevent] = PLEDGE_STDIO,
19991bc69b8Sderaadt 	[SYS_kqueue] = PLEDGE_STDIO,
200eaac6367Svisa 	[SYS_kqueue1] = PLEDGE_STDIO,
20191bc69b8Sderaadt 	[SYS_select] = PLEDGE_STDIO,
2025d955a29Sderaadt 	[SYS_pselect] = PLEDGE_STDIO,
203350b464cSderaadt 
204f9f6a434Sderaadt 	[SYS_fstat] = PLEDGE_STDIO,
205f9f6a434Sderaadt 	[SYS_fsync] = PLEDGE_STDIO,
206f9f6a434Sderaadt 
207f9f6a434Sderaadt 	[SYS_setsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
208f9f6a434Sderaadt 	[SYS_getsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
209f9f6a434Sderaadt 
210f9f6a434Sderaadt 	/* F_SETOWN requires PLEDGE_PROC */
211f9f6a434Sderaadt 	[SYS_fcntl] = PLEDGE_STDIO,
212f9f6a434Sderaadt 
21391bc69b8Sderaadt 	[SYS_close] = PLEDGE_STDIO,
21491bc69b8Sderaadt 	[SYS_dup] = PLEDGE_STDIO,
21591bc69b8Sderaadt 	[SYS_dup2] = PLEDGE_STDIO,
21691bc69b8Sderaadt 	[SYS_dup3] = PLEDGE_STDIO,
21791bc69b8Sderaadt 	[SYS_closefrom] = PLEDGE_STDIO,
21891bc69b8Sderaadt 	[SYS_shutdown] = PLEDGE_STDIO,
219f9f6a434Sderaadt 	[SYS_fchdir] = PLEDGE_STDIO,	/* XXX consider tightening */
220350b464cSderaadt 
22191bc69b8Sderaadt 	[SYS_pipe] = PLEDGE_STDIO,
22291bc69b8Sderaadt 	[SYS_pipe2] = PLEDGE_STDIO,
22391bc69b8Sderaadt 	[SYS_socketpair] = PLEDGE_STDIO,
224350b464cSderaadt 
225f9f6a434Sderaadt 	[SYS_wait4] = PLEDGE_STDIO,
226144b3efaSguenther 	[SYS_waitid] = PLEDGE_STDIO,
227f9f6a434Sderaadt 
228f9f6a434Sderaadt 	/*
229f9f6a434Sderaadt 	 * Can kill self with "stdio".  Killing another pid
230f9f6a434Sderaadt 	 * requires "proc"
231f9f6a434Sderaadt 	 */
232f9f6a434Sderaadt 	[SYS_kill] = PLEDGE_STDIO,
233f9f6a434Sderaadt 
234f9f6a434Sderaadt 	/*
235f9f6a434Sderaadt 	 * FIONREAD/FIONBIO for "stdio"
236b90d0acdSderaadt 	 * Other ioctl are selectively allowed based upon other pledges.
237f9f6a434Sderaadt 	 */
238f9f6a434Sderaadt 	[SYS_ioctl] = PLEDGE_STDIO,
239f9f6a434Sderaadt 
240f9f6a434Sderaadt 	/*
241f9f6a434Sderaadt 	 * Path access/creation calls encounter many extensive
242ee6e8dd4Srob 	 * checks done during pledge_namei()
243f9f6a434Sderaadt 	 */
244f9f6a434Sderaadt 	[SYS_open] = PLEDGE_STDIO,
245f9f6a434Sderaadt 	[SYS_stat] = PLEDGE_STDIO,
246f9f6a434Sderaadt 	[SYS_access] = PLEDGE_STDIO,
247f9f6a434Sderaadt 	[SYS_readlink] = PLEDGE_STDIO,
248e025c5b7Sderaadt 	[SYS___realpath] = PLEDGE_STDIO,
249f9f6a434Sderaadt 
250f9f6a434Sderaadt 	[SYS_adjtime] = PLEDGE_STDIO,   /* setting requires "settime" */
251f9f6a434Sderaadt 	[SYS_adjfreq] = PLEDGE_SETTIME,
252f9f6a434Sderaadt 	[SYS_settimeofday] = PLEDGE_SETTIME,
253f9f6a434Sderaadt 
254f9f6a434Sderaadt 	/*
255f9f6a434Sderaadt 	 * Needed by threaded programs
256f9f6a434Sderaadt 	 * XXX should we have a new "threads"?
257f9f6a434Sderaadt 	 */
258f9f6a434Sderaadt 	[SYS___tfork] = PLEDGE_STDIO,
259f9f6a434Sderaadt 	[SYS_sched_yield] = PLEDGE_STDIO,
2606ebdaeeaSmpi 	[SYS_futex] = PLEDGE_STDIO,
261f9f6a434Sderaadt 	[SYS___thrsleep] = PLEDGE_STDIO,
262f9f6a434Sderaadt 	[SYS___thrwakeup] = PLEDGE_STDIO,
263f9f6a434Sderaadt 	[SYS___threxit] = PLEDGE_STDIO,
264f9f6a434Sderaadt 	[SYS___thrsigdivert] = PLEDGE_STDIO,
265cef5a146Sguenther 	[SYS_getthrname] = PLEDGE_STDIO,
266cef5a146Sguenther 	[SYS_setthrname] = PLEDGE_STDIO,
267350b464cSderaadt 
268350b464cSderaadt 	[SYS_fork] = PLEDGE_PROC,
269350b464cSderaadt 	[SYS_vfork] = PLEDGE_PROC,
270350b464cSderaadt 	[SYS_setpgid] = PLEDGE_PROC,
27143f44a87Sderaadt 	[SYS_setsid] = PLEDGE_PROC,
27292d83454Sderaadt 
27392d83454Sderaadt 	[SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
27492d83454Sderaadt 	[SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
27592d83454Sderaadt 
276df1d1c41Sderaadt 	[SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
277df1d1c41Sderaadt 
27892d83454Sderaadt 	[SYS_setuid] = PLEDGE_ID,
27992d83454Sderaadt 	[SYS_seteuid] = PLEDGE_ID,
28048549e65Sderaadt 	[SYS_setreuid] = PLEDGE_ID,
28192d83454Sderaadt 	[SYS_setresuid] = PLEDGE_ID,
28292d83454Sderaadt 	[SYS_setgid] = PLEDGE_ID,
28392d83454Sderaadt 	[SYS_setegid] = PLEDGE_ID,
28448549e65Sderaadt 	[SYS_setregid] = PLEDGE_ID,
28592d83454Sderaadt 	[SYS_setresgid] = PLEDGE_ID,
28692d83454Sderaadt 	[SYS_setgroups] = PLEDGE_ID,
28792d83454Sderaadt 	[SYS_setlogin] = PLEDGE_ID,
2887e1460e5Stedu 	[SYS_setrtable] = PLEDGE_ID,
289350b464cSderaadt 
2908b23add8Sbeck 	[SYS_unveil] = PLEDGE_UNVEIL,
2918b23add8Sbeck 
292350b464cSderaadt 	[SYS_execve] = PLEDGE_EXEC,
293350b464cSderaadt 
294350b464cSderaadt 	[SYS_chdir] = PLEDGE_RPATH,
295350b464cSderaadt 	[SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
296350b464cSderaadt 	[SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
297350b464cSderaadt 	[SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
298350b464cSderaadt 	[SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
299350b464cSderaadt 	[SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
3004e622d35Sderaadt 	[SYS_truncate] = PLEDGE_WPATH,
3015b93156dSderaadt 	[SYS_rename] = PLEDGE_RPATH | PLEDGE_CPATH,
302350b464cSderaadt 	[SYS_rmdir] = PLEDGE_CPATH,
303350b464cSderaadt 	[SYS_renameat] = PLEDGE_CPATH,
304350b464cSderaadt 	[SYS_link] = PLEDGE_CPATH,
305350b464cSderaadt 	[SYS_linkat] = PLEDGE_CPATH,
306350b464cSderaadt 	[SYS_symlink] = PLEDGE_CPATH,
307a919f51bSschwarze 	[SYS_symlinkat] = PLEDGE_CPATH,
308350b464cSderaadt 	[SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
309350b464cSderaadt 	[SYS_unlinkat] = PLEDGE_CPATH,
310350b464cSderaadt 	[SYS_mkdir] = PLEDGE_CPATH,
311350b464cSderaadt 	[SYS_mkdirat] = PLEDGE_CPATH,
312350b464cSderaadt 
3135a82ee67Sderaadt 	[SYS_mkfifo] = PLEDGE_DPATH,
314e044e6cdSflorian 	[SYS_mkfifoat] = PLEDGE_DPATH,
3155a82ee67Sderaadt 	[SYS_mknod] = PLEDGE_DPATH,
316e044e6cdSflorian 	[SYS_mknodat] = PLEDGE_DPATH,
3175a82ee67Sderaadt 
318859ed624Sderaadt 	[SYS_revoke] = PLEDGE_TTY,	/* also requires PLEDGE_RPATH */
319859ed624Sderaadt 
320350b464cSderaadt 	/*
321350b464cSderaadt 	 * Classify as RPATH|WPATH, because of path information leakage.
322350b464cSderaadt 	 * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
323350b464cSderaadt 	 */
324350b464cSderaadt 	[SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
325350b464cSderaadt 
326350b464cSderaadt 	/* Classify as RPATH, because these leak path information */
327f9f6a434Sderaadt 	[SYS_getdents] = PLEDGE_RPATH,
328350b464cSderaadt 	[SYS_getfsstat] = PLEDGE_RPATH,
329350b464cSderaadt 	[SYS_statfs] = PLEDGE_RPATH,
330350b464cSderaadt 	[SYS_fstatfs] = PLEDGE_RPATH,
331301808e4Sderaadt 	[SYS_pathconf] = PLEDGE_RPATH,
3325f31b145Sguenther 	[SYS_pathconfat] = PLEDGE_RPATH,
333350b464cSderaadt 
334350b464cSderaadt 	[SYS_utimes] = PLEDGE_FATTR,
335350b464cSderaadt 	[SYS_futimes] = PLEDGE_FATTR,
336350b464cSderaadt 	[SYS_utimensat] = PLEDGE_FATTR,
337350b464cSderaadt 	[SYS_futimens] = PLEDGE_FATTR,
338350b464cSderaadt 	[SYS_chmod] = PLEDGE_FATTR,
339350b464cSderaadt 	[SYS_fchmod] = PLEDGE_FATTR,
340350b464cSderaadt 	[SYS_fchmodat] = PLEDGE_FATTR,
341350b464cSderaadt 	[SYS_chflags] = PLEDGE_FATTR,
342350b464cSderaadt 	[SYS_chflagsat] = PLEDGE_FATTR,
3430b92220eSdoug 	[SYS_fchflags] = PLEDGE_FATTR,
3441d0044e1Ssemarie 
3451d0044e1Ssemarie 	[SYS_chown] = PLEDGE_CHOWN,
3461d0044e1Ssemarie 	[SYS_fchownat] = PLEDGE_CHOWN,
3471d0044e1Ssemarie 	[SYS_lchown] = PLEDGE_CHOWN,
3481d0044e1Ssemarie 	[SYS_fchown] = PLEDGE_CHOWN,
349350b464cSderaadt 
3505c5d7832Sderaadt 	[SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
3515c5d7832Sderaadt 	[SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
3525c5d7832Sderaadt 	[SYS_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
3535c5d7832Sderaadt 	[SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
354e29e7853Sderaadt 
355350b464cSderaadt 	[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
356350b464cSderaadt 	[SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
357350b464cSderaadt 	[SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
358350b464cSderaadt 	[SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
359350b464cSderaadt 
3605c5d7832Sderaadt 	[SYS_flock] = PLEDGE_FLOCK,
361dfa9d678Sderaadt 
3622ad204b6Sderaadt 	[SYS_ypconnect] = PLEDGE_GETPW,
3632ad204b6Sderaadt 
36409de7c43Sjca 	[SYS_swapctl] = PLEDGE_VMINFO,
365350b464cSderaadt };
366350b464cSderaadt 
367350b464cSderaadt static const struct {
368350b464cSderaadt 	char *name;
36948a91136Ssemarie 	uint64_t flags;
370350b464cSderaadt } pledgereq[] = {
3715a82ee67Sderaadt 	{ "audio",		PLEDGE_AUDIO },
372b90d0acdSderaadt 	{ "bpf",		PLEDGE_BPF },
3731d0044e1Ssemarie 	{ "chown",		PLEDGE_CHOWN | PLEDGE_CHOWNUID },
374737c0fa9Ssemarie 	{ "cpath",		PLEDGE_CPATH },
3752579b71cSderaadt 	{ "disklabel",		PLEDGE_DISKLABEL },
376737c0fa9Ssemarie 	{ "dns",		PLEDGE_DNS },
3775a82ee67Sderaadt 	{ "dpath",		PLEDGE_DPATH },
378f6b590bcSkettenis 	{ "drm",		PLEDGE_DRM },
3794ea7ed56Sderaadt 	{ "error",		PLEDGE_ERROR },
380737c0fa9Ssemarie 	{ "exec",		PLEDGE_EXEC },
3811d0044e1Ssemarie 	{ "fattr",		PLEDGE_FATTR | PLEDGE_CHOWN },
382737c0fa9Ssemarie 	{ "flock",		PLEDGE_FLOCK },
383737c0fa9Ssemarie 	{ "getpw",		PLEDGE_GETPW },
384737c0fa9Ssemarie 	{ "id",			PLEDGE_ID },
385737c0fa9Ssemarie 	{ "inet",		PLEDGE_INET },
386737c0fa9Ssemarie 	{ "mcast",		PLEDGE_MCAST },
3872119862cSbenno 	{ "pf",			PLEDGE_PF },
388737c0fa9Ssemarie 	{ "proc",		PLEDGE_PROC },
389737c0fa9Ssemarie 	{ "prot_exec",		PLEDGE_PROTEXEC },
390737c0fa9Ssemarie 	{ "ps",			PLEDGE_PS },
391737c0fa9Ssemarie 	{ "recvfd",		PLEDGE_RECVFD },
392737c0fa9Ssemarie 	{ "route",		PLEDGE_ROUTE },
393737c0fa9Ssemarie 	{ "rpath",		PLEDGE_RPATH },
394737c0fa9Ssemarie 	{ "sendfd",		PLEDGE_SENDFD },
395737c0fa9Ssemarie 	{ "settime",		PLEDGE_SETTIME },
39699e59e44Smikeb 	{ "stdio",		PLEDGE_STDIO },
397b90d0acdSderaadt 	{ "tape",		PLEDGE_TAPE },
398737c0fa9Ssemarie 	{ "tmppath",		PLEDGE_TMPPATH },
399737c0fa9Ssemarie 	{ "tty",		PLEDGE_TTY },
400737c0fa9Ssemarie 	{ "unix",		PLEDGE_UNIX },
4018b23add8Sbeck 	{ "unveil",		PLEDGE_UNVEIL },
4023ec81e34Slandry 	{ "video",		PLEDGE_VIDEO },
403737c0fa9Ssemarie 	{ "vminfo",		PLEDGE_VMINFO },
4048bc79b23Sreyk 	{ "vmm",		PLEDGE_VMM },
405737c0fa9Ssemarie 	{ "wpath",		PLEDGE_WPATH },
4068ba961a7Sflorian 	{ "wroute",		PLEDGE_WROUTE },
407350b464cSderaadt };
408350b464cSderaadt 
409350b464cSderaadt int
4104ea7ed56Sderaadt parsepledges(struct proc *p, const char *kname, const char *promises, u_int64_t *fp)
411350b464cSderaadt {
412350b464cSderaadt 	size_t rbuflen;
413350b464cSderaadt 	char *rbuf, *rp, *pn;
4144ea7ed56Sderaadt 	u_int64_t flags = 0, f;
4154ea7ed56Sderaadt 	int error;
416350b464cSderaadt 
417350b464cSderaadt 	rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
4189a3cf6bbSderaadt 	error = copyinstr(promises, rbuf, MAXPATHLEN, &rbuflen);
419350b464cSderaadt 	if (error) {
420350b464cSderaadt 		free(rbuf, M_TEMP, MAXPATHLEN);
421350b464cSderaadt 		return (error);
422350b464cSderaadt 	}
423350b464cSderaadt #ifdef KTRACE
424350b464cSderaadt 	if (KTRPOINT(p, KTR_STRUCT))
4254ea7ed56Sderaadt 		ktrstruct(p, kname, rbuf, rbuflen-1);
426350b464cSderaadt #endif
427350b464cSderaadt 
428769376ccSkn 	for (rp = rbuf; rp && *rp; rp = pn) {
429350b464cSderaadt 		pn = strchr(rp, ' ');	/* find terminator */
430350b464cSderaadt 		if (pn) {
431350b464cSderaadt 			while (*pn == ' ')
432350b464cSderaadt 				*pn++ = '\0';
433350b464cSderaadt 		}
434737c0fa9Ssemarie 		if ((f = pledgereq_flags(rp)) == 0) {
435350b464cSderaadt 			free(rbuf, M_TEMP, MAXPATHLEN);
436350b464cSderaadt 			return (EINVAL);
437350b464cSderaadt 		}
438350b464cSderaadt 		flags |= f;
439350b464cSderaadt 	}
440350b464cSderaadt 	free(rbuf, M_TEMP, MAXPATHLEN);
4414ea7ed56Sderaadt 	*fp = flags;
4424ea7ed56Sderaadt 	return 0;
4434ea7ed56Sderaadt }
444350b464cSderaadt 
4454ea7ed56Sderaadt int
4464ea7ed56Sderaadt sys_pledge(struct proc *p, void *v, register_t *retval)
4474ea7ed56Sderaadt {
4484ea7ed56Sderaadt 	struct sys_pledge_args /* {
4494ea7ed56Sderaadt 		syscallarg(const char *)promises;
4504ea7ed56Sderaadt 		syscallarg(const char *)execpromises;
4514ea7ed56Sderaadt 	} */	*uap = v;
4524ea7ed56Sderaadt 	struct process *pr = p->p_p;
4534ea7ed56Sderaadt 	uint64_t promises, execpromises;
4544ea7ed56Sderaadt 	int error;
455b20cffafSjca 	int unveil_cleanup = 0;
4564ea7ed56Sderaadt 
457b20cffafSjca 	/* Check for any error in user input */
4584ea7ed56Sderaadt 	if (SCARG(uap, promises)) {
4594ea7ed56Sderaadt 		error = parsepledges(p, "pledgereq",
4604ea7ed56Sderaadt 		    SCARG(uap, promises), &promises);
4614ea7ed56Sderaadt 		if (error)
4624ea7ed56Sderaadt 			return (error);
463b20cffafSjca 	}
464b20cffafSjca 	if (SCARG(uap, execpromises)) {
465b20cffafSjca 		error = parsepledges(p, "pledgeexecreq",
466b20cffafSjca 		    SCARG(uap, execpromises), &execpromises);
467b20cffafSjca 		if (error)
468b20cffafSjca 			return (error);
469b20cffafSjca 	}
4704ea7ed56Sderaadt 
471b20cffafSjca 	mtx_enter(&pr->ps_mtx);
472b20cffafSjca 
473b20cffafSjca 	/* Check for any error wrt current promises */
474b20cffafSjca 	if (SCARG(uap, promises)) {
4754ea7ed56Sderaadt 		/* In "error" mode, ignore promise increase requests,
4764ea7ed56Sderaadt 		 * but accept promise decrease requests */
477cbc3adfbSguenther 		if (ISSET(pr->ps_flags, PS_PLEDGE) &&
4784ea7ed56Sderaadt 		    (pr->ps_pledge & PLEDGE_ERROR))
4794ea7ed56Sderaadt 			promises &= (pr->ps_pledge & PLEDGE_USERSET);
4804ea7ed56Sderaadt 
4814ea7ed56Sderaadt 		/* Only permit reductions */
4824ea7ed56Sderaadt 		if (ISSET(pr->ps_flags, PS_PLEDGE) &&
483b20cffafSjca 		    (((promises | pr->ps_pledge) != pr->ps_pledge))) {
484b20cffafSjca 			mtx_leave(&pr->ps_mtx);
4854ea7ed56Sderaadt 			return (EPERM);
4864ea7ed56Sderaadt 		}
487b20cffafSjca 	}
4884ea7ed56Sderaadt 	if (SCARG(uap, execpromises)) {
4894ea7ed56Sderaadt 		/* Only permit reductions */
4904ea7ed56Sderaadt 		if (ISSET(pr->ps_flags, PS_EXECPLEDGE) &&
491b20cffafSjca 		    (((execpromises | pr->ps_execpledge) != pr->ps_execpledge))) {
492b20cffafSjca 			mtx_leave(&pr->ps_mtx);
493350b464cSderaadt 			return (EPERM);
494350b464cSderaadt 		}
495b20cffafSjca 	}
496350b464cSderaadt 
497b20cffafSjca 	/* Set up promises */
4984ea7ed56Sderaadt 	if (SCARG(uap, promises)) {
4994ea7ed56Sderaadt 		pr->ps_pledge = promises;
5009648c32bSanton 		atomic_setbits_int(&pr->ps_flags, PS_PLEDGE);
501b20cffafSjca 
5028b23add8Sbeck 		if ((pr->ps_pledge & (PLEDGE_RPATH | PLEDGE_WPATH |
5038b23add8Sbeck 		    PLEDGE_CPATH | PLEDGE_DPATH | PLEDGE_TMPPATH | PLEDGE_EXEC |
5048b23add8Sbeck 		    PLEDGE_UNIX | PLEDGE_UNVEIL)) == 0)
505b20cffafSjca 			unveil_cleanup = 1;
5069afe20eeSsemarie 	}
5074ea7ed56Sderaadt 	if (SCARG(uap, execpromises)) {
5084ea7ed56Sderaadt 		pr->ps_execpledge = execpromises;
5099648c32bSanton 		atomic_setbits_int(&pr->ps_flags, PS_EXECPLEDGE);
5104ea7ed56Sderaadt 	}
511b20cffafSjca 
512b20cffafSjca 	mtx_leave(&pr->ps_mtx);
513b20cffafSjca 
514b20cffafSjca 	if (unveil_cleanup) {
515b20cffafSjca 		/*
516b20cffafSjca 		 * Kill off unveil and drop unveil vnode refs if we no
517b20cffafSjca 		 * longer are holding any path-accessing pledge
518b20cffafSjca 		 */
519b20cffafSjca 		KERNEL_LOCK();
520b20cffafSjca 		unveil_destroy(pr);
521b20cffafSjca 		KERNEL_UNLOCK();
522b20cffafSjca 	}
523b20cffafSjca 
524350b464cSderaadt 	return (0);
525350b464cSderaadt }
526350b464cSderaadt 
527350b464cSderaadt int
528f8e00d7dSderaadt pledge_syscall(struct proc *p, int code, uint64_t *tval)
529350b464cSderaadt {
530350b464cSderaadt 	p->p_pledge_syscall = code;
531d14eca6cSsemarie 	*tval = 0;
532350b464cSderaadt 
533350b464cSderaadt 	if (code < 0 || code > SYS_MAXSYSCALL - 1)
534d14eca6cSsemarie 		return (EINVAL);
535d14eca6cSsemarie 
536d4839ae0Sderaadt 	if (pledge_syscalls[code] == PLEDGE_ALWAYS)
537350b464cSderaadt 		return (0);
538350b464cSderaadt 
539d14eca6cSsemarie 	if (p->p_p->ps_pledge & pledge_syscalls[code])
540d14eca6cSsemarie 		return (0);
541d14eca6cSsemarie 
542d14eca6cSsemarie 	*tval = pledge_syscalls[code];
543d14eca6cSsemarie 	return (EPERM);
544350b464cSderaadt }
545350b464cSderaadt 
546350b464cSderaadt int
547fe2523afSderaadt pledge_fail(struct proc *p, int error, uint64_t code)
548350b464cSderaadt {
549354feef1Svisa 	const char *codes = "";
55091bc69b8Sderaadt 	int i;
55191bc69b8Sderaadt 
55291bc69b8Sderaadt 	/* Print first matching pledge */
553853c4e2eSderaadt 	for (i = 0; code && pledgenames[i].bits != 0; i++)
554853c4e2eSderaadt 		if (pledgenames[i].bits & code) {
555853c4e2eSderaadt 			codes = pledgenames[i].name;
55691bc69b8Sderaadt 			break;
557853c4e2eSderaadt 		}
55891bc69b8Sderaadt #ifdef KTRACE
5593b974249Sguenther 	if (KTRPOINT(p, KTR_PLEDGE))
56091bc69b8Sderaadt 		ktrpledge(p, error, code, p->p_pledge_syscall);
56191bc69b8Sderaadt #endif
5624ea7ed56Sderaadt 	if (p->p_p->ps_pledge & PLEDGE_ERROR)
5634ea7ed56Sderaadt 		return (ENOSYS);
5644ea7ed56Sderaadt 
565646656c2Smpi 	KERNEL_LOCK();
56601f24c16Sderaadt 	uprintf("%s[%d]: pledge \"%s\", syscall %d\n",
5674ea7ed56Sderaadt 	    p->p_p->ps_comm, p->p_p->ps_pid, codes, p->p_pledge_syscall);
5684ea7ed56Sderaadt 	p->p_p->ps_acflag |= APLEDGE;
56929256776Smpi 
570a556b217Sclaudio 	/* Try to stop threads immediately, because this process is suspect */
571eb0deef5Sderaadt 	if (P_HASSIBLING(p))
572a556b217Sclaudio 		single_thread_set(p, SINGLE_UNWIND | SINGLE_DEEP);
573eb0deef5Sderaadt 
574fbc2f996Ssemarie 	/* Send uncatchable SIGABRT for coredump */
575fffcd96bSmpi 	sigabort(p);
576350b464cSderaadt 
577350b464cSderaadt 	p->p_p->ps_pledge = 0;		/* Disable all PLEDGE_ flags */
578646656c2Smpi 	KERNEL_UNLOCK();
579350b464cSderaadt 	return (error);
580350b464cSderaadt }
581350b464cSderaadt 
582350b464cSderaadt /*
583350b464cSderaadt  * Need to make it more obvious that one cannot get through here
584350b464cSderaadt  * without the right flags set
585350b464cSderaadt  */
586350b464cSderaadt int
587345a92b4Ssemarie pledge_namei(struct proc *p, struct nameidata *ni, char *origpath)
588350b464cSderaadt {
589350b464cSderaadt 	char path[PATH_MAX];
590215f4190Sderaadt 	uint64_t pledge;
59191bc69b8Sderaadt 	int error;
592350b464cSderaadt 
593fbc2f996Ssemarie 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0 ||
594fbc2f996Ssemarie 	    (p->p_p->ps_flags & PS_COREDUMP))
595a48a073bSsemarie 		return (0);
596beabbbc9Sjca 	pledge = READ_ONCE(p->p_p->ps_pledge);
597a48a073bSsemarie 
598ee41fe2bSderaadt 	if (ni->ni_pledge == 0)
599ee41fe2bSderaadt 		panic("pledge_namei: ni_pledge");
600345a92b4Ssemarie 
6018b23add8Sbeck 	/*
6028b23add8Sbeck 	 * We set the BYPASSUNVEIL flag to skip unveil checks
6038b23add8Sbeck 	 * as necessary
6048b23add8Sbeck 	 */
6058b23add8Sbeck 
606ea999a5dSsemarie 	/* Doing a permitted execve() */
607345a92b4Ssemarie 	if ((ni->ni_pledge & PLEDGE_EXEC) &&
608215f4190Sderaadt 	    (pledge & PLEDGE_EXEC))
609ea999a5dSsemarie 		return (0);
610ea999a5dSsemarie 
61191bc69b8Sderaadt 	error = canonpath(origpath, path, sizeof(path));
61291bc69b8Sderaadt 	if (error)
6138e928e0dSsemarie 		return (error);
614350b464cSderaadt 
615350b464cSderaadt 	/* Detect what looks like a mkstemp(3) family operation */
616215f4190Sderaadt 	if ((pledge & PLEDGE_TMPPATH) &&
617350b464cSderaadt 	    (p->p_pledge_syscall == SYS_open) &&
618345a92b4Ssemarie 	    (ni->ni_pledge & PLEDGE_CPATH) &&
619350b464cSderaadt 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
6208b23add8Sbeck 		ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
621350b464cSderaadt 		return (0);
622350b464cSderaadt 	}
623350b464cSderaadt 
624350b464cSderaadt 	/* Allow unlinking of a mkstemp(3) file...
625350b464cSderaadt 	 * Good opportunity for strict checks here.
626350b464cSderaadt 	 */
627215f4190Sderaadt 	if ((pledge & PLEDGE_TMPPATH) &&
628350b464cSderaadt 	    (p->p_pledge_syscall == SYS_unlink) &&
629350b464cSderaadt 	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
6308b23add8Sbeck 		ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
631350b464cSderaadt 		return (0);
632350b464cSderaadt 	}
633350b464cSderaadt 
634dc5a79f2Ssemarie 	/* Whitelisted paths */
6359c625b88Ssemarie 	switch (p->p_pledge_syscall) {
636dc5a79f2Ssemarie 	case SYS_access:
637dc5a79f2Ssemarie 		/* tzset() needs this. */
6389dfd71d8Sbeck 		if (ni->ni_pledge == PLEDGE_RPATH &&
6398b23add8Sbeck 		    strcmp(path, "/etc/localtime") == 0) {
6408b23add8Sbeck 			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
641dc5a79f2Ssemarie 			return (0);
6428b23add8Sbeck 		}
643a2104a60Smestre 		break;
6449c625b88Ssemarie 	case SYS_open:
6459c625b88Ssemarie 		/* daemon(3) or other such functions */
646345a92b4Ssemarie 		if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
6479c625b88Ssemarie 		    strcmp(path, "/dev/null") == 0) {
6488b23add8Sbeck 			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
6499c625b88Ssemarie 			return (0);
6509c625b88Ssemarie 		}
6519c625b88Ssemarie 
6521d2979c3Sderaadt 		/* readpassphrase(3), getpass(3) */
653215f4190Sderaadt 		if ((pledge & PLEDGE_TTY) &&
654345a92b4Ssemarie 		    (ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
6559c625b88Ssemarie 		    strcmp(path, "/dev/tty") == 0) {
6568b23add8Sbeck 			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
6579c625b88Ssemarie 			return (0);
6589c625b88Ssemarie 		}
6599c625b88Ssemarie 
660350b464cSderaadt 		/* getpw* and friends need a few files */
661345a92b4Ssemarie 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
662215f4190Sderaadt 		    (pledge & PLEDGE_GETPW)) {
663ddd71a3cSsemarie 			if (strcmp(path, "/etc/spwd.db") == 0)
664ddd71a3cSsemarie 				return (EPERM); /* don't call pledge_fail */
6658b23add8Sbeck 			if (strcmp(path, "/etc/pwd.db") == 0) {
6668b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
667350b464cSderaadt 				return (0);
6688b23add8Sbeck 			}
6698b23add8Sbeck 			if (strcmp(path, "/etc/group") == 0) {
6708b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
671350b464cSderaadt 				return (0);
6728b23add8Sbeck 			}
6738b23add8Sbeck 			if (strcmp(path, "/etc/netid") == 0) {
6748b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
675c8cd53f2Sderaadt 				return (0);
676350b464cSderaadt 			}
6778b23add8Sbeck 		}
678350b464cSderaadt 
6799d40f071Sdlg 		/* DNS needs /etc/{resolv.conf,hosts,services,protocols}. */
680345a92b4Ssemarie 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
681215f4190Sderaadt 		    (pledge & PLEDGE_DNS)) {
6828b23add8Sbeck 			if (strcmp(path, "/etc/resolv.conf") == 0) {
6838b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
684350b464cSderaadt 				return (0);
6858b23add8Sbeck 			}
6868b23add8Sbeck 			if (strcmp(path, "/etc/hosts") == 0) {
6878b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
688350b464cSderaadt 				return (0);
6898b23add8Sbeck 			}
6908b23add8Sbeck 			if (strcmp(path, "/etc/services") == 0) {
6918b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
692350b464cSderaadt 				return (0);
693350b464cSderaadt 			}
6949d40f071Sdlg 			if (strcmp(path, "/etc/protocols") == 0) {
6959d40f071Sdlg 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
6969d40f071Sdlg 				return (0);
6979d40f071Sdlg 			}
6988b23add8Sbeck 		}
69937573a84Sderaadt 
700350b464cSderaadt 		/* tzset() needs these. */
701345a92b4Ssemarie 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
702350b464cSderaadt 		    strncmp(path, "/usr/share/zoneinfo/",
7038b23add8Sbeck 		    sizeof("/usr/share/zoneinfo/") - 1) == 0)  {
7048b23add8Sbeck 			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
705350b464cSderaadt 			return (0);
7068b23add8Sbeck 		}
707345a92b4Ssemarie 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
7088b23add8Sbeck 		    strcmp(path, "/etc/localtime") == 0) {
7098b23add8Sbeck 			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
710350b464cSderaadt 			return (0);
7118b23add8Sbeck 		}
712350b464cSderaadt 
713350b464cSderaadt 		break;
714350b464cSderaadt 	case SYS_stat:
715583f2eafStedu 		/* DNS needs /etc/{resolv.conf,hosts}. */
7169dfd71d8Sbeck 		if ((ni->ni_pledge == PLEDGE_RPATH) &&
717583f2eafStedu 		    (pledge & PLEDGE_DNS)) {
718583f2eafStedu 			if (strcmp(path, "/etc/resolv.conf") == 0) {
7198b23add8Sbeck 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
720350b464cSderaadt 				return (0);
7218b23add8Sbeck 			}
722583f2eafStedu 			if (strcmp(path, "/etc/hosts") == 0) {
723583f2eafStedu 				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
724583f2eafStedu 				return (0);
725583f2eafStedu 			}
726583f2eafStedu 		}
727350b464cSderaadt 		break;
728350b464cSderaadt 	}
729350b464cSderaadt 
730eeb4c48fSsemarie 	/*
7311bb80ef7Sbeck 	 * Ensure each flag of ni_pledge has counterpart allowing it in
7329dfd71d8Sbeck 	 * ps_pledge.
733eeb4c48fSsemarie 	 */
734215f4190Sderaadt 	if (ni->ni_pledge & ~pledge)
735215f4190Sderaadt 		return (pledge_fail(p, EPERM, (ni->ni_pledge & ~pledge)));
73651f93831Ssemarie 
7378b23add8Sbeck 	/* continue, and check unveil if present */
738a6ebf764Sbeck 	return (0);
739a6ebf764Sbeck }
740a6ebf764Sbeck 
741350b464cSderaadt /*
74295dd1152Sderaadt  * Only allow reception of safe file descriptors.
743350b464cSderaadt  */
744350b464cSderaadt int
745a48a073bSsemarie pledge_recvfd(struct proc *p, struct file *fp)
746350b464cSderaadt {
7470ced5da0Sderaadt 	struct vnode *vp;
748350b464cSderaadt 
749350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
750350b464cSderaadt 		return (0);
751ebe0f911Sderaadt 	if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
75295dd1152Sderaadt 		return pledge_fail(p, EPERM, PLEDGE_RECVFD);
753350b464cSderaadt 
754350b464cSderaadt 	switch (fp->f_type) {
755350b464cSderaadt 	case DTYPE_SOCKET:
756350b464cSderaadt 	case DTYPE_PIPE:
757a9ee023bSkettenis 	case DTYPE_DMABUF:
75861c1bba6Sjsg 	case DTYPE_SYNC:
75995dd1152Sderaadt 		return (0);
760350b464cSderaadt 	case DTYPE_VNODE:
7616171e120Stedu 		vp = fp->f_data;
76295dd1152Sderaadt 
76395dd1152Sderaadt 		if (vp->v_type != VDIR)
764350b464cSderaadt 			return (0);
76595dd1152Sderaadt 	}
7663775e79eSsemarie 	return pledge_fail(p, EINVAL, PLEDGE_RECVFD);
767350b464cSderaadt }
768350b464cSderaadt 
769350b464cSderaadt /*
77095dd1152Sderaadt  * Only allow sending of safe file descriptors.
771350b464cSderaadt  */
772350b464cSderaadt int
773a48a073bSsemarie pledge_sendfd(struct proc *p, struct file *fp)
774350b464cSderaadt {
7750ced5da0Sderaadt 	struct vnode *vp;
776350b464cSderaadt 
777350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
778350b464cSderaadt 		return (0);
7790ced5da0Sderaadt 	if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
7803793cba7Sderaadt 		return pledge_fail(p, EPERM, PLEDGE_SENDFD);
7813793cba7Sderaadt 
782350b464cSderaadt 	switch (fp->f_type) {
783350b464cSderaadt 	case DTYPE_SOCKET:
784350b464cSderaadt 	case DTYPE_PIPE:
785a9ee023bSkettenis 	case DTYPE_DMABUF:
78661c1bba6Sjsg 	case DTYPE_SYNC:
78795dd1152Sderaadt 		return (0);
788350b464cSderaadt 	case DTYPE_VNODE:
7896171e120Stedu 		vp = fp->f_data;
79095dd1152Sderaadt 
79195dd1152Sderaadt 		if (vp->v_type != VDIR)
792350b464cSderaadt 			return (0);
79395dd1152Sderaadt 		break;
79495dd1152Sderaadt 	}
7953775e79eSsemarie 	return pledge_fail(p, EINVAL, PLEDGE_SENDFD);
796350b464cSderaadt }
797350b464cSderaadt 
798350b464cSderaadt int
799a48a073bSsemarie pledge_sysctl(struct proc *p, int miblen, int *mib, void *new)
800350b464cSderaadt {
8011b2e2cb7Sderaadt 	char	buf[80];
802215f4190Sderaadt 	uint64_t pledge;
80331757d5dStb 	int	i;
80431757d5dStb 
805350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
806350b464cSderaadt 		return (0);
807beabbbc9Sjca 	pledge = READ_ONCE(p->p_p->ps_pledge);
808350b464cSderaadt 
809350b464cSderaadt 	if (new)
810a48a073bSsemarie 		return pledge_fail(p, EFAULT, 0);
811350b464cSderaadt 
812350b464cSderaadt 	/* routing table observation */
813215f4190Sderaadt 	if ((pledge & PLEDGE_ROUTE)) {
814ff5d5b24Sjca 		if ((miblen == 6 || miblen == 7) &&
815350b464cSderaadt 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
816350b464cSderaadt 		    mib[2] == 0 &&
817350b464cSderaadt 		    mib[4] == NET_RT_DUMP)
818350b464cSderaadt 			return (0);
819350b464cSderaadt 
820350b464cSderaadt 		if (miblen == 6 &&
821350b464cSderaadt 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
822350b464cSderaadt 		    mib[2] == 0 &&
823350b464cSderaadt 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
82472366f00Sdenis 		    (mib[4] == NET_RT_TABLE || mib[4] == NET_RT_SOURCE))
825350b464cSderaadt 			return (0);
826350b464cSderaadt 
827350b464cSderaadt 		if (miblen == 7 &&		/* exposes MACs */
828350b464cSderaadt 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
829ee88d605Sderaadt 		    mib[2] == 0 &&
830ee88d605Sderaadt 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
831350b464cSderaadt 		    mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
832350b464cSderaadt 			return (0);
833350b464cSderaadt 	}
834350b464cSderaadt 
835215f4190Sderaadt 	if ((pledge & PLEDGE_WROUTE)) {
8368ba961a7Sflorian 		if (miblen == 4 &&
8378ba961a7Sflorian 		    mib[0] == CTL_NET && mib[1] == PF_INET6 &&
8388ba961a7Sflorian 		    mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_SOIIKEY)
8398ba961a7Sflorian 			return (0);
8408ba961a7Sflorian 	}
8418ba961a7Sflorian 
842215f4190Sderaadt 	if (pledge & (PLEDGE_PS | PLEDGE_VMINFO)) {
843dfa9d678Sderaadt 		if (miblen == 2 &&		/* kern.fscale */
844dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_FSCALE)
845dfa9d678Sderaadt 			return (0);
846dfa9d678Sderaadt 		if (miblen == 2 &&		/* kern.boottime */
847dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_BOOTTIME)
848dfa9d678Sderaadt 			return (0);
849dfa9d678Sderaadt 		if (miblen == 2 &&		/* kern.consdev */
850dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_CONSDEV)
851dfa9d678Sderaadt 			return (0);
8523950137eSderaadt 		if (miblen == 2 &&			/* kern.cptime */
853a89854d8Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME)
854a89854d8Sderaadt 			return (0);
855dfa9d678Sderaadt 		if (miblen == 3 &&			/* kern.cptime2 */
856dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME2)
857dfa9d678Sderaadt 			return (0);
858d52dbbbeScheloha 		if (miblen == 3 &&			/* kern.cpustats */
859d52dbbbeScheloha 		    mib[0] == CTL_KERN && mib[1] == KERN_CPUSTATS)
860d52dbbbeScheloha 			return (0);
861dfa9d678Sderaadt 	}
862dfa9d678Sderaadt 
863215f4190Sderaadt 	if ((pledge & PLEDGE_PS)) {
864dfa9d678Sderaadt 		if (miblen == 4 &&		/* kern.procargs.* */
865dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_ARGS &&
866dfa9d678Sderaadt 		    (mib[3] == KERN_PROC_ARGV || mib[3] == KERN_PROC_ENV))
867dfa9d678Sderaadt 			return (0);
868dfa9d678Sderaadt 		if (miblen == 6 &&		/* kern.proc.* */
869dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC)
870dfa9d678Sderaadt 			return (0);
871ab8f7adbSderaadt 		if (miblen == 3 &&		/* kern.proc_cwd.* */
872ab8f7adbSderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_CWD)
873ab8f7adbSderaadt 			return (0);
874dfa9d678Sderaadt 		if (miblen == 2 &&		/* kern.ccpu */
875dfa9d678Sderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_CCPU)
876dfa9d678Sderaadt 			return (0);
877dfa9d678Sderaadt 		if (miblen == 2 &&		/* vm.maxslp */
878dfa9d678Sderaadt 		    mib[0] == CTL_VM && mib[1] == VM_MAXSLP)
879dfa9d678Sderaadt 			return (0);
880dfa9d678Sderaadt 	}
881dfa9d678Sderaadt 
882215f4190Sderaadt 	if ((pledge & PLEDGE_VMINFO)) {
883dfa9d678Sderaadt 		if (miblen == 2 &&		/* vm.uvmexp */
884dfa9d678Sderaadt 		    mib[0] == CTL_VM && mib[1] == VM_UVMEXP)
885dfa9d678Sderaadt 			return (0);
886dfa9d678Sderaadt 		if (miblen == 3 &&		/* vfs.generic.bcachestat */
887dfa9d678Sderaadt 		    mib[0] == CTL_VFS && mib[1] == VFS_GENERIC &&
888dfa9d678Sderaadt 		    mib[2] == VFS_BCACHESTAT)
889dfa9d678Sderaadt 			return (0);
89090c5cf9bSclaudio 		if (miblen == 3 &&		/* for sysconf(3) */
89190c5cf9bSclaudio 		    mib[0] == CTL_NET && mib[1] == PF_INET6)
89290c5cf9bSclaudio 			return (0);
893dfa9d678Sderaadt 	}
894dfa9d678Sderaadt 
895215f4190Sderaadt 	if ((pledge & (PLEDGE_INET | PLEDGE_UNIX))) {
8965d6a987fSderaadt 		if (miblen == 2 &&		/* kern.somaxconn */
8975d6a987fSderaadt 		    mib[0] == CTL_KERN && mib[1] == KERN_SOMAXCONN)
8985d6a987fSderaadt 			return (0);
8995d6a987fSderaadt 	}
9005d6a987fSderaadt 
901215f4190Sderaadt 	if ((pledge & (PLEDGE_ROUTE | PLEDGE_INET | PLEDGE_DNS))) {
902350b464cSderaadt 		if (miblen == 6 &&		/* getifaddrs() */
903350b464cSderaadt 		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
904350b464cSderaadt 		    mib[2] == 0 &&
905350b464cSderaadt 		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
906350b464cSderaadt 		    mib[4] == NET_RT_IFLIST)
907350b464cSderaadt 			return (0);
908350b464cSderaadt 	}
909350b464cSderaadt 
910215f4190Sderaadt 	if ((pledge & PLEDGE_DISKLABEL)) {
9112579b71cSderaadt 		if (miblen == 2 &&		/* kern.rawpartition */
9122579b71cSderaadt 		    mib[0] == CTL_KERN &&
9132579b71cSderaadt 		    mib[1] == KERN_RAWPARTITION)
9142579b71cSderaadt 			return (0);
915fe565481Sderaadt 		if (miblen == 2 &&		/* kern.maxpartitions */
916fe565481Sderaadt 		    mib[0] == CTL_KERN &&
917fe565481Sderaadt 		    mib[1] == KERN_MAXPARTITIONS)
918fe565481Sderaadt 			return (0);
9192c12dca0Sderaadt #ifdef CPU_CHR2BLK
9202c12dca0Sderaadt 		if (miblen == 3 &&		/* machdep.chr2blk */
9212c12dca0Sderaadt 		    mib[0] == CTL_MACHDEP &&
9222c12dca0Sderaadt 		    mib[1] == CPU_CHR2BLK)
9232c12dca0Sderaadt 			return (0);
9242c12dca0Sderaadt #endif /* CPU_CHR2BLK */
9252579b71cSderaadt 	}
9262579b71cSderaadt 
92721662f6fSderaadt 	if (miblen >= 3 &&			/* ntpd(8) to read sensors */
928350b464cSderaadt 	    mib[0] == CTL_HW && mib[1] == HW_SENSORS)
929350b464cSderaadt 		return (0);
930350b464cSderaadt 
9310d357b6bSclaudio 	if (miblen == 6 &&		/* if_nameindex() */
9320d357b6bSclaudio 	    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
9330d357b6bSclaudio 	    mib[2] == 0 && mib[3] == 0 && mib[4] == NET_RT_IFNAMES)
9340d357b6bSclaudio 		return (0);
9358ab74fdeStedu 
9368ab74fdeStedu 	if (miblen == 2) {
9378ab74fdeStedu 		switch (mib[0]) {
9388ab74fdeStedu 		case CTL_KERN:
9398ab74fdeStedu 			switch (mib[1]) {
9408ab74fdeStedu 			case KERN_DOMAINNAME:	/* getdomainname() */
9418ab74fdeStedu 			case KERN_HOSTNAME:	/* gethostname() */
9428ab74fdeStedu 			case KERN_OSTYPE:	/* uname() */
9438ab74fdeStedu 			case KERN_OSRELEASE:	/* uname() */
9448ab74fdeStedu 			case KERN_OSVERSION:	/* uname() */
9458ab74fdeStedu 			case KERN_VERSION:	/* uname() */
9468ab74fdeStedu 			case KERN_CLOCKRATE:	/* kern.clockrate */
9478ab74fdeStedu 			case KERN_ARGMAX:	/* kern.argmax */
9488ab74fdeStedu 			case KERN_NGROUPS:	/* kern.ngroups */
9498ab74fdeStedu 			case KERN_SYSVSHM:	/* kern.sysvshm */
9508ab74fdeStedu 			case KERN_POSIX1:	/* kern.posix1version */
95181d71f69Srobert 			case KERN_AUTOCONF_SERIAL:	/* kern.autoconf_serial */
952350b464cSderaadt 				return (0);
9538ab74fdeStedu 			}
9548ab74fdeStedu 			break;
9558ab74fdeStedu 		case CTL_HW:
9568ab74fdeStedu 			switch (mib[1]) {
9578ab74fdeStedu 			case HW_MACHINE: 	/* uname() */
9588ab74fdeStedu 			case HW_PAGESIZE: 	/* getpagesize() */
9598aec63ddSjsg 			case HW_PHYSMEM64:	/* hw.physmem */
9608ab74fdeStedu 			case HW_NCPU:		/* hw.ncpu */
9618ab74fdeStedu 			case HW_NCPUONLINE:	/* hw.ncpuonline */
962848974e3Sjsg 			case HW_USERMEM64:	/* hw.usermem */
963350b464cSderaadt 				return (0);
9648ab74fdeStedu 			}
9658ab74fdeStedu 			break;
9668ab74fdeStedu 		case CTL_VM:
9678ab74fdeStedu 			switch (mib[1]) {
9688ab74fdeStedu 			case VM_PSSTRINGS:	/* setproctitle() */
9698ab74fdeStedu 			case VM_LOADAVG:	/* vm.loadavg / getloadavg(3) */
9708ab74fdeStedu 			case VM_MALLOC_CONF:	/* vm.malloc_conf */
971350b464cSderaadt 				return (0);
9728ab74fdeStedu 			}
9738ab74fdeStedu 			break;
9748ab74fdeStedu 		default:
9758ab74fdeStedu 			break;
9768ab74fdeStedu 		}
9778ab74fdeStedu 	}
9788ab74fdeStedu 
979acb89c39Sderaadt #ifdef CPU_SSE
980acb89c39Sderaadt 	if (miblen == 2 &&		/* i386 libm tests for SSE */
981acb89c39Sderaadt 	    mib[0] == CTL_MACHDEP && mib[1] == CPU_SSE)
982acb89c39Sderaadt 		return (0);
983acb89c39Sderaadt #endif /* CPU_SSE */
984350b464cSderaadt 
98549f71640Srobert #ifdef CPU_ID_AA64ISAR0
98649f71640Srobert 	if (miblen == 2 &&		/* arm64 libcrypto inspects CPU features */
98749f71640Srobert 	    mib[0] == CTL_MACHDEP && mib[1] == CPU_ID_AA64ISAR0)
98849f71640Srobert 		return (0);
98949f71640Srobert #endif /* CPU_ID_AA64ISAR0 */
9906a5f8eabSderaadt #ifdef CPU_ID_AA64ISAR1
9916a5f8eabSderaadt 	if (miblen == 2 &&		/* arm64 libcrypto inspects CPU features */
9926a5f8eabSderaadt 	    mib[0] == CTL_MACHDEP && mib[1] == CPU_ID_AA64ISAR1)
9936a5f8eabSderaadt 		return (0);
9946a5f8eabSderaadt #endif /* CPU_ID_AA64ISAR1 */
99549f71640Srobert 
996a4ee6db0Sderaadt 	snprintf(buf, sizeof(buf), "%s(%d): pledge sysctl %d:",
9971b2e2cb7Sderaadt 	    p->p_p->ps_comm, p->p_p->ps_pid, miblen);
9981b2e2cb7Sderaadt 	for (i = 0; i < miblen; i++) {
9994872263bSderaadt 		char *s = buf + strlen(buf);
10004872263bSderaadt 		snprintf(s, sizeof(buf) - (s - buf), " %d", mib[i]);
10011b2e2cb7Sderaadt 	}
100201f24c16Sderaadt 	uprintf("%s\n", buf);
100331757d5dStb 
1004a48a073bSsemarie 	return pledge_fail(p, EINVAL, 0);
1005350b464cSderaadt }
1006350b464cSderaadt 
1007350b464cSderaadt int
1008a48a073bSsemarie pledge_chown(struct proc *p, uid_t uid, gid_t gid)
1009702d2838Sderaadt {
1010702d2838Sderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1011702d2838Sderaadt 		return (0);
1012e29e7853Sderaadt 
10131d0044e1Ssemarie 	if (p->p_p->ps_pledge & PLEDGE_CHOWNUID)
10141d0044e1Ssemarie 		return (0);
10151d0044e1Ssemarie 
1016702d2838Sderaadt 	if (uid != -1 && uid != p->p_ucred->cr_uid)
1017702d2838Sderaadt 		return (EPERM);
1018702d2838Sderaadt 	if (gid != -1 && !groupmember(gid, p->p_ucred))
1019702d2838Sderaadt 		return (EPERM);
1020702d2838Sderaadt 	return (0);
1021702d2838Sderaadt }
1022702d2838Sderaadt 
1023702d2838Sderaadt int
1024a48a073bSsemarie pledge_adjtime(struct proc *p, const void *v)
1025350b464cSderaadt {
1026350b464cSderaadt 	const struct timeval *delta = v;
1027350b464cSderaadt 
1028350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1029350b464cSderaadt 		return (0);
1030350b464cSderaadt 
1031dfa9d678Sderaadt 	if ((p->p_p->ps_pledge & PLEDGE_SETTIME))
1032dfa9d678Sderaadt 		return (0);
1033350b464cSderaadt 	if (delta)
1034a48a073bSsemarie 		return (EPERM);
1035350b464cSderaadt 	return (0);
1036350b464cSderaadt }
1037350b464cSderaadt 
1038350b464cSderaadt int
1039a48a073bSsemarie pledge_sendit(struct proc *p, const void *to)
1040350b464cSderaadt {
1041350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1042350b464cSderaadt 		return (0);
1043350b464cSderaadt 
10445c5d7832Sderaadt 	if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS)))
1045e29e7853Sderaadt 		return (0);		/* may use address */
1046350b464cSderaadt 	if (to == NULL)
1047350b464cSderaadt 		return (0);		/* behaves just like write */
1048a48a073bSsemarie 	return pledge_fail(p, EPERM, PLEDGE_INET);
1049350b464cSderaadt }
1050350b464cSderaadt 
1051350b464cSderaadt int
105243c642caStedu pledge_ioctl(struct proc *p, long com, struct file *fp)
1053350b464cSderaadt {
1054350b464cSderaadt 	struct vnode *vp = NULL;
1055f6b590bcSkettenis 	int error = EPERM;
1056215f4190Sderaadt 	uint64_t pledge;
1057350b464cSderaadt 
1058350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1059350b464cSderaadt 		return (0);
1060beabbbc9Sjca 	pledge = READ_ONCE(p->p_p->ps_pledge);
1061350b464cSderaadt 
1062350b464cSderaadt 	/*
1063350b464cSderaadt 	 * The ioctl's which are always allowed.
1064350b464cSderaadt 	 */
1065350b464cSderaadt 	switch (com) {
1066350b464cSderaadt 	case FIONREAD:
1067350b464cSderaadt 	case FIONBIO:
106839e8cee0Sderaadt 	case FIOCLEX:
106939e8cee0Sderaadt 	case FIONCLEX:
1070350b464cSderaadt 		return (0);
1071350b464cSderaadt 	}
1072350b464cSderaadt 
107366b07cedSsemarie 	/* fp != NULL was already checked */
10743c7289daSratchov 	if (fp->f_type == DTYPE_VNODE) {
10756171e120Stedu 		vp = fp->f_data;
10763c7289daSratchov 		if (vp->v_type == VBAD)
10773c7289daSratchov 			return (ENOTTY);
10783c7289daSratchov 	}
1079350b464cSderaadt 
1080215f4190Sderaadt 	if ((pledge & PLEDGE_INET)) {
1081350b464cSderaadt 		switch (com) {
10820f9a4325Sbluhm 		case SIOCATMARK:
1083b90d0acdSderaadt 		case SIOCGIFGROUP:
1084b90d0acdSderaadt 			if (fp->f_type == DTYPE_SOCKET)
108551d1e1a4Sderaadt 				return (0);
1086b90d0acdSderaadt 			break;
1087b90d0acdSderaadt 		}
1088b90d0acdSderaadt 	}
1089b90d0acdSderaadt 
10903279cf16Sderaadt #if NBPFILTER > 0
1091215f4190Sderaadt 	if ((pledge & PLEDGE_BPF)) {
1092b90d0acdSderaadt 		switch (com) {
1093350b464cSderaadt 		case BIOCGSTATS:	/* bpf: tcpdump privsep on ^C */
1094350b464cSderaadt 			if (fp->f_type == DTYPE_VNODE &&
1095075c06a5Snatano 			    fp->f_ops->fo_ioctl == vn_ioctl &&
1096075c06a5Snatano 			    vp->v_type == VCHR &&
1097075c06a5Snatano 			    cdevsw[major(vp->v_rdev)].d_open == bpfopen)
1098350b464cSderaadt 				return (0);
1099350b464cSderaadt 			break;
1100b90d0acdSderaadt 		}
1101b90d0acdSderaadt 	}
11023279cf16Sderaadt #endif /* NBPFILTER > 0 */
1103b90d0acdSderaadt 
1104215f4190Sderaadt 	if ((pledge & PLEDGE_TAPE)) {
1105b90d0acdSderaadt 		switch (com) {
1106350b464cSderaadt 		case MTIOCGET:
1107350b464cSderaadt 		case MTIOCTOP:
1108350b464cSderaadt 			/* for pax(1) and such, checking tapes... */
1109350b464cSderaadt 			if (fp->f_type == DTYPE_VNODE &&
1110aa8cf620Sderaadt 			    vp->v_type == VCHR) {
1111aa8cf620Sderaadt 				if (vp->v_flag & VISTTY)
1112aa8cf620Sderaadt 					return (ENOTTY);
1113aa8cf620Sderaadt 				else
1114350b464cSderaadt 					return (0);
1115aa8cf620Sderaadt 			}
1116350b464cSderaadt 			break;
1117350b464cSderaadt 		}
1118350b464cSderaadt 	}
1119350b464cSderaadt 
1120f6b590bcSkettenis #if NDRM > 0
1121215f4190Sderaadt 	if ((pledge & PLEDGE_DRM)) {
1122f6b590bcSkettenis 		if ((fp->f_type == DTYPE_VNODE) &&
1123f6b590bcSkettenis 		    (vp->v_type == VCHR) &&
1124f6b590bcSkettenis 		    (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
1125f6b590bcSkettenis 			error = pledge_ioctl_drm(p, com, vp->v_rdev);
1126f6b590bcSkettenis 			if (error == 0)
1127f6b590bcSkettenis 				return 0;
1128f6b590bcSkettenis 		}
1129f6b590bcSkettenis 	}
113061f1f5d4Sderaadt #endif /* NDRM > 0 */
1131f6b590bcSkettenis 
113239b22fbbSderaadt #if NAUDIO > 0
1133215f4190Sderaadt 	if ((pledge & PLEDGE_AUDIO)) {
1134e48418c3Sratchov 		switch (com) {
1135e449cd73Sratchov 		case AUDIO_GETDEV:
1136e48418c3Sratchov 		case AUDIO_GETPOS:
1137898171b4Sratchov 		case AUDIO_GETPAR:
1138898171b4Sratchov 		case AUDIO_SETPAR:
1139898171b4Sratchov 		case AUDIO_START:
1140898171b4Sratchov 		case AUDIO_STOP:
11419dc2590bSratchov 		case AUDIO_MIXER_DEVINFO:
11429dc2590bSratchov 		case AUDIO_MIXER_READ:
11439dc2590bSratchov 		case AUDIO_MIXER_WRITE:
1144e48418c3Sratchov 			if (fp->f_type == DTYPE_VNODE &&
1145e48418c3Sratchov 			    vp->v_type == VCHR &&
1146e48418c3Sratchov 			    cdevsw[major(vp->v_rdev)].d_open == audioopen)
1147e48418c3Sratchov 				return (0);
1148e48418c3Sratchov 		}
1149e48418c3Sratchov 	}
115061f1f5d4Sderaadt #endif /* NAUDIO > 0 */
1151e48418c3Sratchov 
1152215f4190Sderaadt 	if ((pledge & PLEDGE_DISKLABEL)) {
11532579b71cSderaadt 		switch (com) {
11542579b71cSderaadt 		case DIOCGDINFO:
11552579b71cSderaadt 		case DIOCGPDINFO:
11562579b71cSderaadt 		case DIOCRLDINFO:
11572579b71cSderaadt 		case DIOCWDINFO:
1158968bf6a1Sjca 		case BIOCDISK:
11592c12dca0Sderaadt 		case BIOCINQ:
1160968bf6a1Sjca 		case BIOCINSTALLBOOT:
11612c12dca0Sderaadt 		case BIOCVOL:
11622579b71cSderaadt 			if (fp->f_type == DTYPE_VNODE &&
11632579b71cSderaadt 			    ((vp->v_type == VCHR &&
11642579b71cSderaadt 			    cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
11652579b71cSderaadt 			    (vp->v_type == VBLK &&
11662579b71cSderaadt 			    bdevsw[major(vp->v_rdev)].d_type == D_DISK)))
11672579b71cSderaadt 				return (0);
11682579b71cSderaadt 			break;
11692579b71cSderaadt 		case DIOCMAP:
11702579b71cSderaadt 			if (fp->f_type == DTYPE_VNODE &&
11712579b71cSderaadt 			    vp->v_type == VCHR &&
11722579b71cSderaadt 			    cdevsw[major(vp->v_rdev)].d_ioctl == diskmapioctl)
11732579b71cSderaadt 				return (0);
11742579b71cSderaadt 			break;
11752579b71cSderaadt 		}
11762579b71cSderaadt 	}
11772579b71cSderaadt 
11782b0927afSderaadt #if NVIDEO > 0
1179215f4190Sderaadt 	if ((pledge & PLEDGE_VIDEO)) {
11803ec81e34Slandry 		switch (com) {
11813ec81e34Slandry 		case VIDIOC_QUERYCAP:
11823ec81e34Slandry 		case VIDIOC_TRY_FMT:
11833ec81e34Slandry 		case VIDIOC_ENUM_FMT:
11843ec81e34Slandry 		case VIDIOC_S_FMT:
11853ec81e34Slandry 		case VIDIOC_QUERYCTRL:
11863ec81e34Slandry 		case VIDIOC_G_CTRL:
11873ec81e34Slandry 		case VIDIOC_S_CTRL:
11883ec81e34Slandry 		case VIDIOC_G_PARM:
11893ec81e34Slandry 		case VIDIOC_S_PARM:
11903ec81e34Slandry 		case VIDIOC_REQBUFS:
11913ec81e34Slandry 		case VIDIOC_QBUF:
11923ec81e34Slandry 		case VIDIOC_DQBUF:
11933ec81e34Slandry 		case VIDIOC_QUERYBUF:
11943ec81e34Slandry 		case VIDIOC_STREAMON:
11953ec81e34Slandry 		case VIDIOC_STREAMOFF:
11963ec81e34Slandry 		case VIDIOC_ENUM_FRAMESIZES:
11973ec81e34Slandry 		case VIDIOC_ENUM_FRAMEINTERVALS:
1198423d7634Srobert 		case VIDIOC_DQEVENT:
1199423d7634Srobert 		case VIDIOC_ENCODER_CMD:
1200423d7634Srobert 		case VIDIOC_EXPBUF:
1201423d7634Srobert 		case VIDIOC_G_CROP:
1202423d7634Srobert 		case VIDIOC_G_EXT_CTRLS:
1203423d7634Srobert 		case VIDIOC_G_FMT:
1204423d7634Srobert 		case VIDIOC_G_SELECTION:
1205423d7634Srobert 		case VIDIOC_QUERYMENU:
1206423d7634Srobert 		case VIDIOC_SUBSCRIBE_EVENT:
1207423d7634Srobert 		case VIDIOC_S_EXT_CTRLS:
1208423d7634Srobert 		case VIDIOC_S_SELECTION:
1209423d7634Srobert 		case VIDIOC_TRY_DECODER_CMD:
1210423d7634Srobert 		case VIDIOC_TRY_ENCODER_CMD:
12113ec81e34Slandry 			if (fp->f_type == DTYPE_VNODE &&
12123ec81e34Slandry 			    vp->v_type == VCHR &&
12133ec81e34Slandry 			    cdevsw[major(vp->v_rdev)].d_open == videoopen)
12143ec81e34Slandry 				return (0);
12153ec81e34Slandry 			break;
12163ec81e34Slandry 		}
12173ec81e34Slandry 	}
12182b0927afSderaadt #endif
12193ec81e34Slandry 
12202009fb49Stedu #if NPF > 0
1221215f4190Sderaadt 	if ((pledge & PLEDGE_PF)) {
12222119862cSbenno 		switch (com) {
12232119862cSbenno 		case DIOCADDRULE:
12242119862cSbenno 		case DIOCGETSTATUS:
12252119862cSbenno 		case DIOCNATLOOK:
12262119862cSbenno 		case DIOCRADDTABLES:
12272119862cSbenno 		case DIOCRCLRADDRS:
12282119862cSbenno 		case DIOCRCLRTABLES:
12292119862cSbenno 		case DIOCRCLRTSTATS:
12302119862cSbenno 		case DIOCRGETTSTATS:
12312119862cSbenno 		case DIOCRSETADDRS:
12322119862cSbenno 		case DIOCXBEGIN:
12332119862cSbenno 		case DIOCXCOMMIT:
1234c5b34c43Sbenno 		case DIOCKILLSRCNODES:
12352119862cSbenno 			if ((fp->f_type == DTYPE_VNODE) &&
12362119862cSbenno 			    (vp->v_type == VCHR) &&
12372119862cSbenno 			    (cdevsw[major(vp->v_rdev)].d_open == pfopen))
12382119862cSbenno 				return (0);
12392119862cSbenno 			break;
12402119862cSbenno 		}
12412119862cSbenno 	}
124261f1f5d4Sderaadt #endif
12432119862cSbenno 
1244215f4190Sderaadt 	if ((pledge & PLEDGE_TTY)) {
1245350b464cSderaadt 		switch (com) {
1246c975014eSderaadt #if NPTY > 0
12477064a666Snicm 		case PTMGET:
1248215f4190Sderaadt 			if ((pledge & PLEDGE_RPATH) == 0)
12497064a666Snicm 				break;
1250215f4190Sderaadt 			if ((pledge & PLEDGE_WPATH) == 0)
12517064a666Snicm 				break;
12527064a666Snicm 			if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
12537064a666Snicm 				break;
12547064a666Snicm 			if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
12557064a666Snicm 				break;
12567064a666Snicm 			return (0);
12573268d68dSmpi 		case TIOCUCNTL:		/* vmd */
1258215f4190Sderaadt 			if ((pledge & PLEDGE_RPATH) == 0)
12593268d68dSmpi 				break;
1260215f4190Sderaadt 			if ((pledge & PLEDGE_WPATH) == 0)
12613268d68dSmpi 				break;
12623268d68dSmpi 			if (cdevsw[major(vp->v_rdev)].d_open != ptcopen)
12633268d68dSmpi 				break;
12643268d68dSmpi 			return (0);
1265c975014eSderaadt #endif /* NPTY > 0 */
1266350b464cSderaadt 		case TIOCSPGRP:
1267215f4190Sderaadt 			if ((pledge & PLEDGE_PROC) == 0)
1268350b464cSderaadt 				break;
126906152653Ssthen 			/* FALLTHROUGH */
127047c8966aSmillert 		case TIOCFLUSH:		/* getty, telnet */
1271282e3e98Sderaadt 		case TIOCSTART:		/* emacs, etc */
12720c9061ecSderaadt 		case TIOCGPGRP:
1273350b464cSderaadt 		case TIOCGETA:
12747c6a6920Sderaadt 		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
127593bc6376Sderaadt 		case TIOCSTAT:		/* csh */
127651d1e1a4Sderaadt 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
127751d1e1a4Sderaadt 				return (0);
127851d1e1a4Sderaadt 			return (ENOTTY);
1279f50373aeSderaadt 		case TIOCSWINSZ:
12800d584c33Sderaadt 		case TIOCEXT:		/* mail, libedit .. */
12811ed3cb15Sdoug 		case TIOCCBRK:		/* cu */
1282350b464cSderaadt 		case TIOCSBRK:		/* cu */
1283350b464cSderaadt 		case TIOCCDTR:		/* cu */
12841ed3cb15Sdoug 		case TIOCSDTR:		/* cu */
12850fb7496eSderaadt 		case TIOCEXCL:		/* cu */
1286350b464cSderaadt 		case TIOCSETA:		/* cu, ... */
1287350b464cSderaadt 		case TIOCSETAW:		/* cu, ... */
1288350b464cSderaadt 		case TIOCSETAF:		/* tcsetattr TCSAFLUSH, script */
1289843184b3Sderaadt 		case TIOCSCTTY:		/* forkpty(3), login_tty(3), ... */
1290350b464cSderaadt 			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1291350b464cSderaadt 				return (0);
1292350b464cSderaadt 			break;
1293350b464cSderaadt 		}
1294350b464cSderaadt 	}
1295350b464cSderaadt 
1296215f4190Sderaadt 	if ((pledge & PLEDGE_ROUTE)) {
1297f50373aeSderaadt 		switch (com) {
1298f50373aeSderaadt 		case SIOCGIFADDR:
12994607fe4cSflorian 		case SIOCGIFAFLAG_IN6:
13004607fe4cSflorian 		case SIOCGIFALIFETIME_IN6:
130139c636e3Srob 		case SIOCGIFDESCR:
1302f50373aeSderaadt 		case SIOCGIFFLAGS:
13030ecdc917Sjca 		case SIOCGIFMETRIC:
13045e685f16Sreyk 		case SIOCGIFGMEMB:
130502811cbbSderaadt 		case SIOCGIFRDOMAIN:
130602811cbbSderaadt 		case SIOCGIFDSTADDR_IN6:
130702811cbbSderaadt 		case SIOCGIFNETMASK_IN6:
13083b21bdc0Sflorian 		case SIOCGIFXFLAGS:
130902811cbbSderaadt 		case SIOCGNBRINFO_IN6:
131002811cbbSderaadt 		case SIOCGIFINFO_IN6:
13117df8304aSderaadt 		case SIOCGIFMEDIA:
1312f50373aeSderaadt 			if (fp->f_type == DTYPE_SOCKET)
1313f50373aeSderaadt 				return (0);
1314f50373aeSderaadt 			break;
1315f50373aeSderaadt 		}
1316f50373aeSderaadt 	}
1317f50373aeSderaadt 
1318215f4190Sderaadt 	if ((pledge & PLEDGE_WROUTE)) {
13198ba961a7Sflorian 		switch (com) {
13206f55e1acStobhe 		case SIOCAIFADDR:
13216f55e1acStobhe 		case SIOCDIFADDR:
13228ba961a7Sflorian 		case SIOCAIFADDR_IN6:
1323deac7d1eSpamela 		case SIOCDIFADDR_IN6:
13248ba961a7Sflorian 			if (fp->f_type == DTYPE_SOCKET)
13258ba961a7Sflorian 				return (0);
13268ba961a7Sflorian 			break;
13274728222fSbket 		case SIOCSIFMTU:
13284728222fSbket 			if (fp->f_type == DTYPE_SOCKET)
13294728222fSbket 				return (0);
13304728222fSbket 			break;
13318ba961a7Sflorian 		}
13328ba961a7Sflorian 	}
13338ba961a7Sflorian 
13348bc79b23Sreyk #if NVMM > 0
1335215f4190Sderaadt 	if ((pledge & PLEDGE_VMM)) {
13368bc79b23Sreyk 		if ((fp->f_type == DTYPE_VNODE) &&
13378bc79b23Sreyk 		    (vp->v_type == VCHR) &&
13388bc79b23Sreyk 		    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
13398bc79b23Sreyk 			error = pledge_ioctl_vmm(p, com);
13408bc79b23Sreyk 			if (error == 0)
13418bc79b23Sreyk 				return 0;
13428bc79b23Sreyk 		}
13438bc79b23Sreyk 	}
134461f1f5d4Sderaadt #endif
13458bc79b23Sreyk 
13468eadc5ecSjsg #if NPSP > 0
134789961ef8Sbluhm 	if ((pledge & PLEDGE_VMM)) {
134889961ef8Sbluhm 		if ((fp->f_type == DTYPE_VNODE) &&
134989961ef8Sbluhm 		    (vp->v_type == VCHR) &&
135089961ef8Sbluhm 		    (cdevsw[major(vp->v_rdev)].d_open == pspopen)) {
135189961ef8Sbluhm 			error = pledge_ioctl_psp(p, com);
135289961ef8Sbluhm 			if (error == 0)
135389961ef8Sbluhm 				return (0);
135489961ef8Sbluhm 		}
135589961ef8Sbluhm 	}
135689961ef8Sbluhm #endif
135789961ef8Sbluhm 
1358b90d0acdSderaadt 	return pledge_fail(p, error, PLEDGE_TTY);
1359350b464cSderaadt }
1360350b464cSderaadt 
1361350b464cSderaadt int
1362a48a073bSsemarie pledge_sockopt(struct proc *p, int set, int level, int optname)
1363350b464cSderaadt {
1364215f4190Sderaadt 	uint64_t pledge;
1365215f4190Sderaadt 
1366350b464cSderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1367350b464cSderaadt 		return (0);
1368beabbbc9Sjca 	pledge = READ_ONCE(p->p_p->ps_pledge);
1369350b464cSderaadt 
13707ba9c3ebSderaadt 	/* Always allow these, which are too common to reject */
13717ba9c3ebSderaadt 	switch (level) {
13727ba9c3ebSderaadt 	case SOL_SOCKET:
13737ba9c3ebSderaadt 		switch (optname) {
13747ba9c3ebSderaadt 		case SO_RCVBUF:
137536392245Sderaadt 		case SO_ERROR:
1376ced6d44dSclaudio 			return (0);
13777ba9c3ebSderaadt 		}
13787ba9c3ebSderaadt 		break;
1379d6e48951Sderaadt 	case IPPROTO_TCP:
1380d6e48951Sderaadt 		switch (optname) {
1381d6e48951Sderaadt 		case TCP_NODELAY:
1382d6e48951Sderaadt 			return (0);
1383265d4379Sjsg 		}
1384d6e48951Sderaadt 		break;
13857ba9c3ebSderaadt 	}
13867ba9c3ebSderaadt 
1387215f4190Sderaadt 	if ((pledge & PLEDGE_WROUTE)) {
1388a6409917Sflorian 		switch (level) {
1389a6409917Sflorian 		case SOL_SOCKET:
1390a6409917Sflorian 			switch (optname) {
1391a6409917Sflorian 			case SO_RTABLE:
1392a6409917Sflorian 				return (0);
1393a6409917Sflorian 			}
1394a6409917Sflorian 		}
1395a6409917Sflorian 	}
1396a6409917Sflorian 
13975c5d7832Sderaadt 	if ((pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS)) == 0)
1398a48a073bSsemarie 		return pledge_fail(p, EPERM, PLEDGE_INET);
13997ba9c3ebSderaadt 	/* In use by some service libraries */
14007ba9c3ebSderaadt 	switch (level) {
14017ba9c3ebSderaadt 	case SOL_SOCKET:
14027ba9c3ebSderaadt 		switch (optname) {
14037ba9c3ebSderaadt 		case SO_TIMESTAMP:
1404ced6d44dSclaudio 			return (0);
14057ba9c3ebSderaadt 		}
14067ba9c3ebSderaadt 		break;
14077ba9c3ebSderaadt 	}
14087ba9c3ebSderaadt 
140991beba30Sderaadt 	/* DNS resolver may do these requests */
1410215f4190Sderaadt 	if ((pledge & PLEDGE_DNS)) {
141191beba30Sderaadt 		switch (level) {
141291beba30Sderaadt 		case IPPROTO_IPV6:
141391beba30Sderaadt 			switch (optname) {
141491beba30Sderaadt 			case IPV6_RECVPKTINFO:
141591beba30Sderaadt 			case IPV6_USE_MIN_MTU:
141691beba30Sderaadt 				return (0);
141791beba30Sderaadt 			}
141891beba30Sderaadt 		}
141991beba30Sderaadt 	}
142091beba30Sderaadt 
1421215f4190Sderaadt 	if ((pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
1422a48a073bSsemarie 		return pledge_fail(p, EPERM, PLEDGE_INET);
1423350b464cSderaadt 	switch (level) {
1424350b464cSderaadt 	case SOL_SOCKET:
1425350b464cSderaadt 		switch (optname) {
1426350b464cSderaadt 		case SO_RTABLE:
1427f0bd57ecSbluhm 			return pledge_fail(p, EINVAL, PLEDGE_WROUTE);
1428350b464cSderaadt 		}
1429350b464cSderaadt 		return (0);
1430350b464cSderaadt 	}
1431350b464cSderaadt 
1432215f4190Sderaadt 	if ((pledge & PLEDGE_INET) == 0)
1433a48a073bSsemarie 		return pledge_fail(p, EPERM, PLEDGE_INET);
1434350b464cSderaadt 	switch (level) {
1435350b464cSderaadt 	case IPPROTO_TCP:
1436350b464cSderaadt 		switch (optname) {
1437350b464cSderaadt 		case TCP_MD5SIG:
1438350b464cSderaadt 		case TCP_SACK_ENABLE:
1439350b464cSderaadt 		case TCP_MAXSEG:
1440350b464cSderaadt 		case TCP_NOPUSH:
1441ced6d44dSclaudio 		case TCP_INFO:
1442350b464cSderaadt 			return (0);
1443350b464cSderaadt 		}
1444350b464cSderaadt 		break;
1445350b464cSderaadt 	case IPPROTO_IP:
1446350b464cSderaadt 		switch (optname) {
1447fbc4f5d4Snicm 		case IP_OPTIONS:
144843182f4cSderaadt 			if (!set)
1449fbc4f5d4Snicm 				return (0);
1450fbc4f5d4Snicm 			break;
1451350b464cSderaadt 		case IP_TOS:
1452350b464cSderaadt 		case IP_TTL:
1453350b464cSderaadt 		case IP_MINTTL:
1454cf9e83c3Sbenno 		case IP_IPDEFTTL:
1455350b464cSderaadt 		case IP_PORTRANGE:
1456350b464cSderaadt 		case IP_RECVDSTADDR:
1457645be954Sderaadt 		case IP_RECVDSTPORT:
1458350b464cSderaadt 			return (0);
1459350b464cSderaadt 		case IP_MULTICAST_IF:
14607d5bc9dfSbluhm 		case IP_MULTICAST_TTL:
14617d5bc9dfSbluhm 		case IP_MULTICAST_LOOP:
1462350b464cSderaadt 		case IP_ADD_MEMBERSHIP:
1463350b464cSderaadt 		case IP_DROP_MEMBERSHIP:
1464215f4190Sderaadt 			if (pledge & PLEDGE_MCAST)
1465350b464cSderaadt 				return (0);
1466350b464cSderaadt 			break;
1467350b464cSderaadt 		}
1468350b464cSderaadt 		break;
1469350b464cSderaadt 	case IPPROTO_ICMP:
1470350b464cSderaadt 		break;
1471350b464cSderaadt 	case IPPROTO_IPV6:
1472350b464cSderaadt 		switch (optname) {
147382913e62Sderaadt 		case IPV6_TCLASS:
1474350b464cSderaadt 		case IPV6_UNICAST_HOPS:
1475e5ff19c7Sjca 		case IPV6_MINHOPCOUNT:
1476350b464cSderaadt 		case IPV6_RECVHOPLIMIT:
1477350b464cSderaadt 		case IPV6_PORTRANGE:
1478350b464cSderaadt 		case IPV6_RECVPKTINFO:
1479645be954Sderaadt 		case IPV6_RECVDSTPORT:
1480350b464cSderaadt 		case IPV6_V6ONLY:
1481350b464cSderaadt 			return (0);
1482350b464cSderaadt 		case IPV6_MULTICAST_IF:
14837d5bc9dfSbluhm 		case IPV6_MULTICAST_HOPS:
14847d5bc9dfSbluhm 		case IPV6_MULTICAST_LOOP:
1485350b464cSderaadt 		case IPV6_JOIN_GROUP:
1486350b464cSderaadt 		case IPV6_LEAVE_GROUP:
1487215f4190Sderaadt 			if (pledge & PLEDGE_MCAST)
1488350b464cSderaadt 				return (0);
1489350b464cSderaadt 			break;
1490350b464cSderaadt 		}
1491350b464cSderaadt 		break;
1492350b464cSderaadt 	case IPPROTO_ICMPV6:
1493350b464cSderaadt 		break;
1494350b464cSderaadt 	}
1495a48a073bSsemarie 	return pledge_fail(p, EPERM, PLEDGE_INET);
1496350b464cSderaadt }
1497350b464cSderaadt 
1498350b464cSderaadt int
149969dc22ffSmpi pledge_socket(struct proc *p, int domain, unsigned int state)
1500350b464cSderaadt {
1501215f4190Sderaadt 	uint64_t pledge;
1502215f4190Sderaadt 
150339c26ad4Ssemarie 	if (!ISSET(p->p_p->ps_flags, PS_PLEDGE))
150439c26ad4Ssemarie 		return 0;
1505beabbbc9Sjca 	pledge = READ_ONCE(p->p_p->ps_pledge);
1506350b464cSderaadt 
150739c26ad4Ssemarie 	if (ISSET(state, SS_DNS)) {
1508215f4190Sderaadt 		if (ISSET(pledge, PLEDGE_DNS))
150939c26ad4Ssemarie 			return 0;
151039c26ad4Ssemarie 		return pledge_fail(p, EPERM, PLEDGE_DNS);
151139c26ad4Ssemarie 	}
151239c26ad4Ssemarie 
151339c26ad4Ssemarie 	switch (domain) {
1514e956b092Sderaadt 	case -1:		/* accept on any domain */
1515e956b092Sderaadt 		return (0);
151639c26ad4Ssemarie 	case AF_INET:
151739c26ad4Ssemarie 	case AF_INET6:
15185c5d7832Sderaadt 		if (ISSET(pledge, PLEDGE_INET))
151939c26ad4Ssemarie 			return 0;
152039c26ad4Ssemarie 		return pledge_fail(p, EPERM, PLEDGE_INET);
152139c26ad4Ssemarie 
152239c26ad4Ssemarie 	case AF_UNIX:
1523215f4190Sderaadt 		if (ISSET(pledge, PLEDGE_UNIX))
152439c26ad4Ssemarie 			return 0;
152539c26ad4Ssemarie 		return pledge_fail(p, EPERM, PLEDGE_UNIX);
152639c26ad4Ssemarie 	}
152739c26ad4Ssemarie 
152839c26ad4Ssemarie 	return pledge_fail(p, EINVAL, PLEDGE_INET);
1529350b464cSderaadt }
1530350b464cSderaadt 
1531cbbcd319Smillert int
1532a48a073bSsemarie pledge_flock(struct proc *p)
1533cbbcd319Smillert {
1534cbbcd319Smillert 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1535cbbcd319Smillert 		return (0);
1536e29e7853Sderaadt 
1537cbbcd319Smillert 	if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
1538cbbcd319Smillert 		return (0);
1539cbbcd319Smillert 	return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
1540cbbcd319Smillert }
1541cbbcd319Smillert 
1542dfa9d678Sderaadt int
154309de7c43Sjca pledge_swapctl(struct proc *p, int cmd)
1544dfa9d678Sderaadt {
1545dfa9d678Sderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1546dfa9d678Sderaadt 		return (0);
154709de7c43Sjca 
154809de7c43Sjca 	if (p->p_p->ps_pledge & PLEDGE_VMINFO) {
154909de7c43Sjca 		switch (cmd) {
155009de7c43Sjca 		case SWAP_NSWAP:
155109de7c43Sjca 		case SWAP_STATS:
155209de7c43Sjca 			return (0);
155309de7c43Sjca 		}
155409de7c43Sjca 	}
155509de7c43Sjca 
155609de7c43Sjca 	return pledge_fail(p, EPERM, PLEDGE_VMINFO);
1557dfa9d678Sderaadt }
1558dfa9d678Sderaadt 
1559737c0fa9Ssemarie /* bsearch over pledgereq. return flags value if found, 0 else */
15606aabbe27Ssemarie uint64_t
1561737c0fa9Ssemarie pledgereq_flags(const char *req_name)
1562737c0fa9Ssemarie {
1563737c0fa9Ssemarie 	int base = 0, cmp, i, lim;
1564737c0fa9Ssemarie 
1565737c0fa9Ssemarie 	for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
1566737c0fa9Ssemarie 		i = base + (lim >> 1);
1567737c0fa9Ssemarie 		cmp = strcmp(req_name, pledgereq[i].name);
1568737c0fa9Ssemarie 		if (cmp == 0)
1569737c0fa9Ssemarie 			return (pledgereq[i].flags);
1570737c0fa9Ssemarie 		if (cmp > 0) { /* not found before, move right */
1571737c0fa9Ssemarie 			base = i + 1;
1572737c0fa9Ssemarie 			lim--;
1573737c0fa9Ssemarie 		} /* else move left */
1574737c0fa9Ssemarie 	}
1575737c0fa9Ssemarie 	return (0);
1576737c0fa9Ssemarie }
1577737c0fa9Ssemarie 
1578a3951973Sderaadt int
1579a48a073bSsemarie pledge_fcntl(struct proc *p, int cmd)
1580a3951973Sderaadt {
1581a3951973Sderaadt 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1582a3951973Sderaadt 		return (0);
1583a48a073bSsemarie 	if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0 && cmd == F_SETOWN)
1584a48a073bSsemarie 		return pledge_fail(p, EPERM, PLEDGE_PROC);
1585a3951973Sderaadt 	return (0);
1586a3951973Sderaadt }
1587a3951973Sderaadt 
1588a48a073bSsemarie int
1589a48a073bSsemarie pledge_kill(struct proc *p, pid_t pid)
1590a48a073bSsemarie {
1591a48a073bSsemarie 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1592a48a073bSsemarie 		return 0;
1593a48a073bSsemarie 	if (p->p_p->ps_pledge & PLEDGE_PROC)
1594a48a073bSsemarie 		return 0;
159560d49506Sguenther 	if (pid == 0 || pid == p->p_p->ps_pid)
1596a48a073bSsemarie 		return 0;
1597a48a073bSsemarie 	return pledge_fail(p, EPERM, PLEDGE_PROC);
1598a48a073bSsemarie }
1599a48a073bSsemarie 
1600a48a073bSsemarie int
1601b7a7cb6aScheloha pledge_profil(struct proc *p, u_int scale)
1602b7a7cb6aScheloha {
1603b7a7cb6aScheloha 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1604b7a7cb6aScheloha 		return 0;
1605b7a7cb6aScheloha 	if (scale != 0)
1606b7a7cb6aScheloha 		return pledge_fail(p, EPERM, PLEDGE_STDIO);
1607b7a7cb6aScheloha 	return 0;
1608b7a7cb6aScheloha }
1609b7a7cb6aScheloha 
1610b7a7cb6aScheloha int
1611a48a073bSsemarie pledge_protexec(struct proc *p, int prot)
1612a48a073bSsemarie {
1613a48a073bSsemarie 	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1614a48a073bSsemarie 		return 0;
16154ea7ed56Sderaadt 	/* Before kbind(2) call, ld.so and crt may create EXEC mappings */
16164ea7ed56Sderaadt 	if (p->p_p->ps_kbind_addr == 0 && p->p_p->ps_kbind_cookie == 0)
16174ea7ed56Sderaadt 		return 0;
1618a48a073bSsemarie 	if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
1619a48a073bSsemarie 		return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
1620a48a073bSsemarie 	return 0;
1621a48a073bSsemarie }
1622a48a073bSsemarie 
1623350b464cSderaadt int
1624350b464cSderaadt canonpath(const char *input, char *buf, size_t bufsize)
1625350b464cSderaadt {
16268e928e0dSsemarie 	const char *p;
16278e928e0dSsemarie 	char *q;
1628350b464cSderaadt 
1629350b464cSderaadt 	/* can't canon relative paths, don't bother */
1630350b464cSderaadt 	if (input[0] != '/') {
1631350b464cSderaadt 		if (strlcpy(buf, input, bufsize) >= bufsize)
16328e928e0dSsemarie 			return ENAMETOOLONG;
16338e928e0dSsemarie 		return 0;
1634350b464cSderaadt 	}
1635350b464cSderaadt 
16368e928e0dSsemarie 	p = input;
16378e928e0dSsemarie 	q = buf;
16388e928e0dSsemarie 	while (*p && (q - buf < bufsize)) {
16398e928e0dSsemarie 		if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
1640350b464cSderaadt 			p += 1;
16418e928e0dSsemarie 
1642350b464cSderaadt 		} else if (p[0] == '/' && p[1] == '.' &&
16438e928e0dSsemarie 		    (p[2] == '/' || p[2] == '\0')) {
1644350b464cSderaadt 			p += 2;
16458e928e0dSsemarie 
16468e928e0dSsemarie 		} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
16478e928e0dSsemarie 		    (p[3] == '/' || p[3] == '\0')) {
16488e928e0dSsemarie 			p += 3;
16498e928e0dSsemarie 			if (q != buf)	/* "/../" at start of buf */
16508e928e0dSsemarie 				while (*--q != '/')
165142fa0292Stedu 					continue;
16528e928e0dSsemarie 
1653350b464cSderaadt 		} else {
1654350b464cSderaadt 			*q++ = *p++;
1655350b464cSderaadt 		}
1656350b464cSderaadt 	}
16578e928e0dSsemarie 	if ((*p == '\0') && (q - buf < bufsize)) {
1658350b464cSderaadt 		*q = 0;
1659350b464cSderaadt 		return 0;
16608e928e0dSsemarie 	} else
16618e928e0dSsemarie 		return ENAMETOOLONG;
1662350b464cSderaadt }
1663