1/*	$OpenBSD: kern_pledge.c,v 1.316 2024/06/03 03:41:47 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5 * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/param.h>
21#include <sys/mount.h>
22#include <sys/proc.h>
23#include <sys/mutex.h>
24#include <sys/fcntl.h>
25#include <sys/file.h>
26#include <sys/namei.h>
27#include <sys/socketvar.h>
28#include <sys/vnode.h>
29#include <sys/mman.h>
30#include <sys/sysctl.h>
31#include <sys/syslog.h>
32#include <sys/ktrace.h>
33#include <sys/acct.h>
34#include <sys/swap.h>
35
36#include <sys/ioctl.h>
37#include <sys/termios.h>
38#include <sys/tty.h>
39#include <sys/device.h>
40#include <sys/disklabel.h>
41#include <sys/dkio.h>
42#include <sys/mtio.h>
43#include <sys/audioio.h>
44#include <sys/videoio.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 "video.h"
72#include "pty.h"
73
74#if defined(__amd64__)
75#include "vmm.h"
76#if NVMM > 0
77#include <machine/conf.h>
78#endif
79#endif
80
81#include "drm.h"
82
83uint64_t pledgereq_flags(const char *req);
84int	 parsepledges(struct proc *p, const char *kname,
85	    const char *promises, u_int64_t *fp);
86int	 canonpath(const char *input, char *buf, size_t bufsize);
87void	 unveil_destroy(struct process *ps);
88
89/* #define DEBUG_PLEDGE */
90#ifdef DEBUG_PLEDGE
91int 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 */
102const 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	[SYS_pinsyscalls] = PLEDGE_ALWAYS,
115
116	/* "getting" information about self is considered safe */
117	[SYS_getuid] = PLEDGE_STDIO,
118	[SYS_geteuid] = PLEDGE_STDIO,
119	[SYS_getresuid] = PLEDGE_STDIO,
120	[SYS_getgid] = PLEDGE_STDIO,
121	[SYS_getegid] = PLEDGE_STDIO,
122	[SYS_getresgid] = PLEDGE_STDIO,
123	[SYS_getgroups] = PLEDGE_STDIO,
124	[SYS_getlogin_r] = PLEDGE_STDIO,
125	[SYS_getpgrp] = PLEDGE_STDIO,
126	[SYS_getpgid] = PLEDGE_STDIO,
127	[SYS_getppid] = PLEDGE_STDIO,
128	[SYS_getsid] = PLEDGE_STDIO,
129	[SYS_getthrid] = PLEDGE_STDIO,
130	[SYS_getrlimit] = PLEDGE_STDIO,
131	[SYS_getrtable] = PLEDGE_STDIO,
132	[SYS_gettimeofday] = PLEDGE_STDIO,
133	[SYS_getdtablecount] = PLEDGE_STDIO,
134	[SYS_getrusage] = PLEDGE_STDIO,
135	[SYS_issetugid] = PLEDGE_STDIO,
136	[SYS_clock_getres] = PLEDGE_STDIO,
137	[SYS_clock_gettime] = PLEDGE_STDIO,
138	[SYS_getpid] = PLEDGE_STDIO,
139
140	/*
141	 * Almost exclusively read-only, Very narrow subset.
142	 * Use of "route", "inet", "dns", "ps", or "vminfo"
143	 * expands access.
144	 */
145	[SYS_sysctl] = PLEDGE_STDIO,
146
147	/* For moncontrol(3).  Only allowed to disable profiling. */
148	[SYS_profil] = PLEDGE_STDIO,
149
150	/* Support for malloc(3) family of operations */
151	[SYS_getentropy] = PLEDGE_STDIO,
152	[SYS_madvise] = PLEDGE_STDIO,
153	[SYS_minherit] = PLEDGE_STDIO,
154	[SYS_mmap] = PLEDGE_STDIO,
155	[SYS_mprotect] = PLEDGE_STDIO,
156	[SYS_mimmutable] = PLEDGE_STDIO,
157	[SYS_mquery] = PLEDGE_STDIO,
158	[SYS_munmap] = PLEDGE_STDIO,
159	[SYS_msync] = PLEDGE_STDIO,
160	[SYS_break] = PLEDGE_STDIO,
161
162	[SYS_umask] = PLEDGE_STDIO,
163
164	/* read/write operations */
165	[SYS_read] = PLEDGE_STDIO,
166	[SYS_readv] = PLEDGE_STDIO,
167	[SYS_pread] = PLEDGE_STDIO,
168	[SYS_preadv] = PLEDGE_STDIO,
169	[SYS_write] = PLEDGE_STDIO,
170	[SYS_writev] = PLEDGE_STDIO,
171	[SYS_pwrite] = PLEDGE_STDIO,
172	[SYS_pwritev] = PLEDGE_STDIO,
173	[SYS_recvmsg] = PLEDGE_STDIO,
174	[SYS_recvmmsg] = PLEDGE_STDIO,
175	[SYS_recvfrom] = PLEDGE_STDIO,
176	[SYS_ftruncate] = PLEDGE_STDIO,
177	[SYS_lseek] = PLEDGE_STDIO,
178	[SYS_fpathconf] = PLEDGE_STDIO,
179
180	/*
181	 * Address selection required a network pledge ("inet",
182	 * "unix", "dns".
183	 */
184	[SYS_sendto] = PLEDGE_STDIO,
185
186	/*
187	 * Address specification required a network pledge ("inet",
188	 * "unix", "dns".  SCM_RIGHTS requires "sendfd" or "recvfd".
189	 */
190	[SYS_sendmsg] = PLEDGE_STDIO,
191	[SYS_sendmmsg] = PLEDGE_STDIO,
192
193	/* Common signal operations */
194	[SYS_nanosleep] = PLEDGE_STDIO,
195	[SYS_sigaltstack] = PLEDGE_STDIO,
196	[SYS_sigprocmask] = PLEDGE_STDIO,
197	[SYS_sigsuspend] = PLEDGE_STDIO,
198	[SYS_sigaction] = PLEDGE_STDIO,
199	[SYS_sigreturn] = PLEDGE_STDIO,
200	[SYS_sigpending] = PLEDGE_STDIO,
201	[SYS_getitimer] = PLEDGE_STDIO,
202	[SYS_setitimer] = PLEDGE_STDIO,
203
204	/*
205	 * To support event driven programming.
206	 */
207	[SYS_poll] = PLEDGE_STDIO,
208	[SYS_ppoll] = PLEDGE_STDIO,
209	[SYS_kevent] = PLEDGE_STDIO,
210	[SYS_kqueue] = PLEDGE_STDIO,
211	[SYS_kqueue1] = PLEDGE_STDIO,
212	[SYS_select] = PLEDGE_STDIO,
213	[SYS_pselect] = PLEDGE_STDIO,
214
215	[SYS_fstat] = PLEDGE_STDIO,
216	[SYS_fsync] = PLEDGE_STDIO,
217
218	[SYS_setsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
219	[SYS_getsockopt] = PLEDGE_STDIO,	/* narrow whitelist */
220
221	/* F_SETOWN requires PLEDGE_PROC */
222	[SYS_fcntl] = PLEDGE_STDIO,
223
224	[SYS_close] = PLEDGE_STDIO,
225	[SYS_dup] = PLEDGE_STDIO,
226	[SYS_dup2] = PLEDGE_STDIO,
227	[SYS_dup3] = PLEDGE_STDIO,
228	[SYS_closefrom] = PLEDGE_STDIO,
229	[SYS_shutdown] = PLEDGE_STDIO,
230	[SYS_fchdir] = PLEDGE_STDIO,	/* XXX consider tightening */
231
232	[SYS_pipe] = PLEDGE_STDIO,
233	[SYS_pipe2] = PLEDGE_STDIO,
234	[SYS_socketpair] = PLEDGE_STDIO,
235
236	[SYS_wait4] = PLEDGE_STDIO,
237	[SYS_waitid] = PLEDGE_STDIO,
238
239	/*
240	 * Can kill self with "stdio".  Killing another pid
241	 * requires "proc"
242	 */
243	[SYS_kill] = PLEDGE_STDIO,
244
245	/*
246	 * FIONREAD/FIONBIO for "stdio"
247	 * Other ioctl are selectively allowed based upon other pledges.
248	 */
249	[SYS_ioctl] = PLEDGE_STDIO,
250
251	/*
252	 * Path access/creation calls encounter many extensive
253	 * checks done during pledge_namei()
254	 */
255	[SYS_open] = PLEDGE_STDIO,
256	[SYS_stat] = PLEDGE_STDIO,
257	[SYS_access] = PLEDGE_STDIO,
258	[SYS_readlink] = PLEDGE_STDIO,
259	[SYS___realpath] = PLEDGE_STDIO,
260
261	[SYS_adjtime] = PLEDGE_STDIO,   /* setting requires "settime" */
262	[SYS_adjfreq] = PLEDGE_SETTIME,
263	[SYS_settimeofday] = PLEDGE_SETTIME,
264
265	/*
266	 * Needed by threaded programs
267	 * XXX should we have a new "threads"?
268	 */
269	[SYS___tfork] = PLEDGE_STDIO,
270	[SYS_sched_yield] = PLEDGE_STDIO,
271	[SYS_futex] = PLEDGE_STDIO,
272	[SYS___thrsleep] = PLEDGE_STDIO,
273	[SYS___thrwakeup] = PLEDGE_STDIO,
274	[SYS___threxit] = PLEDGE_STDIO,
275	[SYS___thrsigdivert] = PLEDGE_STDIO,
276	[SYS_getthrname] = PLEDGE_STDIO,
277	[SYS_setthrname] = PLEDGE_STDIO,
278
279	[SYS_fork] = PLEDGE_PROC,
280	[SYS_vfork] = PLEDGE_PROC,
281	[SYS_setpgid] = PLEDGE_PROC,
282	[SYS_setsid] = PLEDGE_PROC,
283
284	[SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
285	[SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
286
287	[SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
288
289	[SYS_setuid] = PLEDGE_ID,
290	[SYS_seteuid] = PLEDGE_ID,
291	[SYS_setreuid] = PLEDGE_ID,
292	[SYS_setresuid] = PLEDGE_ID,
293	[SYS_setgid] = PLEDGE_ID,
294	[SYS_setegid] = PLEDGE_ID,
295	[SYS_setregid] = PLEDGE_ID,
296	[SYS_setresgid] = PLEDGE_ID,
297	[SYS_setgroups] = PLEDGE_ID,
298	[SYS_setlogin] = PLEDGE_ID,
299	[SYS_setrtable] = PLEDGE_ID,
300
301	[SYS_unveil] = PLEDGE_UNVEIL,
302
303	[SYS_execve] = PLEDGE_EXEC,
304
305	[SYS_chdir] = PLEDGE_RPATH,
306	[SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
307	[SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
308	[SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
309	[SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
310	[SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
311	[SYS_truncate] = PLEDGE_WPATH,
312	[SYS_rename] = PLEDGE_RPATH | PLEDGE_CPATH,
313	[SYS_rmdir] = PLEDGE_CPATH,
314	[SYS_renameat] = PLEDGE_CPATH,
315	[SYS_link] = PLEDGE_CPATH,
316	[SYS_linkat] = PLEDGE_CPATH,
317	[SYS_symlink] = PLEDGE_CPATH,
318	[SYS_symlinkat] = PLEDGE_CPATH,
319	[SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
320	[SYS_unlinkat] = PLEDGE_CPATH,
321	[SYS_mkdir] = PLEDGE_CPATH,
322	[SYS_mkdirat] = PLEDGE_CPATH,
323
324	[SYS_mkfifo] = PLEDGE_DPATH,
325	[SYS_mkfifoat] = PLEDGE_DPATH,
326	[SYS_mknod] = PLEDGE_DPATH,
327	[SYS_mknodat] = PLEDGE_DPATH,
328
329	[SYS_revoke] = PLEDGE_TTY,	/* also requires PLEDGE_RPATH */
330
331	/*
332	 * Classify as RPATH|WPATH, because of path information leakage.
333	 * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
334	 */
335	[SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
336
337	/* Classify as RPATH, because these leak path information */
338	[SYS_getdents] = PLEDGE_RPATH,
339	[SYS_getfsstat] = PLEDGE_RPATH,
340	[SYS_statfs] = PLEDGE_RPATH,
341	[SYS_fstatfs] = PLEDGE_RPATH,
342	[SYS_pathconf] = PLEDGE_RPATH,
343	[SYS_pathconfat] = PLEDGE_RPATH,
344
345	[SYS_utimes] = PLEDGE_FATTR,
346	[SYS_futimes] = PLEDGE_FATTR,
347	[SYS_utimensat] = PLEDGE_FATTR,
348	[SYS_futimens] = PLEDGE_FATTR,
349	[SYS_chmod] = PLEDGE_FATTR,
350	[SYS_fchmod] = PLEDGE_FATTR,
351	[SYS_fchmodat] = PLEDGE_FATTR,
352	[SYS_chflags] = PLEDGE_FATTR,
353	[SYS_chflagsat] = PLEDGE_FATTR,
354	[SYS_fchflags] = PLEDGE_FATTR,
355
356	[SYS_chown] = PLEDGE_CHOWN,
357	[SYS_fchownat] = PLEDGE_CHOWN,
358	[SYS_lchown] = PLEDGE_CHOWN,
359	[SYS_fchown] = PLEDGE_CHOWN,
360
361	[SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
362	[SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
363	[SYS_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
364	[SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
365
366	[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
367	[SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
368	[SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
369	[SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
370
371	[SYS_flock] = PLEDGE_FLOCK,
372
373	[SYS_ypconnect] = PLEDGE_GETPW,
374
375	[SYS_swapctl] = PLEDGE_VMINFO,
376};
377
378static const struct {
379	char *name;
380	uint64_t flags;
381} pledgereq[] = {
382	{ "audio",		PLEDGE_AUDIO },
383	{ "bpf",		PLEDGE_BPF },
384	{ "chown",		PLEDGE_CHOWN | PLEDGE_CHOWNUID },
385	{ "cpath",		PLEDGE_CPATH },
386	{ "disklabel",		PLEDGE_DISKLABEL },
387	{ "dns",		PLEDGE_DNS },
388	{ "dpath",		PLEDGE_DPATH },
389	{ "drm",		PLEDGE_DRM },
390	{ "error",		PLEDGE_ERROR },
391	{ "exec",		PLEDGE_EXEC },
392	{ "fattr",		PLEDGE_FATTR | PLEDGE_CHOWN },
393	{ "flock",		PLEDGE_FLOCK },
394	{ "getpw",		PLEDGE_GETPW },
395	{ "id",			PLEDGE_ID },
396	{ "inet",		PLEDGE_INET },
397	{ "mcast",		PLEDGE_MCAST },
398	{ "pf",			PLEDGE_PF },
399	{ "proc",		PLEDGE_PROC },
400	{ "prot_exec",		PLEDGE_PROTEXEC },
401	{ "ps",			PLEDGE_PS },
402	{ "recvfd",		PLEDGE_RECVFD },
403	{ "route",		PLEDGE_ROUTE },
404	{ "rpath",		PLEDGE_RPATH },
405	{ "sendfd",		PLEDGE_SENDFD },
406	{ "settime",		PLEDGE_SETTIME },
407	{ "stdio",		PLEDGE_STDIO },
408	{ "tape",		PLEDGE_TAPE },
409	{ "tmppath",		PLEDGE_TMPPATH },
410	{ "tty",		PLEDGE_TTY },
411	{ "unix",		PLEDGE_UNIX },
412	{ "unveil",		PLEDGE_UNVEIL },
413	{ "video",		PLEDGE_VIDEO },
414	{ "vminfo",		PLEDGE_VMINFO },
415	{ "vmm",		PLEDGE_VMM },
416	{ "wpath",		PLEDGE_WPATH },
417	{ "wroute",		PLEDGE_WROUTE },
418};
419
420int
421parsepledges(struct proc *p, const char *kname, const char *promises, u_int64_t *fp)
422{
423	size_t rbuflen;
424	char *rbuf, *rp, *pn;
425	u_int64_t flags = 0, f;
426	int error;
427
428	rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
429	error = copyinstr(promises, rbuf, MAXPATHLEN, &rbuflen);
430	if (error) {
431		free(rbuf, M_TEMP, MAXPATHLEN);
432		return (error);
433	}
434#ifdef KTRACE
435	if (KTRPOINT(p, KTR_STRUCT))
436		ktrstruct(p, kname, rbuf, rbuflen-1);
437#endif
438
439	for (rp = rbuf; rp && *rp; rp = pn) {
440		pn = strchr(rp, ' ');	/* find terminator */
441		if (pn) {
442			while (*pn == ' ')
443				*pn++ = '\0';
444		}
445		if ((f = pledgereq_flags(rp)) == 0) {
446			free(rbuf, M_TEMP, MAXPATHLEN);
447			return (EINVAL);
448		}
449		flags |= f;
450	}
451	free(rbuf, M_TEMP, MAXPATHLEN);
452	*fp = flags;
453	return 0;
454}
455
456int
457sys_pledge(struct proc *p, void *v, register_t *retval)
458{
459	struct sys_pledge_args /* {
460		syscallarg(const char *)promises;
461		syscallarg(const char *)execpromises;
462	} */	*uap = v;
463	struct process *pr = p->p_p;
464	uint64_t promises, execpromises;
465	int error;
466	int unveil_cleanup = 0;
467
468	/* Check for any error in user input */
469	if (SCARG(uap, promises)) {
470		error = parsepledges(p, "pledgereq",
471		    SCARG(uap, promises), &promises);
472		if (error)
473			return (error);
474	}
475	if (SCARG(uap, execpromises)) {
476		error = parsepledges(p, "pledgeexecreq",
477		    SCARG(uap, execpromises), &execpromises);
478		if (error)
479			return (error);
480	}
481
482	mtx_enter(&pr->ps_mtx);
483
484	/* Check for any error wrt current promises */
485	if (SCARG(uap, promises)) {
486		/* In "error" mode, ignore promise increase requests,
487		 * but accept promise decrease requests */
488		if (ISSET(pr->ps_flags, PS_PLEDGE) &&
489		    (pr->ps_pledge & PLEDGE_ERROR))
490			promises &= (pr->ps_pledge & PLEDGE_USERSET);
491
492		/* Only permit reductions */
493		if (ISSET(pr->ps_flags, PS_PLEDGE) &&
494		    (((promises | pr->ps_pledge) != pr->ps_pledge))) {
495			mtx_leave(&pr->ps_mtx);
496			return (EPERM);
497		}
498	}
499	if (SCARG(uap, execpromises)) {
500		/* Only permit reductions */
501		if (ISSET(pr->ps_flags, PS_EXECPLEDGE) &&
502		    (((execpromises | pr->ps_execpledge) != pr->ps_execpledge))) {
503			mtx_leave(&pr->ps_mtx);
504			return (EPERM);
505		}
506	}
507
508	/* Set up promises */
509	if (SCARG(uap, promises)) {
510		pr->ps_pledge = promises;
511		atomic_setbits_int(&pr->ps_flags, PS_PLEDGE);
512
513		if ((pr->ps_pledge & (PLEDGE_RPATH | PLEDGE_WPATH |
514		    PLEDGE_CPATH | PLEDGE_DPATH | PLEDGE_TMPPATH | PLEDGE_EXEC |
515		    PLEDGE_UNIX | PLEDGE_UNVEIL)) == 0)
516			unveil_cleanup = 1;
517	}
518	if (SCARG(uap, execpromises)) {
519		pr->ps_execpledge = execpromises;
520		atomic_setbits_int(&pr->ps_flags, PS_EXECPLEDGE);
521	}
522
523	mtx_leave(&pr->ps_mtx);
524
525	if (unveil_cleanup) {
526		/*
527		 * Kill off unveil and drop unveil vnode refs if we no
528		 * longer are holding any path-accessing pledge
529		 */
530		KERNEL_LOCK();
531		unveil_destroy(pr);
532		KERNEL_UNLOCK();
533	}
534
535	return (0);
536}
537
538int
539pledge_syscall(struct proc *p, int code, uint64_t *tval)
540{
541	p->p_pledge_syscall = code;
542	*tval = 0;
543
544	if (code < 0 || code > SYS_MAXSYSCALL - 1)
545		return (EINVAL);
546
547	if (pledge_syscalls[code] == PLEDGE_ALWAYS)
548		return (0);
549
550	if (p->p_p->ps_pledge & pledge_syscalls[code])
551		return (0);
552
553	*tval = pledge_syscalls[code];
554	return (EPERM);
555}
556
557int
558pledge_fail(struct proc *p, int error, uint64_t code)
559{
560	const char *codes = "";
561	int i;
562
563	/* Print first matching pledge */
564	for (i = 0; code && pledgenames[i].bits != 0; i++)
565		if (pledgenames[i].bits & code) {
566			codes = pledgenames[i].name;
567			break;
568		}
569#ifdef KTRACE
570	if (KTRPOINT(p, KTR_PLEDGE))
571		ktrpledge(p, error, code, p->p_pledge_syscall);
572#endif
573	if (p->p_p->ps_pledge & PLEDGE_ERROR)
574		return (ENOSYS);
575
576	KERNEL_LOCK();
577	uprintf("%s[%d]: pledge \"%s\", syscall %d\n",
578	    p->p_p->ps_comm, p->p_p->ps_pid, codes, p->p_pledge_syscall);
579	p->p_p->ps_acflag |= APLEDGE;
580
581	/* Try to stop threads immediately, because this process is suspect */
582	if (P_HASSIBLING(p))
583		single_thread_set(p, SINGLE_UNWIND | SINGLE_DEEP);
584
585	/* Send uncatchable SIGABRT for coredump */
586	sigabort(p);
587
588	p->p_p->ps_pledge = 0;		/* Disable all PLEDGE_ flags */
589	KERNEL_UNLOCK();
590	return (error);
591}
592
593/*
594 * Need to make it more obvious that one cannot get through here
595 * without the right flags set
596 */
597int
598pledge_namei(struct proc *p, struct nameidata *ni, char *origpath)
599{
600	char path[PATH_MAX];
601	uint64_t pledge;
602	int error;
603
604	if ((p->p_p->ps_flags & PS_PLEDGE) == 0 ||
605	    (p->p_p->ps_flags & PS_COREDUMP))
606		return (0);
607	pledge = READ_ONCE(p->p_p->ps_pledge);
608
609	if (ni->ni_pledge == 0)
610		panic("pledge_namei: ni_pledge");
611
612	/*
613	 * We set the BYPASSUNVEIL flag to skip unveil checks
614	 * as necessary
615	 */
616
617	/* Doing a permitted execve() */
618	if ((ni->ni_pledge & PLEDGE_EXEC) &&
619	    (pledge & PLEDGE_EXEC))
620		return (0);
621
622	error = canonpath(origpath, path, sizeof(path));
623	if (error)
624		return (error);
625
626	/* Detect what looks like a mkstemp(3) family operation */
627	if ((pledge & PLEDGE_TMPPATH) &&
628	    (p->p_pledge_syscall == SYS_open) &&
629	    (ni->ni_pledge & PLEDGE_CPATH) &&
630	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
631		ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
632		return (0);
633	}
634
635	/* Allow unlinking of a mkstemp(3) file...
636	 * Good opportunity for strict checks here.
637	 */
638	if ((pledge & PLEDGE_TMPPATH) &&
639	    (p->p_pledge_syscall == SYS_unlink) &&
640	    strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
641		ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
642		return (0);
643	}
644
645	/* Whitelisted paths */
646	switch (p->p_pledge_syscall) {
647	case SYS_access:
648		/* tzset() needs this. */
649		if (ni->ni_pledge == PLEDGE_RPATH &&
650		    strcmp(path, "/etc/localtime") == 0) {
651			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
652			return (0);
653		}
654		break;
655	case SYS_open:
656		/* daemon(3) or other such functions */
657		if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
658		    strcmp(path, "/dev/null") == 0) {
659			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
660			return (0);
661		}
662
663		/* readpassphrase(3), getpass(3) */
664		if ((pledge & PLEDGE_TTY) &&
665		    (ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 &&
666		    strcmp(path, "/dev/tty") == 0) {
667			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
668			return (0);
669		}
670
671		/* getpw* and friends need a few files */
672		if ((ni->ni_pledge == PLEDGE_RPATH) &&
673		    (pledge & PLEDGE_GETPW)) {
674			if (strcmp(path, "/etc/spwd.db") == 0)
675				return (EPERM); /* don't call pledge_fail */
676			if (strcmp(path, "/etc/pwd.db") == 0) {
677				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
678				return (0);
679			}
680			if (strcmp(path, "/etc/group") == 0) {
681				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
682				return (0);
683			}
684			if (strcmp(path, "/etc/netid") == 0) {
685				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
686				return (0);
687			}
688		}
689
690		/* DNS needs /etc/{resolv.conf,hosts,services,protocols}. */
691		if ((ni->ni_pledge == PLEDGE_RPATH) &&
692		    (pledge & PLEDGE_DNS)) {
693			if (strcmp(path, "/etc/resolv.conf") == 0) {
694				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
695				return (0);
696			}
697			if (strcmp(path, "/etc/hosts") == 0) {
698				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
699				return (0);
700			}
701			if (strcmp(path, "/etc/services") == 0) {
702				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
703				return (0);
704			}
705			if (strcmp(path, "/etc/protocols") == 0) {
706				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
707				return (0);
708			}
709		}
710
711		/* tzset() needs these. */
712		if ((ni->ni_pledge == PLEDGE_RPATH) &&
713		    strncmp(path, "/usr/share/zoneinfo/",
714		    sizeof("/usr/share/zoneinfo/") - 1) == 0)  {
715			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
716			return (0);
717		}
718		if ((ni->ni_pledge == PLEDGE_RPATH) &&
719		    strcmp(path, "/etc/localtime") == 0) {
720			ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
721			return (0);
722		}
723
724		break;
725	case SYS_stat:
726		/* DNS needs /etc/{resolv.conf,hosts}. */
727		if ((ni->ni_pledge == PLEDGE_RPATH) &&
728		    (pledge & PLEDGE_DNS)) {
729			if (strcmp(path, "/etc/resolv.conf") == 0) {
730				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
731				return (0);
732			}
733			if (strcmp(path, "/etc/hosts") == 0) {
734				ni->ni_cnd.cn_flags |= BYPASSUNVEIL;
735				return (0);
736			}
737		}
738		break;
739	}
740
741	/*
742	 * Ensure each flag of ni_pledge has counterpart allowing it in
743	 * ps_pledge.
744	 */
745	if (ni->ni_pledge & ~pledge)
746		return (pledge_fail(p, EPERM, (ni->ni_pledge & ~pledge)));
747
748	/* continue, and check unveil if present */
749	return (0);
750}
751
752/*
753 * Only allow reception of safe file descriptors.
754 */
755int
756pledge_recvfd(struct proc *p, struct file *fp)
757{
758	struct vnode *vp;
759
760	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
761		return (0);
762	if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
763		return pledge_fail(p, EPERM, PLEDGE_RECVFD);
764
765	switch (fp->f_type) {
766	case DTYPE_SOCKET:
767	case DTYPE_PIPE:
768	case DTYPE_DMABUF:
769	case DTYPE_SYNC:
770		return (0);
771	case DTYPE_VNODE:
772		vp = fp->f_data;
773
774		if (vp->v_type != VDIR)
775			return (0);
776	}
777	return pledge_fail(p, EINVAL, PLEDGE_RECVFD);
778}
779
780/*
781 * Only allow sending of safe file descriptors.
782 */
783int
784pledge_sendfd(struct proc *p, struct file *fp)
785{
786	struct vnode *vp;
787
788	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
789		return (0);
790	if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
791		return pledge_fail(p, EPERM, PLEDGE_SENDFD);
792
793	switch (fp->f_type) {
794	case DTYPE_SOCKET:
795	case DTYPE_PIPE:
796	case DTYPE_DMABUF:
797	case DTYPE_SYNC:
798		return (0);
799	case DTYPE_VNODE:
800		vp = fp->f_data;
801
802		if (vp->v_type != VDIR)
803			return (0);
804		break;
805	}
806	return pledge_fail(p, EINVAL, PLEDGE_SENDFD);
807}
808
809int
810pledge_sysctl(struct proc *p, int miblen, int *mib, void *new)
811{
812	char	buf[80];
813	uint64_t pledge;
814	int	i;
815
816	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
817		return (0);
818	pledge = READ_ONCE(p->p_p->ps_pledge);
819
820	if (new)
821		return pledge_fail(p, EFAULT, 0);
822
823	/* routing table observation */
824	if ((pledge & PLEDGE_ROUTE)) {
825		if ((miblen == 6 || miblen == 7) &&
826		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
827		    mib[2] == 0 &&
828		    mib[4] == NET_RT_DUMP)
829			return (0);
830
831		if (miblen == 6 &&
832		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
833		    mib[2] == 0 &&
834		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
835		    (mib[4] == NET_RT_TABLE || mib[4] == NET_RT_SOURCE))
836			return (0);
837
838		if (miblen == 7 &&		/* exposes MACs */
839		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
840		    mib[2] == 0 &&
841		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
842		    mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
843			return (0);
844	}
845
846	if ((pledge & PLEDGE_WROUTE)) {
847		if (miblen == 4 &&
848		    mib[0] == CTL_NET && mib[1] == PF_INET6 &&
849		    mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_SOIIKEY)
850			return (0);
851	}
852
853	if (pledge & (PLEDGE_PS | PLEDGE_VMINFO)) {
854		if (miblen == 2 &&		/* kern.fscale */
855		    mib[0] == CTL_KERN && mib[1] == KERN_FSCALE)
856			return (0);
857		if (miblen == 2 &&		/* kern.boottime */
858		    mib[0] == CTL_KERN && mib[1] == KERN_BOOTTIME)
859			return (0);
860		if (miblen == 2 &&		/* kern.consdev */
861		    mib[0] == CTL_KERN && mib[1] == KERN_CONSDEV)
862			return (0);
863		if (miblen == 2 &&			/* kern.cptime */
864		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME)
865			return (0);
866		if (miblen == 3 &&			/* kern.cptime2 */
867		    mib[0] == CTL_KERN && mib[1] == KERN_CPTIME2)
868			return (0);
869		if (miblen == 3 &&			/* kern.cpustats */
870		    mib[0] == CTL_KERN && mib[1] == KERN_CPUSTATS)
871			return (0);
872	}
873
874	if ((pledge & PLEDGE_PS)) {
875		if (miblen == 4 &&		/* kern.procargs.* */
876		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_ARGS &&
877		    (mib[3] == KERN_PROC_ARGV || mib[3] == KERN_PROC_ENV))
878			return (0);
879		if (miblen == 6 &&		/* kern.proc.* */
880		    mib[0] == CTL_KERN && mib[1] == KERN_PROC)
881			return (0);
882		if (miblen == 3 &&		/* kern.proc_cwd.* */
883		    mib[0] == CTL_KERN && mib[1] == KERN_PROC_CWD)
884			return (0);
885		if (miblen == 2 &&		/* kern.ccpu */
886		    mib[0] == CTL_KERN && mib[1] == KERN_CCPU)
887			return (0);
888		if (miblen == 2 &&		/* vm.maxslp */
889		    mib[0] == CTL_VM && mib[1] == VM_MAXSLP)
890			return (0);
891	}
892
893	if ((pledge & PLEDGE_VMINFO)) {
894		if (miblen == 2 &&		/* vm.uvmexp */
895		    mib[0] == CTL_VM && mib[1] == VM_UVMEXP)
896			return (0);
897		if (miblen == 3 &&		/* vfs.generic.bcachestat */
898		    mib[0] == CTL_VFS && mib[1] == VFS_GENERIC &&
899		    mib[2] == VFS_BCACHESTAT)
900			return (0);
901		if (miblen == 3 &&		/* for sysconf(3) */
902		    mib[0] == CTL_NET && mib[1] == PF_INET6)
903			return (0);
904	}
905
906	if ((pledge & (PLEDGE_INET | PLEDGE_UNIX))) {
907		if (miblen == 2 &&		/* kern.somaxconn */
908		    mib[0] == CTL_KERN && mib[1] == KERN_SOMAXCONN)
909			return (0);
910	}
911
912	if ((pledge & (PLEDGE_ROUTE | PLEDGE_INET | PLEDGE_DNS))) {
913		if (miblen == 6 &&		/* getifaddrs() */
914		    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
915		    mib[2] == 0 &&
916		    (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
917		    mib[4] == NET_RT_IFLIST)
918			return (0);
919	}
920
921	if ((pledge & PLEDGE_DISKLABEL)) {
922		if (miblen == 2 &&		/* kern.rawpartition */
923		    mib[0] == CTL_KERN &&
924		    mib[1] == KERN_RAWPARTITION)
925			return (0);
926		if (miblen == 2 &&		/* kern.maxpartitions */
927		    mib[0] == CTL_KERN &&
928		    mib[1] == KERN_MAXPARTITIONS)
929			return (0);
930#ifdef CPU_CHR2BLK
931		if (miblen == 3 &&		/* machdep.chr2blk */
932		    mib[0] == CTL_MACHDEP &&
933		    mib[1] == CPU_CHR2BLK)
934			return (0);
935#endif /* CPU_CHR2BLK */
936	}
937
938	if (miblen >= 3 &&			/* ntpd(8) to read sensors */
939	    mib[0] == CTL_HW && mib[1] == HW_SENSORS)
940		return (0);
941
942	if (miblen == 6 &&		/* if_nameindex() */
943	    mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
944	    mib[2] == 0 && mib[3] == 0 && mib[4] == NET_RT_IFNAMES)
945		return (0);
946
947	if (miblen == 2) {
948		switch (mib[0]) {
949		case CTL_KERN:
950			switch (mib[1]) {
951			case KERN_DOMAINNAME:	/* getdomainname() */
952			case KERN_HOSTNAME:	/* gethostname() */
953			case KERN_OSTYPE:	/* uname() */
954			case KERN_OSRELEASE:	/* uname() */
955			case KERN_OSVERSION:	/* uname() */
956			case KERN_VERSION:	/* uname() */
957			case KERN_CLOCKRATE:	/* kern.clockrate */
958			case KERN_ARGMAX:	/* kern.argmax */
959			case KERN_NGROUPS:	/* kern.ngroups */
960			case KERN_SYSVSHM:	/* kern.sysvshm */
961			case KERN_POSIX1:	/* kern.posix1version */
962			case KERN_AUTOCONF_SERIAL:	/* kern.autoconf_serial */
963				return (0);
964			}
965			break;
966		case CTL_HW:
967			switch (mib[1]) {
968			case HW_MACHINE: 	/* uname() */
969			case HW_PAGESIZE: 	/* getpagesize() */
970			case HW_PHYSMEM64:	/* hw.physmem */
971			case HW_NCPU:		/* hw.ncpu */
972			case HW_NCPUONLINE:	/* hw.ncpuonline */
973			case HW_USERMEM64:	/* hw.usermem */
974				return (0);
975			}
976			break;
977		case CTL_VM:
978			switch (mib[1]) {
979			case VM_PSSTRINGS:	/* setproctitle() */
980			case VM_LOADAVG:	/* vm.loadavg / getloadavg(3) */
981			case VM_MALLOC_CONF:	/* vm.malloc_conf */
982				return (0);
983			}
984			break;
985		default:
986			break;
987		}
988	}
989
990#ifdef CPU_SSE
991	if (miblen == 2 &&		/* i386 libm tests for SSE */
992	    mib[0] == CTL_MACHDEP && mib[1] == CPU_SSE)
993		return (0);
994#endif /* CPU_SSE */
995
996#ifdef CPU_ID_AA64ISAR0
997	if (miblen == 2 &&		/* arm64 libcrypto inspects CPU features */
998	    mib[0] == CTL_MACHDEP && mib[1] == CPU_ID_AA64ISAR0)
999		return (0);
1000#endif /* CPU_ID_AA64ISAR0 */
1001
1002	snprintf(buf, sizeof(buf), "%s(%d): pledge sysctl %d:",
1003	    p->p_p->ps_comm, p->p_p->ps_pid, miblen);
1004	for (i = 0; i < miblen; i++) {
1005		char *s = buf + strlen(buf);
1006		snprintf(s, sizeof(buf) - (s - buf), " %d", mib[i]);
1007	}
1008	uprintf("%s\n", buf);
1009
1010	return pledge_fail(p, EINVAL, 0);
1011}
1012
1013int
1014pledge_chown(struct proc *p, uid_t uid, gid_t gid)
1015{
1016	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1017		return (0);
1018
1019	if (p->p_p->ps_pledge & PLEDGE_CHOWNUID)
1020		return (0);
1021
1022	if (uid != -1 && uid != p->p_ucred->cr_uid)
1023		return (EPERM);
1024	if (gid != -1 && !groupmember(gid, p->p_ucred))
1025		return (EPERM);
1026	return (0);
1027}
1028
1029int
1030pledge_adjtime(struct proc *p, const void *v)
1031{
1032	const struct timeval *delta = v;
1033
1034	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1035		return (0);
1036
1037	if ((p->p_p->ps_pledge & PLEDGE_SETTIME))
1038		return (0);
1039	if (delta)
1040		return (EPERM);
1041	return (0);
1042}
1043
1044int
1045pledge_sendit(struct proc *p, const void *to)
1046{
1047	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1048		return (0);
1049
1050	if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS)))
1051		return (0);		/* may use address */
1052	if (to == NULL)
1053		return (0);		/* behaves just like write */
1054	return pledge_fail(p, EPERM, PLEDGE_INET);
1055}
1056
1057int
1058pledge_ioctl(struct proc *p, long com, struct file *fp)
1059{
1060	struct vnode *vp = NULL;
1061	int error = EPERM;
1062	uint64_t pledge;
1063
1064	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1065		return (0);
1066	pledge = READ_ONCE(p->p_p->ps_pledge);
1067
1068	/*
1069	 * The ioctl's which are always allowed.
1070	 */
1071	switch (com) {
1072	case FIONREAD:
1073	case FIONBIO:
1074	case FIOCLEX:
1075	case FIONCLEX:
1076		return (0);
1077	}
1078
1079	/* fp != NULL was already checked */
1080	if (fp->f_type == DTYPE_VNODE) {
1081		vp = fp->f_data;
1082		if (vp->v_type == VBAD)
1083			return (ENOTTY);
1084	}
1085
1086	if ((pledge & PLEDGE_INET)) {
1087		switch (com) {
1088		case SIOCATMARK:
1089		case SIOCGIFGROUP:
1090			if (fp->f_type == DTYPE_SOCKET)
1091				return (0);
1092			break;
1093		}
1094	}
1095
1096#if NBPFILTER > 0
1097	if ((pledge & PLEDGE_BPF)) {
1098		switch (com) {
1099		case BIOCGSTATS:	/* bpf: tcpdump privsep on ^C */
1100			if (fp->f_type == DTYPE_VNODE &&
1101			    fp->f_ops->fo_ioctl == vn_ioctl &&
1102			    vp->v_type == VCHR &&
1103			    cdevsw[major(vp->v_rdev)].d_open == bpfopen)
1104				return (0);
1105			break;
1106		}
1107	}
1108#endif /* NBPFILTER > 0 */
1109
1110	if ((pledge & PLEDGE_TAPE)) {
1111		switch (com) {
1112		case MTIOCGET:
1113		case MTIOCTOP:
1114			/* for pax(1) and such, checking tapes... */
1115			if (fp->f_type == DTYPE_VNODE &&
1116			    vp->v_type == VCHR) {
1117				if (vp->v_flag & VISTTY)
1118					return (ENOTTY);
1119				else
1120					return (0);
1121			}
1122			break;
1123		}
1124	}
1125
1126#if NDRM > 0
1127	if ((pledge & PLEDGE_DRM)) {
1128		if ((fp->f_type == DTYPE_VNODE) &&
1129		    (vp->v_type == VCHR) &&
1130		    (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
1131			error = pledge_ioctl_drm(p, com, vp->v_rdev);
1132			if (error == 0)
1133				return 0;
1134		}
1135	}
1136#endif /* NDRM > 0 */
1137
1138#if NAUDIO > 0
1139	if ((pledge & PLEDGE_AUDIO)) {
1140		switch (com) {
1141		case AUDIO_GETDEV:
1142		case AUDIO_GETPOS:
1143		case AUDIO_GETPAR:
1144		case AUDIO_SETPAR:
1145		case AUDIO_START:
1146		case AUDIO_STOP:
1147		case AUDIO_MIXER_DEVINFO:
1148		case AUDIO_MIXER_READ:
1149		case AUDIO_MIXER_WRITE:
1150			if (fp->f_type == DTYPE_VNODE &&
1151			    vp->v_type == VCHR &&
1152			    cdevsw[major(vp->v_rdev)].d_open == audioopen)
1153				return (0);
1154		}
1155	}
1156#endif /* NAUDIO > 0 */
1157
1158	if ((pledge & PLEDGE_DISKLABEL)) {
1159		switch (com) {
1160		case DIOCGDINFO:
1161		case DIOCGPDINFO:
1162		case DIOCRLDINFO:
1163		case DIOCWDINFO:
1164		case BIOCDISK:
1165		case BIOCINQ:
1166		case BIOCINSTALLBOOT:
1167		case BIOCVOL:
1168			if (fp->f_type == DTYPE_VNODE &&
1169			    ((vp->v_type == VCHR &&
1170			    cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
1171			    (vp->v_type == VBLK &&
1172			    bdevsw[major(vp->v_rdev)].d_type == D_DISK)))
1173				return (0);
1174			break;
1175		case DIOCMAP:
1176			if (fp->f_type == DTYPE_VNODE &&
1177			    vp->v_type == VCHR &&
1178			    cdevsw[major(vp->v_rdev)].d_ioctl == diskmapioctl)
1179				return (0);
1180			break;
1181		}
1182	}
1183
1184#if NVIDEO > 0
1185	if ((pledge & PLEDGE_VIDEO)) {
1186		switch (com) {
1187		case VIDIOC_QUERYCAP:
1188		case VIDIOC_TRY_FMT:
1189		case VIDIOC_ENUM_FMT:
1190		case VIDIOC_S_FMT:
1191		case VIDIOC_QUERYCTRL:
1192		case VIDIOC_G_CTRL:
1193		case VIDIOC_S_CTRL:
1194		case VIDIOC_G_PARM:
1195		case VIDIOC_S_PARM:
1196		case VIDIOC_REQBUFS:
1197		case VIDIOC_QBUF:
1198		case VIDIOC_DQBUF:
1199		case VIDIOC_QUERYBUF:
1200		case VIDIOC_STREAMON:
1201		case VIDIOC_STREAMOFF:
1202		case VIDIOC_ENUM_FRAMESIZES:
1203		case VIDIOC_ENUM_FRAMEINTERVALS:
1204		case VIDIOC_DQEVENT:
1205		case VIDIOC_ENCODER_CMD:
1206		case VIDIOC_EXPBUF:
1207		case VIDIOC_G_CROP:
1208		case VIDIOC_G_EXT_CTRLS:
1209		case VIDIOC_G_FMT:
1210		case VIDIOC_G_SELECTION:
1211		case VIDIOC_QUERYMENU:
1212		case VIDIOC_SUBSCRIBE_EVENT:
1213		case VIDIOC_S_EXT_CTRLS:
1214		case VIDIOC_S_SELECTION:
1215		case VIDIOC_TRY_DECODER_CMD:
1216		case VIDIOC_TRY_ENCODER_CMD:
1217			if (fp->f_type == DTYPE_VNODE &&
1218			    vp->v_type == VCHR &&
1219			    cdevsw[major(vp->v_rdev)].d_open == videoopen)
1220				return (0);
1221			break;
1222		}
1223	}
1224#endif
1225
1226#if NPF > 0
1227	if ((pledge & PLEDGE_PF)) {
1228		switch (com) {
1229		case DIOCADDRULE:
1230		case DIOCGETSTATUS:
1231		case DIOCNATLOOK:
1232		case DIOCRADDTABLES:
1233		case DIOCRCLRADDRS:
1234		case DIOCRCLRTABLES:
1235		case DIOCRCLRTSTATS:
1236		case DIOCRGETTSTATS:
1237		case DIOCRSETADDRS:
1238		case DIOCXBEGIN:
1239		case DIOCXCOMMIT:
1240		case DIOCKILLSRCNODES:
1241			if ((fp->f_type == DTYPE_VNODE) &&
1242			    (vp->v_type == VCHR) &&
1243			    (cdevsw[major(vp->v_rdev)].d_open == pfopen))
1244				return (0);
1245			break;
1246		}
1247	}
1248#endif
1249
1250	if ((pledge & PLEDGE_TTY)) {
1251		switch (com) {
1252#if NPTY > 0
1253		case PTMGET:
1254			if ((pledge & PLEDGE_RPATH) == 0)
1255				break;
1256			if ((pledge & PLEDGE_WPATH) == 0)
1257				break;
1258			if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
1259				break;
1260			if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
1261				break;
1262			return (0);
1263		case TIOCUCNTL:		/* vmd */
1264			if ((pledge & PLEDGE_RPATH) == 0)
1265				break;
1266			if ((pledge & PLEDGE_WPATH) == 0)
1267				break;
1268			if (cdevsw[major(vp->v_rdev)].d_open != ptcopen)
1269				break;
1270			return (0);
1271#endif /* NPTY > 0 */
1272		case TIOCSPGRP:
1273			if ((pledge & PLEDGE_PROC) == 0)
1274				break;
1275			/* FALLTHROUGH */
1276		case TIOCFLUSH:		/* getty, telnet */
1277		case TIOCSTART:		/* emacs, etc */
1278		case TIOCGPGRP:
1279		case TIOCGETA:
1280		case TIOCGWINSZ:	/* ENOTTY return for non-tty */
1281		case TIOCSTAT:		/* csh */
1282			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1283				return (0);
1284			return (ENOTTY);
1285		case TIOCSWINSZ:
1286		case TIOCEXT:		/* mail, libedit .. */
1287		case TIOCCBRK:		/* cu */
1288		case TIOCSBRK:		/* cu */
1289		case TIOCCDTR:		/* cu */
1290		case TIOCSDTR:		/* cu */
1291		case TIOCEXCL:		/* cu */
1292		case TIOCSETA:		/* cu, ... */
1293		case TIOCSETAW:		/* cu, ... */
1294		case TIOCSETAF:		/* tcsetattr TCSAFLUSH, script */
1295		case TIOCSCTTY:		/* forkpty(3), login_tty(3), ... */
1296			if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
1297				return (0);
1298			break;
1299		}
1300	}
1301
1302	if ((pledge & PLEDGE_ROUTE)) {
1303		switch (com) {
1304		case SIOCGIFADDR:
1305		case SIOCGIFAFLAG_IN6:
1306		case SIOCGIFALIFETIME_IN6:
1307		case SIOCGIFDESCR:
1308		case SIOCGIFFLAGS:
1309		case SIOCGIFMETRIC:
1310		case SIOCGIFGMEMB:
1311		case SIOCGIFRDOMAIN:
1312		case SIOCGIFDSTADDR_IN6:
1313		case SIOCGIFNETMASK_IN6:
1314		case SIOCGIFXFLAGS:
1315		case SIOCGNBRINFO_IN6:
1316		case SIOCGIFINFO_IN6:
1317		case SIOCGIFMEDIA:
1318			if (fp->f_type == DTYPE_SOCKET)
1319				return (0);
1320			break;
1321		}
1322	}
1323
1324	if ((pledge & PLEDGE_WROUTE)) {
1325		switch (com) {
1326		case SIOCAIFADDR:
1327		case SIOCDIFADDR:
1328		case SIOCAIFADDR_IN6:
1329		case SIOCDIFADDR_IN6:
1330			if (fp->f_type == DTYPE_SOCKET)
1331				return (0);
1332			break;
1333		case SIOCSIFMTU:
1334			if (fp->f_type == DTYPE_SOCKET)
1335				return (0);
1336			break;
1337		}
1338	}
1339
1340#if NVMM > 0
1341	if ((pledge & PLEDGE_VMM)) {
1342		if ((fp->f_type == DTYPE_VNODE) &&
1343		    (vp->v_type == VCHR) &&
1344		    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
1345			error = pledge_ioctl_vmm(p, com);
1346			if (error == 0)
1347				return 0;
1348		}
1349	}
1350#endif
1351
1352	return pledge_fail(p, error, PLEDGE_TTY);
1353}
1354
1355int
1356pledge_sockopt(struct proc *p, int set, int level, int optname)
1357{
1358	uint64_t pledge;
1359
1360	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1361		return (0);
1362	pledge = READ_ONCE(p->p_p->ps_pledge);
1363
1364	/* Always allow these, which are too common to reject */
1365	switch (level) {
1366	case SOL_SOCKET:
1367		switch (optname) {
1368		case SO_RCVBUF:
1369		case SO_ERROR:
1370			return (0);
1371		}
1372		break;
1373	case IPPROTO_TCP:
1374		switch (optname) {
1375		case TCP_NODELAY:
1376			return (0);
1377		}
1378		break;
1379	}
1380
1381	if ((pledge & PLEDGE_WROUTE)) {
1382		switch (level) {
1383		case SOL_SOCKET:
1384			switch (optname) {
1385			case SO_RTABLE:
1386				return (0);
1387			}
1388		}
1389	}
1390
1391	if ((pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS)) == 0)
1392		return pledge_fail(p, EPERM, PLEDGE_INET);
1393	/* In use by some service libraries */
1394	switch (level) {
1395	case SOL_SOCKET:
1396		switch (optname) {
1397		case SO_TIMESTAMP:
1398			return (0);
1399		}
1400		break;
1401	}
1402
1403	/* DNS resolver may do these requests */
1404	if ((pledge & PLEDGE_DNS)) {
1405		switch (level) {
1406		case IPPROTO_IPV6:
1407			switch (optname) {
1408			case IPV6_RECVPKTINFO:
1409			case IPV6_USE_MIN_MTU:
1410				return (0);
1411			}
1412		}
1413	}
1414
1415	if ((pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
1416		return pledge_fail(p, EPERM, PLEDGE_INET);
1417	switch (level) {
1418	case SOL_SOCKET:
1419		switch (optname) {
1420		case SO_RTABLE:
1421			return pledge_fail(p, EINVAL, PLEDGE_WROUTE);
1422		}
1423		return (0);
1424	}
1425
1426	if ((pledge & PLEDGE_INET) == 0)
1427		return pledge_fail(p, EPERM, PLEDGE_INET);
1428	switch (level) {
1429	case IPPROTO_TCP:
1430		switch (optname) {
1431		case TCP_MD5SIG:
1432		case TCP_SACK_ENABLE:
1433		case TCP_MAXSEG:
1434		case TCP_NOPUSH:
1435		case TCP_INFO:
1436			return (0);
1437		}
1438		break;
1439	case IPPROTO_IP:
1440		switch (optname) {
1441		case IP_OPTIONS:
1442			if (!set)
1443				return (0);
1444			break;
1445		case IP_TOS:
1446		case IP_TTL:
1447		case IP_MINTTL:
1448		case IP_IPDEFTTL:
1449		case IP_PORTRANGE:
1450		case IP_RECVDSTADDR:
1451		case IP_RECVDSTPORT:
1452			return (0);
1453		case IP_MULTICAST_IF:
1454		case IP_MULTICAST_TTL:
1455		case IP_MULTICAST_LOOP:
1456		case IP_ADD_MEMBERSHIP:
1457		case IP_DROP_MEMBERSHIP:
1458			if (pledge & PLEDGE_MCAST)
1459				return (0);
1460			break;
1461		}
1462		break;
1463	case IPPROTO_ICMP:
1464		break;
1465	case IPPROTO_IPV6:
1466		switch (optname) {
1467		case IPV6_TCLASS:
1468		case IPV6_UNICAST_HOPS:
1469		case IPV6_MINHOPCOUNT:
1470		case IPV6_RECVHOPLIMIT:
1471		case IPV6_PORTRANGE:
1472		case IPV6_RECVPKTINFO:
1473		case IPV6_RECVDSTPORT:
1474		case IPV6_V6ONLY:
1475			return (0);
1476		case IPV6_MULTICAST_IF:
1477		case IPV6_MULTICAST_HOPS:
1478		case IPV6_MULTICAST_LOOP:
1479		case IPV6_JOIN_GROUP:
1480		case IPV6_LEAVE_GROUP:
1481			if (pledge & PLEDGE_MCAST)
1482				return (0);
1483			break;
1484		}
1485		break;
1486	case IPPROTO_ICMPV6:
1487		break;
1488	}
1489	return pledge_fail(p, EPERM, PLEDGE_INET);
1490}
1491
1492int
1493pledge_socket(struct proc *p, int domain, unsigned int state)
1494{
1495	uint64_t pledge;
1496
1497	if (!ISSET(p->p_p->ps_flags, PS_PLEDGE))
1498		return 0;
1499	pledge = READ_ONCE(p->p_p->ps_pledge);
1500
1501	if (ISSET(state, SS_DNS)) {
1502		if (ISSET(pledge, PLEDGE_DNS))
1503			return 0;
1504		return pledge_fail(p, EPERM, PLEDGE_DNS);
1505	}
1506
1507	switch (domain) {
1508	case -1:		/* accept on any domain */
1509		return (0);
1510	case AF_INET:
1511	case AF_INET6:
1512		if (ISSET(pledge, PLEDGE_INET))
1513			return 0;
1514		return pledge_fail(p, EPERM, PLEDGE_INET);
1515
1516	case AF_UNIX:
1517		if (ISSET(pledge, PLEDGE_UNIX))
1518			return 0;
1519		return pledge_fail(p, EPERM, PLEDGE_UNIX);
1520	}
1521
1522	return pledge_fail(p, EINVAL, PLEDGE_INET);
1523}
1524
1525int
1526pledge_flock(struct proc *p)
1527{
1528	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1529		return (0);
1530
1531	if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
1532		return (0);
1533	return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
1534}
1535
1536int
1537pledge_swapctl(struct proc *p, int cmd)
1538{
1539	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1540		return (0);
1541
1542	if (p->p_p->ps_pledge & PLEDGE_VMINFO) {
1543		switch (cmd) {
1544		case SWAP_NSWAP:
1545		case SWAP_STATS:
1546			return (0);
1547		}
1548	}
1549
1550	return pledge_fail(p, EPERM, PLEDGE_VMINFO);
1551}
1552
1553/* bsearch over pledgereq. return flags value if found, 0 else */
1554uint64_t
1555pledgereq_flags(const char *req_name)
1556{
1557	int base = 0, cmp, i, lim;
1558
1559	for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
1560		i = base + (lim >> 1);
1561		cmp = strcmp(req_name, pledgereq[i].name);
1562		if (cmp == 0)
1563			return (pledgereq[i].flags);
1564		if (cmp > 0) { /* not found before, move right */
1565			base = i + 1;
1566			lim--;
1567		} /* else move left */
1568	}
1569	return (0);
1570}
1571
1572int
1573pledge_fcntl(struct proc *p, int cmd)
1574{
1575	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1576		return (0);
1577	if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0 && cmd == F_SETOWN)
1578		return pledge_fail(p, EPERM, PLEDGE_PROC);
1579	return (0);
1580}
1581
1582int
1583pledge_kill(struct proc *p, pid_t pid)
1584{
1585	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1586		return 0;
1587	if (p->p_p->ps_pledge & PLEDGE_PROC)
1588		return 0;
1589	if (pid == 0 || pid == p->p_p->ps_pid)
1590		return 0;
1591	return pledge_fail(p, EPERM, PLEDGE_PROC);
1592}
1593
1594int
1595pledge_profil(struct proc *p, u_int scale)
1596{
1597	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1598		return 0;
1599	if (scale != 0)
1600		return pledge_fail(p, EPERM, PLEDGE_STDIO);
1601	return 0;
1602}
1603
1604int
1605pledge_protexec(struct proc *p, int prot)
1606{
1607	if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
1608		return 0;
1609	/* Before kbind(2) call, ld.so and crt may create EXEC mappings */
1610	if (p->p_p->ps_kbind_addr == 0 && p->p_p->ps_kbind_cookie == 0)
1611		return 0;
1612	if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
1613		return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
1614	return 0;
1615}
1616
1617int
1618canonpath(const char *input, char *buf, size_t bufsize)
1619{
1620	const char *p;
1621	char *q;
1622
1623	/* can't canon relative paths, don't bother */
1624	if (input[0] != '/') {
1625		if (strlcpy(buf, input, bufsize) >= bufsize)
1626			return ENAMETOOLONG;
1627		return 0;
1628	}
1629
1630	p = input;
1631	q = buf;
1632	while (*p && (q - buf < bufsize)) {
1633		if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
1634			p += 1;
1635
1636		} else if (p[0] == '/' && p[1] == '.' &&
1637		    (p[2] == '/' || p[2] == '\0')) {
1638			p += 2;
1639
1640		} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
1641		    (p[3] == '/' || p[3] == '\0')) {
1642			p += 3;
1643			if (q != buf)	/* "/../" at start of buf */
1644				while (*--q != '/')
1645					continue;
1646
1647		} else {
1648			*q++ = *p++;
1649		}
1650	}
1651	if ((*p == '\0') && (q - buf < bufsize)) {
1652		*q = 0;
1653		return 0;
1654	} else
1655		return ENAMETOOLONG;
1656}
1657