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