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