LCOV - code coverage report
Current view: top level - kern - kern_pledge.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 625 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13