Rename tame() to pledge(). This fairly interface has evolved to be more
authorderaadt <deraadt@openbsd.org>
Fri, 9 Oct 2015 01:17:18 +0000 (01:17 +0000)
committerderaadt <deraadt@openbsd.org>
Fri, 9 Oct 2015 01:17:18 +0000 (01:17 +0000)
strict than anticipated.  It allows a programmer to pledge/promise/covenant
that their program will operate within an easily defined subset of the
Unix environment, or it pays the price.

sys/conf/files
sys/kern/kern_pledge.c [new file with mode: 0644]
sys/kern/kern_tame.c [deleted file]
sys/kern/sys_generic.c
sys/sys/syscall_mi.h

index 7d3d550..04c3ff7 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.603 2015/09/28 08:32:04 mpi Exp $
+#      $OpenBSD: files,v 1.604 2015/10/09 01:17:21 deraadt Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -663,7 +663,7 @@ file kern/kern_physio.c
 file kern/kern_proc.c
 file kern/kern_prot.c
 file kern/kern_resource.c
-file kern/kern_tame.c
+file kern/kern_pledge.c
 file kern/kern_sched.c
 file kern/kern_sensors.c
 file kern/kern_sig.c
diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c
new file mode 100644 (file)
index 0000000..9f134b6
--- /dev/null
@@ -0,0 +1,1241 @@
+/*     $OpenBSD: kern_pledge.c,v 1.1 2015/10/09 01:17:21 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/vnode.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/ktrace.h>
+
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <sys/mtio.h>
+#include <net/bpf.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/syscall.h>
+#include <sys/syscallargs.h>
+#include <sys/systm.h>
+#include <sys/pledge.h>
+
+int canonpath(const char *input, char *buf, size_t bufsize);
+
+const u_int pledge_syscalls[SYS_MAXSYSCALL] = {
+       [SYS_exit] = 0xffffffff,
+       [SYS_kbind] = 0xffffffff,
+
+       [SYS_getuid] = PLEDGE_SELF,
+       [SYS_geteuid] = PLEDGE_SELF,
+       [SYS_getresuid] = PLEDGE_SELF,
+       [SYS_getgid] = PLEDGE_SELF,
+       [SYS_getegid] = PLEDGE_SELF,
+       [SYS_getresgid] = PLEDGE_SELF,
+       [SYS_getgroups] = PLEDGE_SELF,
+       [SYS_getlogin] = PLEDGE_SELF,
+       [SYS_getpgrp] = PLEDGE_SELF,
+       [SYS_getpgid] = PLEDGE_SELF,
+       [SYS_getppid] = PLEDGE_SELF,
+       [SYS_getsid] = PLEDGE_SELF,
+       [SYS_getthrid] = PLEDGE_SELF,
+       [SYS_getrlimit] = PLEDGE_SELF,
+       [SYS_gettimeofday] = PLEDGE_SELF,
+       [SYS_getdtablecount] = PLEDGE_SELF,
+       [SYS_getrusage] = PLEDGE_SELF,
+       [SYS_issetugid] = PLEDGE_SELF,
+       [SYS_clock_getres] = PLEDGE_SELF,
+       [SYS_clock_gettime] = PLEDGE_SELF,
+       [SYS_getpid] = PLEDGE_SELF,
+       [SYS_umask] = PLEDGE_SELF,
+       [SYS_sysctl] = PLEDGE_SELF,     /* read-only; narrow subset */
+       [SYS_adjtime] = PLEDGE_SELF,    /* read-only */
+
+       [SYS_fchdir] = PLEDGE_SELF,     /* careful of directory fd inside jails */
+
+       /* needed by threaded programs */
+       [SYS_sched_yield] = PLEDGE_SELF,
+       [SYS___thrsleep] = PLEDGE_SELF,
+       [SYS___thrwakeup] = PLEDGE_SELF,
+       [SYS___threxit] = PLEDGE_SELF,
+       [SYS___thrsigdivert] = PLEDGE_SELF,
+
+       [SYS_sendsyslog] = PLEDGE_SELF,
+       [SYS_nanosleep] = PLEDGE_SELF,
+       [SYS_sigprocmask] = PLEDGE_SELF,
+       [SYS_sigaction] = PLEDGE_SELF,
+       [SYS_sigreturn] = PLEDGE_SELF,
+       [SYS_sigpending] = PLEDGE_SELF,
+       [SYS_getitimer] = PLEDGE_SELF,
+       [SYS_setitimer] = PLEDGE_SELF,
+
+       [SYS_pledge] = PLEDGE_SELF,
+
+       [SYS_wait4] = PLEDGE_SELF,
+
+       [SYS_poll] = PLEDGE_RW,
+       [SYS_kevent] = PLEDGE_RW,
+       [SYS_kqueue] = PLEDGE_RW,
+       [SYS_select] = PLEDGE_RW,
+
+       [SYS_close] = PLEDGE_RW,
+       [SYS_dup] = PLEDGE_RW,
+       [SYS_dup2] = PLEDGE_RW,
+       [SYS_dup3] = PLEDGE_RW,
+       [SYS_closefrom] = PLEDGE_RW,
+       [SYS_shutdown] = PLEDGE_RW,
+       [SYS_read] = PLEDGE_RW,
+       [SYS_readv] = PLEDGE_RW,
+       [SYS_pread] = PLEDGE_RW,
+       [SYS_preadv] = PLEDGE_RW,
+       [SYS_write] = PLEDGE_RW,
+       [SYS_writev] = PLEDGE_RW,
+       [SYS_pwrite] = PLEDGE_RW,
+       [SYS_pwritev] = PLEDGE_RW,
+       [SYS_ftruncate] = PLEDGE_RW,
+       [SYS_lseek] = PLEDGE_RW,
+       [SYS_fstat] = PLEDGE_RW,
+
+       [SYS_fcntl] = PLEDGE_RW,
+       [SYS_fsync] = PLEDGE_RW,
+       [SYS_pipe] = PLEDGE_RW,
+       [SYS_pipe2] = PLEDGE_RW,
+       [SYS_socketpair] = PLEDGE_RW,
+       [SYS_getdents] = PLEDGE_RW,
+
+       [SYS_sendto] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+       [SYS_sendmsg] = PLEDGE_RW,
+       [SYS_recvmsg] = PLEDGE_RW,
+       [SYS_recvfrom] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+
+       [SYS_fork] = PLEDGE_PROC,
+       [SYS_vfork] = PLEDGE_PROC,
+       [SYS_kill] = PLEDGE_PROC,
+       [SYS_setpgid] = PLEDGE_PROC,
+       [SYS_sigsuspend] = PLEDGE_PROC,
+       [SYS_setrlimit] = PLEDGE_PROC,
+
+       [SYS_execve] = PLEDGE_EXEC,
+
+       [SYS_setgroups] = PLEDGE_PROC,
+       [SYS_setresgid] = PLEDGE_PROC,
+       [SYS_setresuid] = PLEDGE_PROC,
+
+       /* FIONREAD/FIONBIO, plus further checks in pledge_ioctl_check() */
+       [SYS_ioctl] = PLEDGE_RW | PLEDGE_IOCTL | PLEDGE_TTY,
+
+       [SYS_getentropy] = PLEDGE_MALLOC,
+       [SYS_madvise] = PLEDGE_MALLOC,
+       [SYS_minherit] = PLEDGE_MALLOC,
+       [SYS_mmap] = PLEDGE_MALLOC,
+       [SYS_mprotect] = PLEDGE_MALLOC,
+       [SYS_mquery] = PLEDGE_MALLOC,
+       [SYS_munmap] = PLEDGE_MALLOC,
+
+       [SYS_open] = PLEDGE_SELF,                       /* further checks in namei */
+       [SYS_stat] = PLEDGE_SELF,                       /* further checks in namei */
+       [SYS_access] = PLEDGE_SELF,             /* further checks in namei */
+       [SYS_readlink] = PLEDGE_SELF,           /* further checks in namei */
+
+       [SYS_chdir] = PLEDGE_RPATH,
+       [SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
+       [SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
+       [SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
+       [SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
+       [SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
+       [SYS_rename] = PLEDGE_CPATH,
+       [SYS_rmdir] = PLEDGE_CPATH,
+       [SYS_renameat] = PLEDGE_CPATH,
+       [SYS_link] = PLEDGE_CPATH,
+       [SYS_linkat] = PLEDGE_CPATH,
+       [SYS_symlink] = PLEDGE_CPATH,
+       [SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
+       [SYS_unlinkat] = PLEDGE_CPATH,
+       [SYS_mkdir] = PLEDGE_CPATH,
+       [SYS_mkdirat] = PLEDGE_CPATH,
+
+       /*
+        * Classify as RPATH|WPATH, because of path information leakage.
+        * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
+        */
+       [SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
+
+       /* Classify as RPATH, because these leak path information */
+       [SYS_getfsstat] = PLEDGE_RPATH,
+       [SYS_statfs] = PLEDGE_RPATH,
+       [SYS_fstatfs] = PLEDGE_RPATH,
+
+       [SYS_utimes] = PLEDGE_FATTR,
+       [SYS_futimes] = PLEDGE_FATTR,
+       [SYS_utimensat] = PLEDGE_FATTR,
+       [SYS_futimens] = PLEDGE_FATTR,
+       [SYS_chmod] = PLEDGE_FATTR,
+       [SYS_fchmod] = PLEDGE_FATTR,
+       [SYS_fchmodat] = PLEDGE_FATTR,
+       [SYS_chflags] = PLEDGE_FATTR,
+       [SYS_chflagsat] = PLEDGE_FATTR,
+       [SYS_chown] = PLEDGE_FATTR,
+       [SYS_fchownat] = PLEDGE_FATTR,
+       [SYS_lchown] = PLEDGE_FATTR,
+       [SYS_fchown] = PLEDGE_FATTR,
+
+       [SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+       [SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+
+       [SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_bind] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_setsockopt] = PLEDGE_INET | PLEDGE_UNIX,
+       [SYS_getsockopt] = PLEDGE_INET | PLEDGE_UNIX,
+
+       [SYS_flock] = PLEDGE_GETPW,
+};
+
+static const struct {
+       char *name;
+       int flags;
+} pledgereq[] = {
+       { "malloc",             PLEDGE_SELF | PLEDGE_MALLOC },
+       { "rw",                 PLEDGE_SELF | PLEDGE_RW },
+       { "stdio",              PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_RW },
+       { "rpath",              PLEDGE_SELF | PLEDGE_RW | PLEDGE_RPATH },
+       { "wpath",              PLEDGE_SELF | PLEDGE_RW | PLEDGE_WPATH },
+       { "tmppath",            PLEDGE_SELF | PLEDGE_RW | PLEDGE_TMPPATH },
+       { "inet",               PLEDGE_SELF | PLEDGE_RW | PLEDGE_INET },
+       { "unix",               PLEDGE_SELF | PLEDGE_RW | PLEDGE_UNIX },
+       { "dns",                PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_DNSPATH },
+       { "getpw",              PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_RW | PLEDGE_GETPW },
+/*X*/  { "cmsg",               PLEDGE_UNIX | PLEDGE_INET | PLEDGE_SENDFD | PLEDGE_RECVFD },
+       { "sendfd",             PLEDGE_RW | PLEDGE_SENDFD },
+       { "recvfd",             PLEDGE_RW | PLEDGE_RECVFD },
+       { "ioctl",              PLEDGE_IOCTL },
+       { "route",              PLEDGE_ROUTE },
+       { "mcast",              PLEDGE_MCAST },
+       { "tty",                PLEDGE_TTY },
+       { "proc",               PLEDGE_PROC },
+       { "exec",               PLEDGE_EXEC },
+       { "cpath",              PLEDGE_CPATH },
+       { "abort",              PLEDGE_ABORT },
+       { "fattr",              PLEDGE_FATTR },
+       { "prot_exec",          PLEDGE_PROTEXEC },
+};
+
+int
+sys_pledge(struct proc *p, void *v, register_t *retval)
+{
+       struct sys_pledge_args /* {
+               syscallarg(const char *)request;
+               syscallarg(const char **)paths;
+       } */    *uap = v;
+       int flags = 0;
+       int error;
+
+       if (SCARG(uap, request)) {
+               size_t rbuflen;
+               char *rbuf, *rp, *pn;
+               int f, i;
+
+               rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+               error = copyinstr(SCARG(uap, request), rbuf, MAXPATHLEN,
+                   &rbuflen);
+               if (error) {
+                       free(rbuf, M_TEMP, MAXPATHLEN);
+                       return (error);
+               }
+#ifdef KTRACE
+               if (KTRPOINT(p, KTR_STRUCT))
+                       ktrstruct(p, "pledgereq", rbuf, rbuflen-1);
+#endif
+
+               for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
+                       pn = strchr(rp, ' ');   /* find terminator */
+                       if (pn) {
+                               while (*pn == ' ')
+                                       *pn++ = '\0';
+                       }
+
+                       for (f = i = 0; i < nitems(pledgereq); i++) {
+                               if (strcmp(rp, pledgereq[i].name) == 0) {
+                                       f = pledgereq[i].flags;
+                                       break;
+                               }
+                       }
+                       if (f == 0) {
+                               free(rbuf, M_TEMP, MAXPATHLEN);
+                               return (EINVAL);
+                       }
+                       flags |= f;
+               }
+               free(rbuf, M_TEMP, MAXPATHLEN);
+       }
+
+       if (flags & ~PLEDGE_USERSET)
+               return (EINVAL);
+
+       if ((p->p_p->ps_flags & PS_PLEDGE)) {
+               /* Already pledged, only allow reductions */
+               if (((flags | p->p_p->ps_pledge) & PLEDGE_USERSET) !=
+                   (p->p_p->ps_pledge & PLEDGE_USERSET)) {
+                       return (EPERM);
+               }
+
+               flags &= p->p_p->ps_pledge;
+               flags &= PLEDGE_USERSET;                /* Relearn _ACTIVE */
+       }
+
+       if (SCARG(uap, paths)) {
+               const char **u = SCARG(uap, paths), *sp;
+               struct whitepaths *wl;
+               char *cwdpath = NULL, *path;
+               size_t cwdpathlen = MAXPATHLEN * 4, cwdlen, len, maxargs = 0;
+               int i, error;
+
+               if (p->p_p->ps_pledgepaths)
+                       return (EPERM);
+
+               /* Count paths */
+               for (i = 0; i < PLEDGE_MAXPATHS; i++) {
+                       if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
+                               return (error);
+                       if (sp == NULL)
+                               break;
+               }
+               if (i == PLEDGE_MAXPATHS)
+                       return (E2BIG);
+
+               wl = malloc(sizeof *wl + sizeof(struct whitepath) * (i+1),
+                   M_TEMP, M_WAITOK | M_ZERO);
+               wl->wl_size = sizeof *wl + sizeof(struct whitepath) * (i+1);
+               wl->wl_count = i;
+               wl->wl_ref = 1;
+
+               path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+
+               /* Copy in */
+               for (i = 0; i < wl->wl_count; i++) {
+                       char *fullpath = NULL, *builtpath = NULL, *canopath = NULL, *cwd;
+                       size_t builtlen = 0;
+
+                       if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
+                               break;
+                       if (sp == NULL)
+                               break;
+                       if ((error = copyinstr(sp, path, MAXPATHLEN, &len)) != 0)
+                               break;
+#ifdef KTRACE
+                       if (KTRPOINT(p, KTR_STRUCT))
+                               ktrstruct(p, "pledgepath", path, len-1);
+#endif
+
+                       /* If path is relative, prepend cwd */
+                       if (path[0] != '/') {
+                               if (cwdpath == NULL) {
+                                       char *bp, *bpend;
+
+                                       cwdpath = malloc(cwdpathlen, M_TEMP, M_WAITOK);
+                                       bp = &cwdpath[cwdpathlen];
+                                       bpend = bp;
+                                       *(--bp) = '\0';
+
+                                       error = vfs_getcwd_common(p->p_fd->fd_cdir,
+                                           NULL, &bp, cwdpath, cwdpathlen/2,
+                                           GETCWD_CHECK_ACCESS, p);
+                                       if (error)
+                                               break;
+                                       cwd = bp;
+                                       cwdlen = (bpend - bp);
+                               }
+
+                               /* NUL included in cwd component */
+                               builtlen = cwdlen + 1 + strlen(path);
+                               if (builtlen > PATH_MAX) {
+                                       error = ENAMETOOLONG;
+                                       break;
+                               }
+                               builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
+                               snprintf(builtpath, builtlen, "%s/%s", cwd, path);
+                               // printf("pledge: builtpath = %s\n", builtpath);
+                               fullpath = builtpath;
+                       } else
+                               fullpath = path;
+
+                       canopath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+                       error = canonpath(fullpath, canopath, MAXPATHLEN);
+
+                       free(builtpath, M_TEMP, builtlen);
+                       if (error != 0) {
+                               free(canopath, M_TEMP, MAXPATHLEN);
+                               break;
+                       }
+
+                       len = strlen(canopath) + 1;
+
+                       //printf("pledge: canopath = %s %lld strlen %lld\n", canopath,
+                       //    (long long)len, (long long)strlen(canopath));
+
+                       if (maxargs += len > ARG_MAX) {
+                               error = E2BIG;
+                               break;
+                       }
+                       wl->wl_paths[i].name = malloc(len, M_TEMP, M_WAITOK);
+                       memcpy(wl->wl_paths[i].name, canopath, len);
+                       wl->wl_paths[i].len = len;
+                       free(canopath, M_TEMP, MAXPATHLEN);
+               }
+               free(path, M_TEMP, MAXPATHLEN);
+               free(cwdpath, M_TEMP, cwdpathlen);
+
+               if (error) {
+                       for (i = 0; i < wl->wl_count; i++)
+                               free(wl->wl_paths[i].name,
+                                   M_TEMP, wl->wl_paths[i].len);
+                       free(wl, M_TEMP, wl->wl_size);
+                       return (error);
+               }
+               p->p_p->ps_pledgepaths = wl;
+#if 0
+               printf("pledge: %s(%d): paths loaded:\n", p->p_comm, p->p_pid);
+               for (i = 0; i < wl->wl_count; i++)
+                       if (wl->wl_paths[i].name)
+                               printf("pledge: %d=%s %lld\n", i, wl->wl_paths[i].name,
+                                   (long long)wl->wl_paths[i].len);
+#endif
+       }
+
+       p->p_p->ps_pledge = flags;
+       p->p_p->ps_flags |= PS_PLEDGE;
+       return (0);
+}
+
+int
+pledge_check(struct proc *p, int code)
+{
+       p->p_pledgenote = p->p_pledgeafter = 0; /* XX optimise? */
+       p->p_pledge_syscall = code;
+
+       if (code < 0 || code > SYS_MAXSYSCALL - 1)
+               return (0);
+
+       if (p->p_p->ps_pledge == 0)
+               return (code == SYS_exit || code == SYS_kbind);
+       return (p->p_p->ps_pledge & pledge_syscalls[code]);
+}
+
+int
+pledge_fail(struct proc *p, int error, int code)
+{
+       printf("%s(%d): syscall %d\n", p->p_comm, p->p_pid, p->p_pledge_syscall);
+       if (p->p_p->ps_pledge & PLEDGE_ABORT) { /* Core dump requested */
+               struct sigaction sa;
+
+               memset(&sa, 0, sizeof sa);
+               sa.sa_handler = SIG_DFL;
+               setsigvec(p, SIGABRT, &sa);
+               psignal(p, SIGABRT);
+       } else
+               psignal(p, SIGKILL);
+
+       p->p_p->ps_pledge = 0;          /* Disable all PLEDGE_ flags */
+       return (error);
+}
+
+/*
+ * Need to make it more obvious that one cannot get through here
+ * without the right flags set
+ */
+int
+pledge_namei(struct proc *p, char *origpath)
+{
+       char path[PATH_MAX];
+
+       if (p->p_pledgenote == TMN_COREDUMP)
+               return (0);                     /* Allow a coredump */
+
+       if (canonpath(origpath, path, sizeof(path)) != 0)
+               return (pledge_fail(p, EPERM, PLEDGE_RPATH));
+
+       if ((p->p_pledgenote & TMN_FATTR) &&
+           (p->p_p->ps_pledge & PLEDGE_FATTR) == 0) {
+               printf("%s(%d): inode syscall%d, not allowed\n",
+                   p->p_comm, p->p_pid, p->p_pledge_syscall);
+               return (pledge_fail(p, EPERM, PLEDGE_FATTR));
+       }
+
+       /* Detect what looks like a mkstemp(3) family operation */
+       if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
+           (p->p_pledge_syscall == SYS_open) &&
+           (p->p_pledgenote & TMN_CPATH) &&
+           strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
+               return (0);
+       }
+
+       /* Allow unlinking of a mkstemp(3) file...
+        * Good opportunity for strict checks here.
+        */
+       if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
+           (p->p_pledge_syscall == SYS_unlink) &&
+           strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
+               return (0);
+       }
+
+       /* open, mkdir, or other path creation operation */
+       if ((p->p_pledgenote & TMN_CPATH) &&
+           ((p->p_p->ps_pledge & PLEDGE_CPATH) == 0))
+               return (pledge_fail(p, EPERM, PLEDGE_CPATH));
+
+       if ((p->p_pledgenote & TMN_WPATH) &&
+           (p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
+               return (pledge_fail(p, EPERM, PLEDGE_WPATH));
+
+       /* Read-only paths used occasionally by libc */
+       switch (p->p_pledge_syscall) {
+       case SYS_access:
+               /* tzset() needs this. */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   strcmp(path, "/etc/localtime") == 0)
+                       return (0);
+               break;
+       case SYS_open:
+               /* getpw* and friends need a few files */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   (p->p_p->ps_pledge & PLEDGE_GETPW)) {
+                       if (strcmp(path, "/etc/spwd.db") == 0)
+                               return (EPERM);
+                       if (strcmp(path, "/etc/pwd.db") == 0)
+                               return (0);
+                       if (strcmp(path, "/etc/group") == 0)
+                               return (0);
+               }
+
+               /* DNS needs /etc/{resolv.conf,hosts,services}. */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
+                       if (strcmp(path, "/etc/resolv.conf") == 0) {
+                               p->p_pledgeafter |= TMA_DNSRESOLV;
+                               return (0);
+                       }
+                       if (strcmp(path, "/etc/hosts") == 0)
+                               return (0);
+                       if (strcmp(path, "/etc/services") == 0)
+                               return (0);
+               }
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   (p->p_p->ps_pledge & PLEDGE_GETPW)) {
+                       if (strcmp(path, "/var/run/ypbind.lock") == 0) {
+                               p->p_pledgeafter |= TMA_YPLOCK;
+                               return (0);
+                       }
+                       if (strncmp(path, "/var/yp/binding/",
+                           sizeof("/var/yp/binding/") - 1) == 0)
+                               return (0);
+               }
+               /* tzset() needs these. */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   strncmp(path, "/usr/share/zoneinfo/",
+                   sizeof("/usr/share/zoneinfo/") - 1) == 0)
+                       return (0);
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   strcmp(path, "/etc/localtime") == 0)
+                       return (0);
+
+               /* /usr/share/nls/../libc.cat has to succeed for strerror(3). */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   strncmp(path, "/usr/share/nls/",
+                   sizeof("/usr/share/nls/") - 1) == 0 &&
+                   strcmp(path + strlen(path) - 9, "/libc.cat") == 0)
+                       return (0);
+               break;
+       case SYS_readlink:
+               /* Allow /etc/malloc.conf for malloc(3). */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   strcmp(path, "/etc/malloc.conf") == 0)
+                       return (0);
+               break;
+       case SYS_stat:
+               /* DNS needs /etc/resolv.conf. */
+               if ((p->p_pledgenote == TMN_RPATH) &&
+                   (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
+                       if (strcmp(path, "/etc/resolv.conf") == 0) {
+                               p->p_pledgeafter |= TMA_DNSRESOLV;
+                               return (0);
+                       }
+               }
+               break;
+       }
+
+       /*
+        * If a whitelist is set, compare canonical paths.  Anything
+        * not on the whitelist gets ENOENT.
+        */
+       if (p->p_p->ps_pledgepaths) {
+               struct whitepaths *wl = p->p_p->ps_pledgepaths;
+               char *fullpath, *builtpath = NULL, *canopath = NULL;
+               size_t builtlen = 0;
+               int i, error;
+
+               if (origpath[0] != '/') {
+                       char *cwdpath, *cwd, *bp, *bpend;
+                       size_t cwdpathlen = MAXPATHLEN * 4, cwdlen;
+
+                       cwdpath = malloc(cwdpathlen, M_TEMP, M_WAITOK);
+                       bp = &cwdpath[cwdpathlen];
+                       bpend = bp;
+                       *(--bp) = '\0';
+
+                       error = vfs_getcwd_common(p->p_fd->fd_cdir,
+                           NULL, &bp, cwdpath, cwdpathlen/2,
+                           GETCWD_CHECK_ACCESS, p);
+                       if (error) {
+                               free(cwdpath, M_TEMP, cwdpathlen);
+                               return (error);
+                       }
+                       cwd = bp;
+                       cwdlen = (bpend - bp);
+
+                       /* NUL included in cwd component */
+                       builtlen = cwdlen + 1 + strlen(origpath);
+                       builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
+                       snprintf(builtpath, builtlen, "%s/%s", cwd, origpath);
+                       fullpath = builtpath;
+                       free(cwdpath, M_TEMP, cwdpathlen);
+
+                       //printf("namei: builtpath = %s %lld strlen %lld\n", builtpath,
+                       //    (long long)builtlen, (long long)strlen(builtpath));
+               } else
+                       fullpath = path;
+
+               canopath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+               error = canonpath(fullpath, canopath, MAXPATHLEN);
+
+               free(builtpath, M_TEMP, builtlen);
+               if (error != 0) {
+                       free(canopath, M_TEMP, MAXPATHLEN);
+                       return (pledge_fail(p, EPERM, PLEDGE_RPATH));
+               }
+
+               //printf("namei: canopath = %s strlen %lld\n", canopath,
+               //    (long long)strlen(canopath));
+
+               error = ENOENT;
+               for (i = 0; i < wl->wl_count && wl->wl_paths[i].name && error; i++) {
+                       if (strncmp(canopath, wl->wl_paths[i].name,
+                           wl->wl_paths[i].len - 1) == 0) {
+                               u_char term = canopath[wl->wl_paths[i].len - 1];
+
+                               if (term == '\0' || term == '/' ||
+                                   wl->wl_paths[i].name[1] == '\0')
+                                       error = 0;
+                       }
+               }
+               free(canopath, M_TEMP, MAXPATHLEN);
+               return (error);                 /* Don't hint why it failed */
+       }
+
+       if (p->p_p->ps_pledge & PLEDGE_RPATH)
+               return (0);
+       if (p->p_p->ps_pledge & PLEDGE_WPATH)
+               return (0);
+       if (p->p_p->ps_pledge & PLEDGE_CPATH)
+               return (0);
+
+       return (pledge_fail(p, EPERM, PLEDGE_RPATH));
+}
+
+void
+pledge_aftersyscall(struct proc *p, int code, int error)
+{
+       if ((p->p_pledgeafter & TMA_YPLOCK) && error == 0)
+               atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_YP_ACTIVE | PLEDGE_INET);
+       if ((p->p_pledgeafter & TMA_DNSRESOLV) && error == 0)
+               atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_DNS_ACTIVE);
+}
+
+/*
+ * By default, only the advisory cmsg's can be received from the kernel,
+ * such as TIMESTAMP ntpd.
+ *
+ * If PLEDGE_RECVFD is set SCM_RIGHTS is also allowed in for a carefully
+ * selected set of descriptors (specifically to exclude directories).
+ *
+ * This results in a kill upon recv, if some other process on the system
+ * send a SCM_RIGHTS to an open socket of some sort.  That will discourage
+ * leaving such sockets lying around...
+ */
+int
+pledge_cmsg_recv(struct proc *p, struct mbuf *control)
+{
+       struct msghdr tmp;
+       struct cmsghdr *cmsg;
+       int *fdp, fd;
+       struct file *fp;
+       int nfds, i;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       /* Scan the cmsg */
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.msg_control = mtod(control, struct cmsghdr *);
+       tmp.msg_controllen = control->m_len;
+       cmsg = CMSG_FIRSTHDR(&tmp);
+
+       while (cmsg != NULL) {
+               if (cmsg->cmsg_level == SOL_SOCKET &&
+                   cmsg->cmsg_type == SCM_RIGHTS)
+                       break;
+               cmsg = CMSG_NXTHDR(&tmp, cmsg);
+       }
+
+       /* No SCM_RIGHTS found -> OK */
+       if (cmsg == NULL)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
+               return pledge_fail(p, EPERM, PLEDGE_RECVFD);
+
+       /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
+       fdp = (int *)CMSG_DATA(cmsg);
+       nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
+           sizeof(struct file *);
+       for (i = 0; i < nfds; i++) {
+               struct vnode *vp;
+
+               fd = *fdp++;
+               fp = fd_getfile(p->p_fd, fd);
+               if (fp == NULL)
+                       return pledge_fail(p, EBADF, PLEDGE_RECVFD);
+
+               /* Only allow passing of sockets, pipes, and pure files */
+               switch (fp->f_type) {
+               case DTYPE_SOCKET:
+               case DTYPE_PIPE:
+                       continue;
+               case DTYPE_VNODE:
+                       vp = (struct vnode *)fp->f_data;
+                       if (vp->v_type == VREG)
+                               continue;
+                       break;
+               default:
+                       break;
+               }
+               return pledge_fail(p, EPERM, PLEDGE_RECVFD);
+       }
+       return (0);
+}
+
+/*
+ * When pledged, default prevents sending of a cmsg.
+ *
+ * Unlike pledge_cmsg_recv pledge_cmsg_send is called with individual
+ * cmsgs one per mbuf. So no need to loop or scan.
+ */
+int
+pledge_cmsg_send(struct proc *p, struct mbuf *control)
+{
+       struct cmsghdr *cmsg;
+       int *fdp, fd;
+       struct file *fp;
+       int nfds, i;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
+               return pledge_fail(p, EPERM, PLEDGE_SENDFD);
+
+       /* Scan the cmsg */
+       cmsg = mtod(control, struct cmsghdr *);
+
+       /* Contains no SCM_RIGHTS, so OK */
+       if (!(cmsg->cmsg_level == SOL_SOCKET &&
+           cmsg->cmsg_type == SCM_RIGHTS))
+               return (0);
+
+       /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
+       fdp = (int *)CMSG_DATA(cmsg);
+       nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
+           sizeof(struct file *);
+       for (i = 0; i < nfds; i++) {
+               struct vnode *vp;
+
+               fd = *fdp++;
+               fp = fd_getfile(p->p_fd, fd);
+               if (fp == NULL)
+                       return pledge_fail(p, EBADF, PLEDGE_SENDFD);
+
+               /* Only allow passing of sockets, pipes, and pure files */
+               switch (fp->f_type) {
+               case DTYPE_SOCKET:
+               case DTYPE_PIPE:
+                       continue;
+               case DTYPE_VNODE:
+                       vp = (struct vnode *)fp->f_data;
+                       if (vp->v_type == VREG)
+                               continue;
+                       break;
+               default:
+                       break;
+               }
+               /* Not allowed to send a bad fd type */
+               return pledge_fail(p, EPERM, PLEDGE_SENDFD);
+       }
+       return (0);
+}
+
+int
+pledge_sysctl_check(struct proc *p, int miblen, int *mib, void *new)
+{
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if (new)
+               return (EFAULT);
+
+       /* routing table observation */
+       if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
+               if (miblen == 7 &&
+                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
+                   mib[2] == 0 &&
+                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
+                   mib[4] == NET_RT_DUMP)
+                       return (0);
+
+               if (miblen == 6 &&
+                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
+                   mib[2] == 0 &&
+                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
+                   mib[4] == NET_RT_TABLE)
+                       return (0);
+
+               if (miblen == 7 &&                      /* exposes MACs */
+                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
+                   mib[2] == 0 && mib[3] == AF_INET &&
+                   mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
+                       return (0);
+       }
+
+       if ((p->p_p->ps_pledge & (PLEDGE_ROUTE | PLEDGE_INET))) {
+               if (miblen == 6 &&              /* getifaddrs() */
+                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
+                   mib[2] == 0 &&
+                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
+                   mib[4] == NET_RT_IFLIST)
+                       return (0);
+       }
+
+       /* used by ntpd(8) to read sensors. */
+       if (miblen >= 3 &&
+           mib[0] == CTL_HW && mib[1] == HW_SENSORS)
+               return (0);
+
+       if (miblen == 2 &&                      /* getdomainname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_DOMAINNAME)
+               return (0);
+       if (miblen == 2 &&                      /* gethostname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_HOSTNAME)
+               return (0);
+       if (miblen == 2 &&                      /* uname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_OSTYPE)
+               return (0);
+       if (miblen == 2 &&                      /* uname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_OSRELEASE)
+               return (0);
+       if (miblen == 2 &&                      /* uname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_OSVERSION)
+               return (0);
+       if (miblen == 2 &&                      /* uname() */
+           mib[0] == CTL_KERN && mib[1] == KERN_VERSION)
+               return (0);
+       if (miblen == 2 &&                      /* uname() */
+           mib[0] == CTL_HW && mib[1] == HW_MACHINE)
+               return (0);
+       if (miblen == 2 &&                      /* getpagesize() */
+           mib[0] == CTL_HW && mib[1] == HW_PAGESIZE)
+               return (0);
+       if (miblen == 2 &&                      /* setproctitle() */
+           mib[0] == CTL_VM && mib[1] == VM_PSSTRINGS)
+               return (0);
+
+       printf("%s(%d): sysctl %d: %d %d %d %d %d %d\n",
+           p->p_comm, p->p_pid, miblen, mib[0], mib[1],
+           mib[2], mib[3], mib[4], mib[5]);
+       return (EFAULT);
+}
+
+int
+pledge_adjtime_check(struct proc *p, const void *v)
+{
+       const struct timeval *delta = v;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if (delta)
+               return (EFAULT);
+       return (0);
+}
+
+int
+pledge_connect_check(struct proc *p)
+{
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE))
+               return (0);     /* A port check happens inside sys_connect() */
+
+       if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
+               return (0);
+       return (EPERM);
+}
+
+int
+pledge_recvfrom_check(struct proc *p, void *v)
+{
+       struct sockaddr *from = v;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && from == NULL)
+               return (0);
+       if (p->p_p->ps_pledge & PLEDGE_INET)
+               return (0);
+       if (p->p_p->ps_pledge & PLEDGE_UNIX)
+               return (0);
+       if (from == NULL)
+               return (0);             /* behaves just like write */
+       return (EPERM);
+}
+
+int
+pledge_sendto_check(struct proc *p, const void *v)
+{
+       const struct sockaddr *to = v;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && to == NULL)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_INET))
+               return (0);
+       if ((p->p_p->ps_pledge & PLEDGE_UNIX))
+               return (0);
+       if (to == NULL)
+               return (0);             /* behaves just like write */
+       return (EPERM);
+}
+
+int
+pledge_socket_check(struct proc *p, int domain)
+{
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+       if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
+               return (0);
+       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) &&
+           (domain == AF_INET || domain == AF_INET6))
+               return (0);
+       return (EPERM);
+}
+
+int
+pledge_bind_check(struct proc *p, const void *v)
+{
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+       if ((p->p_p->ps_pledge & PLEDGE_INET))
+               return (0);
+       return (EPERM);
+}
+
+int
+pledge_ioctl_check(struct proc *p, long com, void *v)
+{
+       struct file *fp = v;
+       struct vnode *vp = NULL;
+
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       /*
+        * The ioctl's which are always allowed.
+        */
+       switch (com) {
+       case FIONREAD:
+       case FIONBIO:
+               return (0);
+       }
+
+       if (fp == NULL)
+               return (EBADF);
+       vp = (struct vnode *)fp->f_data;
+
+       /*
+        * Further sets of ioctl become available, but are checked a
+        * bit more carefully against the vnode.
+        */
+       if ((p->p_p->ps_pledge & PLEDGE_IOCTL)) {
+               switch (com) {
+               case FIOCLEX:
+               case FIONCLEX:
+               case FIOASYNC:
+               case FIOSETOWN:
+               case FIOGETOWN:
+                       return (0);
+               case TIOCGETA:
+               case TIOCGPGRP:
+               case TIOCGWINSZ:        /* various programs */
+                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
+                               return (0);
+                       break;
+               case BIOCGSTATS:        /* bpf: tcpdump privsep on ^C */
+                       if (fp->f_type == DTYPE_VNODE &&
+                           fp->f_ops->fo_ioctl == vn_ioctl)
+                               return (0);
+                       break;
+               case MTIOCGET:
+               case MTIOCTOP:
+                       /* for pax(1) and such, checking tapes... */
+                       if (fp->f_type == DTYPE_VNODE &&
+                           (vp->v_type == VCHR || vp->v_type == VBLK))
+                               return (0);
+                       break;
+               case SIOCGIFGROUP:
+                       if ((p->p_p->ps_pledge & PLEDGE_INET) &&
+                           fp->f_type == DTYPE_SOCKET)
+                               return (0);
+                       break;
+               }
+       }
+
+       if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
+               switch (com) {
+               case SIOCGIFADDR:
+               case SIOCGIFFLAGS:
+               case SIOCGIFRDOMAIN:
+                       if (fp->f_type == DTYPE_SOCKET)
+                               return (0);
+                       break;
+               }
+       }
+
+       if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
+               switch (com) {
+               case TIOCSPGRP:
+                       if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
+                               break;
+                       /* FALTHROUGH */
+               case TIOCGETA:
+               case TIOCGPGRP:
+               case TIOCGWINSZ:        /* various programs */
+#if notyet
+               case TIOCSTI:           /* ksh? csh? */
+#endif
+               case TIOCSBRK:          /* cu */
+               case TIOCCDTR:          /* cu */
+               case TIOCSETA:          /* cu, ... */
+               case TIOCSETAW:         /* cu, ... */
+               case TIOCSETAF:         /* tcsetattr TCSAFLUSH, script */
+                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
+                               return (0);
+                       break;
+               }
+       }
+
+       return pledge_fail(p, EPERM, PLEDGE_IOCTL);
+}
+
+int
+pledge_setsockopt_check(struct proc *p, int level, int optname)
+{
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       /* common case for PLEDGE_UNIX and PLEDGE_INET */
+       switch (level) {
+       case SOL_SOCKET:
+               switch (optname) {
+               case SO_RTABLE:
+                       return (EPERM);
+               }
+               return (0);
+       }
+
+       if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
+               return (EPERM);
+
+       switch (level) {
+       case IPPROTO_TCP:
+               switch (optname) {
+               case TCP_NODELAY:
+               case TCP_MD5SIG:
+               case TCP_SACK_ENABLE:
+               case TCP_MAXSEG:
+               case TCP_NOPUSH:
+                       return (0);
+               }
+               break;
+       case IPPROTO_IP:
+               switch (optname) {
+               case IP_TOS:
+               case IP_TTL:
+               case IP_MINTTL:
+               case IP_PORTRANGE:
+               case IP_RECVDSTADDR:
+                       return (0);
+               case IP_MULTICAST_IF:
+               case IP_ADD_MEMBERSHIP:
+               case IP_DROP_MEMBERSHIP:
+                       if ((p->p_p->ps_pledge & PLEDGE_MCAST) == 0)
+                               return (0);
+                       break;
+               }               
+               break;
+       case IPPROTO_ICMP:
+               break;
+       case IPPROTO_IPV6:
+               switch (optname) {
+               case IPV6_UNICAST_HOPS:
+               case IPV6_RECVHOPLIMIT:
+               case IPV6_PORTRANGE:
+               case IPV6_RECVPKTINFO:
+#ifdef notyet
+               case IPV6_V6ONLY:
+#endif
+                       return (0);
+               case IPV6_MULTICAST_IF:
+               case IPV6_JOIN_GROUP:
+               case IPV6_LEAVE_GROUP:
+                       if ((p->p_p->ps_pledge & PLEDGE_MCAST) == 0)
+                               return (0);
+                       break;
+               }
+               break;
+       case IPPROTO_ICMPV6:
+               break;
+       }
+       return (EPERM);
+}
+
+int
+pledge_dns_check(struct proc *p, in_port_t port)
+{
+       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+               return (0);
+
+       if ((p->p_p->ps_pledge & PLEDGE_INET))
+               return (0);
+       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && port == htons(53))
+               return (0);     /* Allow a DNS connect outbound */
+       return (EPERM);
+}
+
+void
+pledge_dropwpaths(struct process *pr)
+{
+       if (pr->ps_pledgepaths && --pr->ps_pledgepaths->wl_ref == 0) {
+               struct whitepaths *wl = pr->ps_pledgepaths;
+               int i;
+
+               for (i = 0; i < wl->wl_count; i++)
+                       free(wl->wl_paths[i].name, M_TEMP, wl->wl_paths[i].len);
+               free(wl, M_TEMP, wl->wl_size);
+       }
+       pr->ps_pledgepaths = NULL;
+}
+
+int
+canonpath(const char *input, char *buf, size_t bufsize)
+{
+       char *p, *q, *s, *end;
+
+       /* can't canon relative paths, don't bother */
+       if (input[0] != '/') {
+               if (strlcpy(buf, input, bufsize) >= bufsize)
+                       return (ENAMETOOLONG);
+               return (0);
+       }
+
+       /* easiest to work with strings always ending in '/' */
+       if (snprintf(buf, bufsize, "%s/", input) >= bufsize)
+               return (ENAMETOOLONG);
+
+       /* after this we will only be shortening the string. */
+       p = buf;
+       q = p;
+       while (*p) {
+               if (p[0] == '/' && p[1] == '/') {
+                       p += 1;
+               } else if (p[0] == '/' && p[1] == '.' &&
+                   p[2] == '/') {
+                       p += 2;
+               } else {
+                       *q++ = *p++;
+               }
+       }
+       *q = 0;
+
+       end = buf + strlen(buf);
+       s = buf;
+       p = s;
+       while (1) {
+               /* find "/../" (where's strstr when you need it?) */
+               while (p < end) {
+                       if (p[0] == '/' && strncmp(p + 1, "../", 3) == 0)
+                               break;
+                       p++;
+               }
+               if (p == end)
+                       break;
+               if (p == s) {
+                       memmove(s, p + 3, end - p - 3 + 1);
+                       end -= 3;
+               } else {
+                       /* s starts with '/', so we know there's one
+                        * somewhere before p. */
+                       q = p - 1;
+                       while (*q != '/')
+                               q--;
+                       memmove(q, p + 3, end - p - 3 + 1);
+                       end -= p + 3 - q;
+                       p = q;
+               }
+       }
+       if (end > s + 1)
+               *(end - 1) = 0; /* remove trailing '/' */
+
+       return 0;
+}
diff --git a/sys/kern/kern_tame.c b/sys/kern/kern_tame.c
deleted file mode 100644 (file)
index 3ccb099..0000000
+++ /dev/null
@@ -1,1241 +0,0 @@
-/*     $OpenBSD: kern_tame.c,v 1.71 2015/10/09 01:10:27 deraadt Exp $  */
-
-/*
- * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
- * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/types.h>
-
-#include <sys/mount.h>
-#include <sys/proc.h>
-#include <sys/fcntl.h>
-#include <sys/file.h>
-#include <sys/filedesc.h>
-#include <sys/vnode.h>
-#include <sys/mbuf.h>
-#include <sys/sysctl.h>
-#include <sys/ktrace.h>
-
-#include <sys/ioctl.h>
-#include <sys/termios.h>
-#include <sys/mtio.h>
-#include <net/bpf.h>
-#include <net/route.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <sys/signal.h>
-#include <sys/signalvar.h>
-#include <sys/syscall.h>
-#include <sys/syscallargs.h>
-#include <sys/systm.h>
-#include <sys/pledge.h>
-
-int canonpath(const char *input, char *buf, size_t bufsize);
-
-const u_int pledge_syscalls[SYS_MAXSYSCALL] = {
-       [SYS_exit] = 0xffffffff,
-       [SYS_kbind] = 0xffffffff,
-
-       [SYS_getuid] = PLEDGE_SELF,
-       [SYS_geteuid] = PLEDGE_SELF,
-       [SYS_getresuid] = PLEDGE_SELF,
-       [SYS_getgid] = PLEDGE_SELF,
-       [SYS_getegid] = PLEDGE_SELF,
-       [SYS_getresgid] = PLEDGE_SELF,
-       [SYS_getgroups] = PLEDGE_SELF,
-       [SYS_getlogin] = PLEDGE_SELF,
-       [SYS_getpgrp] = PLEDGE_SELF,
-       [SYS_getpgid] = PLEDGE_SELF,
-       [SYS_getppid] = PLEDGE_SELF,
-       [SYS_getsid] = PLEDGE_SELF,
-       [SYS_getthrid] = PLEDGE_SELF,
-       [SYS_getrlimit] = PLEDGE_SELF,
-       [SYS_gettimeofday] = PLEDGE_SELF,
-       [SYS_getdtablecount] = PLEDGE_SELF,
-       [SYS_getrusage] = PLEDGE_SELF,
-       [SYS_issetugid] = PLEDGE_SELF,
-       [SYS_clock_getres] = PLEDGE_SELF,
-       [SYS_clock_gettime] = PLEDGE_SELF,
-       [SYS_getpid] = PLEDGE_SELF,
-       [SYS_umask] = PLEDGE_SELF,
-       [SYS_sysctl] = PLEDGE_SELF,     /* read-only; narrow subset */
-       [SYS_adjtime] = PLEDGE_SELF,    /* read-only */
-
-       [SYS_fchdir] = PLEDGE_SELF,     /* careful of directory fd inside jails */
-
-       /* needed by threaded programs */
-       [SYS_sched_yield] = PLEDGE_SELF,
-       [SYS___thrsleep] = PLEDGE_SELF,
-       [SYS___thrwakeup] = PLEDGE_SELF,
-       [SYS___threxit] = PLEDGE_SELF,
-       [SYS___thrsigdivert] = PLEDGE_SELF,
-
-       [SYS_sendsyslog] = PLEDGE_SELF,
-       [SYS_nanosleep] = PLEDGE_SELF,
-       [SYS_sigprocmask] = PLEDGE_SELF,
-       [SYS_sigaction] = PLEDGE_SELF,
-       [SYS_sigreturn] = PLEDGE_SELF,
-       [SYS_sigpending] = PLEDGE_SELF,
-       [SYS_getitimer] = PLEDGE_SELF,
-       [SYS_setitimer] = PLEDGE_SELF,
-
-       [SYS_pledge] = PLEDGE_SELF,
-
-       [SYS_wait4] = PLEDGE_SELF,
-
-       [SYS_poll] = PLEDGE_RW,
-       [SYS_kevent] = PLEDGE_RW,
-       [SYS_kqueue] = PLEDGE_RW,
-       [SYS_select] = PLEDGE_RW,
-
-       [SYS_close] = PLEDGE_RW,
-       [SYS_dup] = PLEDGE_RW,
-       [SYS_dup2] = PLEDGE_RW,
-       [SYS_dup3] = PLEDGE_RW,
-       [SYS_closefrom] = PLEDGE_RW,
-       [SYS_shutdown] = PLEDGE_RW,
-       [SYS_read] = PLEDGE_RW,
-       [SYS_readv] = PLEDGE_RW,
-       [SYS_pread] = PLEDGE_RW,
-       [SYS_preadv] = PLEDGE_RW,
-       [SYS_write] = PLEDGE_RW,
-       [SYS_writev] = PLEDGE_RW,
-       [SYS_pwrite] = PLEDGE_RW,
-       [SYS_pwritev] = PLEDGE_RW,
-       [SYS_ftruncate] = PLEDGE_RW,
-       [SYS_lseek] = PLEDGE_RW,
-       [SYS_fstat] = PLEDGE_RW,
-
-       [SYS_fcntl] = PLEDGE_RW,
-       [SYS_fsync] = PLEDGE_RW,
-       [SYS_pipe] = PLEDGE_RW,
-       [SYS_pipe2] = PLEDGE_RW,
-       [SYS_socketpair] = PLEDGE_RW,
-       [SYS_getdents] = PLEDGE_RW,
-
-       [SYS_sendto] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
-       [SYS_sendmsg] = PLEDGE_RW,
-       [SYS_recvmsg] = PLEDGE_RW,
-       [SYS_recvfrom] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
-
-       [SYS_fork] = PLEDGE_PROC,
-       [SYS_vfork] = PLEDGE_PROC,
-       [SYS_kill] = PLEDGE_PROC,
-       [SYS_setpgid] = PLEDGE_PROC,
-       [SYS_sigsuspend] = PLEDGE_PROC,
-       [SYS_setrlimit] = PLEDGE_PROC,
-
-       [SYS_execve] = PLEDGE_EXEC,
-
-       [SYS_setgroups] = PLEDGE_PROC,
-       [SYS_setresgid] = PLEDGE_PROC,
-       [SYS_setresuid] = PLEDGE_PROC,
-
-       /* FIONREAD/FIONBIO, plus further checks in pledge_ioctl_check() */
-       [SYS_ioctl] = PLEDGE_RW | PLEDGE_IOCTL | PLEDGE_TTY,
-
-       [SYS_getentropy] = PLEDGE_MALLOC,
-       [SYS_madvise] = PLEDGE_MALLOC,
-       [SYS_minherit] = PLEDGE_MALLOC,
-       [SYS_mmap] = PLEDGE_MALLOC,
-       [SYS_mprotect] = PLEDGE_MALLOC,
-       [SYS_mquery] = PLEDGE_MALLOC,
-       [SYS_munmap] = PLEDGE_MALLOC,
-
-       [SYS_open] = PLEDGE_SELF,                       /* further checks in namei */
-       [SYS_stat] = PLEDGE_SELF,                       /* further checks in namei */
-       [SYS_access] = PLEDGE_SELF,             /* further checks in namei */
-       [SYS_readlink] = PLEDGE_SELF,           /* further checks in namei */
-
-       [SYS_chdir] = PLEDGE_RPATH,
-       [SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
-       [SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
-       [SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
-       [SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
-       [SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
-       [SYS_rename] = PLEDGE_CPATH,
-       [SYS_rmdir] = PLEDGE_CPATH,
-       [SYS_renameat] = PLEDGE_CPATH,
-       [SYS_link] = PLEDGE_CPATH,
-       [SYS_linkat] = PLEDGE_CPATH,
-       [SYS_symlink] = PLEDGE_CPATH,
-       [SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
-       [SYS_unlinkat] = PLEDGE_CPATH,
-       [SYS_mkdir] = PLEDGE_CPATH,
-       [SYS_mkdirat] = PLEDGE_CPATH,
-
-       /*
-        * Classify as RPATH|WPATH, because of path information leakage.
-        * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
-        */
-       [SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
-
-       /* Classify as RPATH, because these leak path information */
-       [SYS_getfsstat] = PLEDGE_RPATH,
-       [SYS_statfs] = PLEDGE_RPATH,
-       [SYS_fstatfs] = PLEDGE_RPATH,
-
-       [SYS_utimes] = PLEDGE_FATTR,
-       [SYS_futimes] = PLEDGE_FATTR,
-       [SYS_utimensat] = PLEDGE_FATTR,
-       [SYS_futimens] = PLEDGE_FATTR,
-       [SYS_chmod] = PLEDGE_FATTR,
-       [SYS_fchmod] = PLEDGE_FATTR,
-       [SYS_fchmodat] = PLEDGE_FATTR,
-       [SYS_chflags] = PLEDGE_FATTR,
-       [SYS_chflagsat] = PLEDGE_FATTR,
-       [SYS_chown] = PLEDGE_FATTR,
-       [SYS_fchownat] = PLEDGE_FATTR,
-       [SYS_lchown] = PLEDGE_FATTR,
-       [SYS_fchown] = PLEDGE_FATTR,
-
-       [SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
-       [SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
-
-       [SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_bind] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_setsockopt] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_getsockopt] = PLEDGE_INET | PLEDGE_UNIX,
-
-       [SYS_flock] = PLEDGE_GETPW,
-};
-
-static const struct {
-       char *name;
-       int flags;
-} pledgereq[] = {
-       { "malloc",             PLEDGE_SELF | PLEDGE_MALLOC },
-       { "rw",                 PLEDGE_SELF | PLEDGE_RW },
-       { "stdio",              PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_RW },
-       { "rpath",              PLEDGE_SELF | PLEDGE_RW | PLEDGE_RPATH },
-       { "wpath",              PLEDGE_SELF | PLEDGE_RW | PLEDGE_WPATH },
-       { "tmppath",            PLEDGE_SELF | PLEDGE_RW | PLEDGE_TMPPATH },
-       { "inet",               PLEDGE_SELF | PLEDGE_RW | PLEDGE_INET },
-       { "unix",               PLEDGE_SELF | PLEDGE_RW | PLEDGE_UNIX },
-       { "dns",                PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_DNSPATH },
-       { "getpw",              PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_RW | PLEDGE_GETPW },
-/*X*/  { "cmsg",               PLEDGE_UNIX | PLEDGE_INET | PLEDGE_SENDFD | PLEDGE_RECVFD },
-       { "sendfd",             PLEDGE_RW | PLEDGE_SENDFD },
-       { "recvfd",             PLEDGE_RW | PLEDGE_RECVFD },
-       { "ioctl",              PLEDGE_IOCTL },
-       { "route",              PLEDGE_ROUTE },
-       { "mcast",              PLEDGE_MCAST },
-       { "tty",                PLEDGE_TTY },
-       { "proc",               PLEDGE_PROC },
-       { "exec",               PLEDGE_EXEC },
-       { "cpath",              PLEDGE_CPATH },
-       { "abort",              PLEDGE_ABORT },
-       { "fattr",              PLEDGE_FATTR },
-       { "prot_exec",          PLEDGE_PROTEXEC },
-};
-
-int
-sys_pledge(struct proc *p, void *v, register_t *retval)
-{
-       struct sys_pledge_args /* {
-               syscallarg(const char *)request;
-               syscallarg(const char **)paths;
-       } */    *uap = v;
-       int flags = 0;
-       int error;
-
-       if (SCARG(uap, request)) {
-               size_t rbuflen;
-               char *rbuf, *rp, *pn;
-               int f, i;
-
-               rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-               error = copyinstr(SCARG(uap, request), rbuf, MAXPATHLEN,
-                   &rbuflen);
-               if (error) {
-                       free(rbuf, M_TEMP, MAXPATHLEN);
-                       return (error);
-               }
-#ifdef KTRACE
-               if (KTRPOINT(p, KTR_STRUCT))
-                       ktrstruct(p, "pledgereq", rbuf, rbuflen-1);
-#endif
-
-               for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
-                       pn = strchr(rp, ' ');   /* find terminator */
-                       if (pn) {
-                               while (*pn == ' ')
-                                       *pn++ = '\0';
-                       }
-
-                       for (f = i = 0; i < nitems(pledgereq); i++) {
-                               if (strcmp(rp, pledgereq[i].name) == 0) {
-                                       f = pledgereq[i].flags;
-                                       break;
-                               }
-                       }
-                       if (f == 0) {
-                               free(rbuf, M_TEMP, MAXPATHLEN);
-                               return (EINVAL);
-                       }
-                       flags |= f;
-               }
-               free(rbuf, M_TEMP, MAXPATHLEN);
-       }
-
-       if (flags & ~PLEDGE_USERSET)
-               return (EINVAL);
-
-       if ((p->p_p->ps_flags & PS_PLEDGE)) {
-               /* Already pledged, only allow reductions */
-               if (((flags | p->p_p->ps_pledge) & PLEDGE_USERSET) !=
-                   (p->p_p->ps_pledge & PLEDGE_USERSET)) {
-                       return (EPERM);
-               }
-
-               flags &= p->p_p->ps_pledge;
-               flags &= PLEDGE_USERSET;                /* Relearn _ACTIVE */
-       }
-
-       if (SCARG(uap, paths)) {
-               const char **u = SCARG(uap, paths), *sp;
-               struct whitepaths *wl;
-               char *cwdpath = NULL, *path;
-               size_t cwdpathlen = MAXPATHLEN * 4, cwdlen, len, maxargs = 0;
-               int i, error;
-
-               if (p->p_p->ps_pledgepaths)
-                       return (EPERM);
-
-               /* Count paths */
-               for (i = 0; i < PLEDGE_MAXPATHS; i++) {
-                       if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
-                               return (error);
-                       if (sp == NULL)
-                               break;
-               }
-               if (i == PLEDGE_MAXPATHS)
-                       return (E2BIG);
-
-               wl = malloc(sizeof *wl + sizeof(struct whitepath) * (i+1),
-                   M_TEMP, M_WAITOK | M_ZERO);
-               wl->wl_size = sizeof *wl + sizeof(struct whitepath) * (i+1);
-               wl->wl_count = i;
-               wl->wl_ref = 1;
-
-               path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-
-               /* Copy in */
-               for (i = 0; i < wl->wl_count; i++) {
-                       char *fullpath = NULL, *builtpath = NULL, *canopath = NULL, *cwd;
-                       size_t builtlen = 0;
-
-                       if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
-                               break;
-                       if (sp == NULL)
-                               break;
-                       if ((error = copyinstr(sp, path, MAXPATHLEN, &len)) != 0)
-                               break;
-#ifdef KTRACE
-                       if (KTRPOINT(p, KTR_STRUCT))
-                               ktrstruct(p, "pledgepath", path, len-1);
-#endif
-
-                       /* If path is relative, prepend cwd */
-                       if (path[0] != '/') {
-                               if (cwdpath == NULL) {
-                                       char *bp, *bpend;
-
-                                       cwdpath = malloc(cwdpathlen, M_TEMP, M_WAITOK);
-                                       bp = &cwdpath[cwdpathlen];
-                                       bpend = bp;
-                                       *(--bp) = '\0';
-
-                                       error = vfs_getcwd_common(p->p_fd->fd_cdir,
-                                           NULL, &bp, cwdpath, cwdpathlen/2,
-                                           GETCWD_CHECK_ACCESS, p);
-                                       if (error)
-                                               break;
-                                       cwd = bp;
-                                       cwdlen = (bpend - bp);
-                               }
-
-                               /* NUL included in cwd component */
-                               builtlen = cwdlen + 1 + strlen(path);
-                               if (builtlen > PATH_MAX) {
-                                       error = ENAMETOOLONG;
-                                       break;
-                               }
-                               builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
-                               snprintf(builtpath, builtlen, "%s/%s", cwd, path);
-                               // printf("pledge: builtpath = %s\n", builtpath);
-                               fullpath = builtpath;
-                       } else
-                               fullpath = path;
-
-                       canopath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-                       error = canonpath(fullpath, canopath, MAXPATHLEN);
-
-                       free(builtpath, M_TEMP, builtlen);
-                       if (error != 0) {
-                               free(canopath, M_TEMP, MAXPATHLEN);
-                               break;
-                       }
-
-                       len = strlen(canopath) + 1;
-
-                       //printf("pledge: canopath = %s %lld strlen %lld\n", canopath,
-                       //    (long long)len, (long long)strlen(canopath));
-
-                       if (maxargs += len > ARG_MAX) {
-                               error = E2BIG;
-                               break;
-                       }
-                       wl->wl_paths[i].name = malloc(len, M_TEMP, M_WAITOK);
-                       memcpy(wl->wl_paths[i].name, canopath, len);
-                       wl->wl_paths[i].len = len;
-                       free(canopath, M_TEMP, MAXPATHLEN);
-               }
-               free(path, M_TEMP, MAXPATHLEN);
-               free(cwdpath, M_TEMP, cwdpathlen);
-
-               if (error) {
-                       for (i = 0; i < wl->wl_count; i++)
-                               free(wl->wl_paths[i].name,
-                                   M_TEMP, wl->wl_paths[i].len);
-                       free(wl, M_TEMP, wl->wl_size);
-                       return (error);
-               }
-               p->p_p->ps_pledgepaths = wl;
-#if 0
-               printf("pledge: %s(%d): paths loaded:\n", p->p_comm, p->p_pid);
-               for (i = 0; i < wl->wl_count; i++)
-                       if (wl->wl_paths[i].name)
-                               printf("pledge: %d=%s %lld\n", i, wl->wl_paths[i].name,
-                                   (long long)wl->wl_paths[i].len);
-#endif
-       }
-
-       p->p_p->ps_pledge = flags;
-       p->p_p->ps_flags |= PS_PLEDGE;
-       return (0);
-}
-
-int
-pledge_check(struct proc *p, int code)
-{
-       p->p_pledgenote = p->p_pledgeafter = 0; /* XX optimise? */
-       p->p_pledge_syscall = code;
-
-       if (code < 0 || code > SYS_MAXSYSCALL - 1)
-               return (0);
-
-       if (p->p_p->ps_pledge == 0)
-               return (code == SYS_exit || code == SYS_kbind);
-       return (p->p_p->ps_pledge & pledge_syscalls[code]);
-}
-
-int
-pledge_fail(struct proc *p, int error, int code)
-{
-       printf("%s(%d): syscall %d\n", p->p_comm, p->p_pid, p->p_pledge_syscall);
-       if (p->p_p->ps_pledge & PLEDGE_ABORT) { /* Core dump requested */
-               struct sigaction sa;
-
-               memset(&sa, 0, sizeof sa);
-               sa.sa_handler = SIG_DFL;
-               setsigvec(p, SIGABRT, &sa);
-               psignal(p, SIGABRT);
-       } else
-               psignal(p, SIGKILL);
-
-       p->p_p->ps_pledge = 0;          /* Disable all PLEDGE_ flags */
-       return (error);
-}
-
-/*
- * Need to make it more obvious that one cannot get through here
- * without the right flags set
- */
-int
-pledge_namei(struct proc *p, char *origpath)
-{
-       char path[PATH_MAX];
-
-       if (p->p_pledgenote == TMN_COREDUMP)
-               return (0);                     /* Allow a coredump */
-
-       if (canonpath(origpath, path, sizeof(path)) != 0)
-               return (pledge_fail(p, EPERM, PLEDGE_RPATH));
-
-       if ((p->p_pledgenote & TMN_FATTR) &&
-           (p->p_p->ps_pledge & PLEDGE_FATTR) == 0) {
-               printf("%s(%d): inode syscall%d, not allowed\n",
-                   p->p_comm, p->p_pid, p->p_pledge_syscall);
-               return (pledge_fail(p, EPERM, PLEDGE_FATTR));
-       }
-
-       /* Detect what looks like a mkstemp(3) family operation */
-       if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
-           (p->p_pledge_syscall == SYS_open) &&
-           (p->p_pledgenote & TMN_CPATH) &&
-           strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
-               return (0);
-       }
-
-       /* Allow unlinking of a mkstemp(3) file...
-        * Good opportunity for strict checks here.
-        */
-       if ((p->p_p->ps_pledge & PLEDGE_TMPPATH) &&
-           (p->p_pledge_syscall == SYS_unlink) &&
-           strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
-               return (0);
-       }
-
-       /* open, mkdir, or other path creation operation */
-       if ((p->p_pledgenote & TMN_CPATH) &&
-           ((p->p_p->ps_pledge & PLEDGE_CPATH) == 0))
-               return (pledge_fail(p, EPERM, PLEDGE_CPATH));
-
-       if ((p->p_pledgenote & TMN_WPATH) &&
-           (p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
-               return (pledge_fail(p, EPERM, PLEDGE_WPATH));
-
-       /* Read-only paths used occasionally by libc */
-       switch (p->p_pledge_syscall) {
-       case SYS_access:
-               /* tzset() needs this. */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   strcmp(path, "/etc/localtime") == 0)
-                       return (0);
-               break;
-       case SYS_open:
-               /* getpw* and friends need a few files */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   (p->p_p->ps_pledge & PLEDGE_GETPW)) {
-                       if (strcmp(path, "/etc/spwd.db") == 0)
-                               return (EPERM);
-                       if (strcmp(path, "/etc/pwd.db") == 0)
-                               return (0);
-                       if (strcmp(path, "/etc/group") == 0)
-                               return (0);
-               }
-
-               /* DNS needs /etc/{resolv.conf,hosts,services}. */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
-                       if (strcmp(path, "/etc/resolv.conf") == 0) {
-                               p->p_pledgeafter |= TMA_DNSRESOLV;
-                               return (0);
-                       }
-                       if (strcmp(path, "/etc/hosts") == 0)
-                               return (0);
-                       if (strcmp(path, "/etc/services") == 0)
-                               return (0);
-               }
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   (p->p_p->ps_pledge & PLEDGE_GETPW)) {
-                       if (strcmp(path, "/var/run/ypbind.lock") == 0) {
-                               p->p_pledgeafter |= TMA_YPLOCK;
-                               return (0);
-                       }
-                       if (strncmp(path, "/var/yp/binding/",
-                           sizeof("/var/yp/binding/") - 1) == 0)
-                               return (0);
-               }
-               /* tzset() needs these. */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   strncmp(path, "/usr/share/zoneinfo/",
-                   sizeof("/usr/share/zoneinfo/") - 1) == 0)
-                       return (0);
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   strcmp(path, "/etc/localtime") == 0)
-                       return (0);
-
-               /* /usr/share/nls/../libc.cat has to succeed for strerror(3). */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   strncmp(path, "/usr/share/nls/",
-                   sizeof("/usr/share/nls/") - 1) == 0 &&
-                   strcmp(path + strlen(path) - 9, "/libc.cat") == 0)
-                       return (0);
-               break;
-       case SYS_readlink:
-               /* Allow /etc/malloc.conf for malloc(3). */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   strcmp(path, "/etc/malloc.conf") == 0)
-                       return (0);
-               break;
-       case SYS_stat:
-               /* DNS needs /etc/resolv.conf. */
-               if ((p->p_pledgenote == TMN_RPATH) &&
-                   (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
-                       if (strcmp(path, "/etc/resolv.conf") == 0) {
-                               p->p_pledgeafter |= TMA_DNSRESOLV;
-                               return (0);
-                       }
-               }
-               break;
-       }
-
-       /*
-        * If a whitelist is set, compare canonical paths.  Anything
-        * not on the whitelist gets ENOENT.
-        */
-       if (p->p_p->ps_pledgepaths) {
-               struct whitepaths *wl = p->p_p->ps_pledgepaths;
-               char *fullpath, *builtpath = NULL, *canopath = NULL;
-               size_t builtlen = 0;
-               int i, error;
-
-               if (origpath[0] != '/') {
-                       char *cwdpath, *cwd, *bp, *bpend;
-                       size_t cwdpathlen = MAXPATHLEN * 4, cwdlen;
-
-                       cwdpath = malloc(cwdpathlen, M_TEMP, M_WAITOK);
-                       bp = &cwdpath[cwdpathlen];
-                       bpend = bp;
-                       *(--bp) = '\0';
-
-                       error = vfs_getcwd_common(p->p_fd->fd_cdir,
-                           NULL, &bp, cwdpath, cwdpathlen/2,
-                           GETCWD_CHECK_ACCESS, p);
-                       if (error) {
-                               free(cwdpath, M_TEMP, cwdpathlen);
-                               return (error);
-                       }
-                       cwd = bp;
-                       cwdlen = (bpend - bp);
-
-                       /* NUL included in cwd component */
-                       builtlen = cwdlen + 1 + strlen(origpath);
-                       builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
-                       snprintf(builtpath, builtlen, "%s/%s", cwd, origpath);
-                       fullpath = builtpath;
-                       free(cwdpath, M_TEMP, cwdpathlen);
-
-                       //printf("namei: builtpath = %s %lld strlen %lld\n", builtpath,
-                       //    (long long)builtlen, (long long)strlen(builtpath));
-               } else
-                       fullpath = path;
-
-               canopath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-               error = canonpath(fullpath, canopath, MAXPATHLEN);
-
-               free(builtpath, M_TEMP, builtlen);
-               if (error != 0) {
-                       free(canopath, M_TEMP, MAXPATHLEN);
-                       return (pledge_fail(p, EPERM, PLEDGE_RPATH));
-               }
-
-               //printf("namei: canopath = %s strlen %lld\n", canopath,
-               //    (long long)strlen(canopath));
-
-               error = ENOENT;
-               for (i = 0; i < wl->wl_count && wl->wl_paths[i].name && error; i++) {
-                       if (strncmp(canopath, wl->wl_paths[i].name,
-                           wl->wl_paths[i].len - 1) == 0) {
-                               u_char term = canopath[wl->wl_paths[i].len - 1];
-
-                               if (term == '\0' || term == '/' ||
-                                   wl->wl_paths[i].name[1] == '\0')
-                                       error = 0;
-                       }
-               }
-               free(canopath, M_TEMP, MAXPATHLEN);
-               return (error);                 /* Don't hint why it failed */
-       }
-
-       if (p->p_p->ps_pledge & PLEDGE_RPATH)
-               return (0);
-       if (p->p_p->ps_pledge & PLEDGE_WPATH)
-               return (0);
-       if (p->p_p->ps_pledge & PLEDGE_CPATH)
-               return (0);
-
-       return (pledge_fail(p, EPERM, PLEDGE_RPATH));
-}
-
-void
-pledge_aftersyscall(struct proc *p, int code, int error)
-{
-       if ((p->p_pledgeafter & TMA_YPLOCK) && error == 0)
-               atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_YP_ACTIVE | PLEDGE_INET);
-       if ((p->p_pledgeafter & TMA_DNSRESOLV) && error == 0)
-               atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_DNS_ACTIVE);
-}
-
-/*
- * By default, only the advisory cmsg's can be received from the kernel,
- * such as TIMESTAMP ntpd.
- *
- * If PLEDGE_RECVFD is set SCM_RIGHTS is also allowed in for a carefully
- * selected set of descriptors (specifically to exclude directories).
- *
- * This results in a kill upon recv, if some other process on the system
- * send a SCM_RIGHTS to an open socket of some sort.  That will discourage
- * leaving such sockets lying around...
- */
-int
-pledge_cmsg_recv(struct proc *p, struct mbuf *control)
-{
-       struct msghdr tmp;
-       struct cmsghdr *cmsg;
-       int *fdp, fd;
-       struct file *fp;
-       int nfds, i;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       /* Scan the cmsg */
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.msg_control = mtod(control, struct cmsghdr *);
-       tmp.msg_controllen = control->m_len;
-       cmsg = CMSG_FIRSTHDR(&tmp);
-
-       while (cmsg != NULL) {
-               if (cmsg->cmsg_level == SOL_SOCKET &&
-                   cmsg->cmsg_type == SCM_RIGHTS)
-                       break;
-               cmsg = CMSG_NXTHDR(&tmp, cmsg);
-       }
-
-       /* No SCM_RIGHTS found -> OK */
-       if (cmsg == NULL)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_RECVFD) == 0)
-               return pledge_fail(p, EPERM, PLEDGE_RECVFD);
-
-       /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
-       fdp = (int *)CMSG_DATA(cmsg);
-       nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
-           sizeof(struct file *);
-       for (i = 0; i < nfds; i++) {
-               struct vnode *vp;
-
-               fd = *fdp++;
-               fp = fd_getfile(p->p_fd, fd);
-               if (fp == NULL)
-                       return pledge_fail(p, EBADF, PLEDGE_RECVFD);
-
-               /* Only allow passing of sockets, pipes, and pure files */
-               switch (fp->f_type) {
-               case DTYPE_SOCKET:
-               case DTYPE_PIPE:
-                       continue;
-               case DTYPE_VNODE:
-                       vp = (struct vnode *)fp->f_data;
-                       if (vp->v_type == VREG)
-                               continue;
-                       break;
-               default:
-                       break;
-               }
-               return pledge_fail(p, EPERM, PLEDGE_RECVFD);
-       }
-       return (0);
-}
-
-/*
- * When pledged, default prevents sending of a cmsg.
- *
- * Unlike pledge_cmsg_recv pledge_cmsg_send is called with individual
- * cmsgs one per mbuf. So no need to loop or scan.
- */
-int
-pledge_cmsg_send(struct proc *p, struct mbuf *control)
-{
-       struct cmsghdr *cmsg;
-       int *fdp, fd;
-       struct file *fp;
-       int nfds, i;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_SENDFD) == 0)
-               return pledge_fail(p, EPERM, PLEDGE_SENDFD);
-
-       /* Scan the cmsg */
-       cmsg = mtod(control, struct cmsghdr *);
-
-       /* Contains no SCM_RIGHTS, so OK */
-       if (!(cmsg->cmsg_level == SOL_SOCKET &&
-           cmsg->cmsg_type == SCM_RIGHTS))
-               return (0);
-
-       /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
-       fdp = (int *)CMSG_DATA(cmsg);
-       nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
-           sizeof(struct file *);
-       for (i = 0; i < nfds; i++) {
-               struct vnode *vp;
-
-               fd = *fdp++;
-               fp = fd_getfile(p->p_fd, fd);
-               if (fp == NULL)
-                       return pledge_fail(p, EBADF, PLEDGE_SENDFD);
-
-               /* Only allow passing of sockets, pipes, and pure files */
-               switch (fp->f_type) {
-               case DTYPE_SOCKET:
-               case DTYPE_PIPE:
-                       continue;
-               case DTYPE_VNODE:
-                       vp = (struct vnode *)fp->f_data;
-                       if (vp->v_type == VREG)
-                               continue;
-                       break;
-               default:
-                       break;
-               }
-               /* Not allowed to send a bad fd type */
-               return pledge_fail(p, EPERM, PLEDGE_SENDFD);
-       }
-       return (0);
-}
-
-int
-pledge_sysctl_check(struct proc *p, int miblen, int *mib, void *new)
-{
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if (new)
-               return (EFAULT);
-
-       /* routing table observation */
-       if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
-               if (miblen == 7 &&
-                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
-                   mib[2] == 0 &&
-                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
-                   mib[4] == NET_RT_DUMP)
-                       return (0);
-
-               if (miblen == 6 &&
-                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
-                   mib[2] == 0 &&
-                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
-                   mib[4] == NET_RT_TABLE)
-                       return (0);
-
-               if (miblen == 7 &&                      /* exposes MACs */
-                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
-                   mib[2] == 0 && mib[3] == AF_INET &&
-                   mib[4] == NET_RT_FLAGS && mib[5] == RTF_LLINFO)
-                       return (0);
-       }
-
-       if ((p->p_p->ps_pledge & (PLEDGE_ROUTE | PLEDGE_INET))) {
-               if (miblen == 6 &&              /* getifaddrs() */
-                   mib[0] == CTL_NET && mib[1] == PF_ROUTE &&
-                   mib[2] == 0 &&
-                   (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) &&
-                   mib[4] == NET_RT_IFLIST)
-                       return (0);
-       }
-
-       /* used by ntpd(8) to read sensors. */
-       if (miblen >= 3 &&
-           mib[0] == CTL_HW && mib[1] == HW_SENSORS)
-               return (0);
-
-       if (miblen == 2 &&                      /* getdomainname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_DOMAINNAME)
-               return (0);
-       if (miblen == 2 &&                      /* gethostname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_HOSTNAME)
-               return (0);
-       if (miblen == 2 &&                      /* uname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_OSTYPE)
-               return (0);
-       if (miblen == 2 &&                      /* uname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_OSRELEASE)
-               return (0);
-       if (miblen == 2 &&                      /* uname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_OSVERSION)
-               return (0);
-       if (miblen == 2 &&                      /* uname() */
-           mib[0] == CTL_KERN && mib[1] == KERN_VERSION)
-               return (0);
-       if (miblen == 2 &&                      /* uname() */
-           mib[0] == CTL_HW && mib[1] == HW_MACHINE)
-               return (0);
-       if (miblen == 2 &&                      /* getpagesize() */
-           mib[0] == CTL_HW && mib[1] == HW_PAGESIZE)
-               return (0);
-       if (miblen == 2 &&                      /* setproctitle() */
-           mib[0] == CTL_VM && mib[1] == VM_PSSTRINGS)
-               return (0);
-
-       printf("%s(%d): sysctl %d: %d %d %d %d %d %d\n",
-           p->p_comm, p->p_pid, miblen, mib[0], mib[1],
-           mib[2], mib[3], mib[4], mib[5]);
-       return (EFAULT);
-}
-
-int
-pledge_adjtime_check(struct proc *p, const void *v)
-{
-       const struct timeval *delta = v;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if (delta)
-               return (EFAULT);
-       return (0);
-}
-
-int
-pledge_connect_check(struct proc *p)
-{
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE))
-               return (0);     /* A port check happens inside sys_connect() */
-
-       if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
-               return (0);
-       return (EPERM);
-}
-
-int
-pledge_recvfrom_check(struct proc *p, void *v)
-{
-       struct sockaddr *from = v;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && from == NULL)
-               return (0);
-       if (p->p_p->ps_pledge & PLEDGE_INET)
-               return (0);
-       if (p->p_p->ps_pledge & PLEDGE_UNIX)
-               return (0);
-       if (from == NULL)
-               return (0);             /* behaves just like write */
-       return (EPERM);
-}
-
-int
-pledge_sendto_check(struct proc *p, const void *v)
-{
-       const struct sockaddr *to = v;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && to == NULL)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_INET))
-               return (0);
-       if ((p->p_p->ps_pledge & PLEDGE_UNIX))
-               return (0);
-       if (to == NULL)
-               return (0);             /* behaves just like write */
-       return (EPERM);
-}
-
-int
-pledge_socket_check(struct proc *p, int domain)
-{
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-       if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
-               return (0);
-       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) &&
-           (domain == AF_INET || domain == AF_INET6))
-               return (0);
-       return (EPERM);
-}
-
-int
-pledge_bind_check(struct proc *p, const void *v)
-{
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-       if ((p->p_p->ps_pledge & PLEDGE_INET))
-               return (0);
-       return (EPERM);
-}
-
-int
-pledge_ioctl_check(struct proc *p, long com, void *v)
-{
-       struct file *fp = v;
-       struct vnode *vp = NULL;
-
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       /*
-        * The ioctl's which are always allowed.
-        */
-       switch (com) {
-       case FIONREAD:
-       case FIONBIO:
-               return (0);
-       }
-
-       if (fp == NULL)
-               return (EBADF);
-       vp = (struct vnode *)fp->f_data;
-
-       /*
-        * Further sets of ioctl become available, but are checked a
-        * bit more carefully against the vnode.
-        */
-       if ((p->p_p->ps_pledge & PLEDGE_IOCTL)) {
-               switch (com) {
-               case FIOCLEX:
-               case FIONCLEX:
-               case FIOASYNC:
-               case FIOSETOWN:
-               case FIOGETOWN:
-                       return (0);
-               case TIOCGETA:
-               case TIOCGPGRP:
-               case TIOCGWINSZ:        /* various programs */
-                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
-                               return (0);
-                       break;
-               case BIOCGSTATS:        /* bpf: tcpdump privsep on ^C */
-                       if (fp->f_type == DTYPE_VNODE &&
-                           fp->f_ops->fo_ioctl == vn_ioctl)
-                               return (0);
-                       break;
-               case MTIOCGET:
-               case MTIOCTOP:
-                       /* for pax(1) and such, checking tapes... */
-                       if (fp->f_type == DTYPE_VNODE &&
-                           (vp->v_type == VCHR || vp->v_type == VBLK))
-                               return (0);
-                       break;
-               case SIOCGIFGROUP:
-                       if ((p->p_p->ps_pledge & PLEDGE_INET) &&
-                           fp->f_type == DTYPE_SOCKET)
-                               return (0);
-                       break;
-               }
-       }
-
-       if ((p->p_p->ps_pledge & PLEDGE_ROUTE)) {
-               switch (com) {
-               case SIOCGIFADDR:
-               case SIOCGIFFLAGS:
-               case SIOCGIFRDOMAIN:
-                       if (fp->f_type == DTYPE_SOCKET)
-                               return (0);
-                       break;
-               }
-       }
-
-       if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
-               switch (com) {
-               case TIOCSPGRP:
-                       if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
-                               break;
-                       /* FALTHROUGH */
-               case TIOCGETA:
-               case TIOCGPGRP:
-               case TIOCGWINSZ:        /* various programs */
-#if notyet
-               case TIOCSTI:           /* ksh? csh? */
-#endif
-               case TIOCSBRK:          /* cu */
-               case TIOCCDTR:          /* cu */
-               case TIOCSETA:          /* cu, ... */
-               case TIOCSETAW:         /* cu, ... */
-               case TIOCSETAF:         /* tcsetattr TCSAFLUSH, script */
-                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
-                               return (0);
-                       break;
-               }
-       }
-
-       return pledge_fail(p, EPERM, PLEDGE_IOCTL);
-}
-
-int
-pledge_setsockopt_check(struct proc *p, int level, int optname)
-{
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       /* common case for PLEDGE_UNIX and PLEDGE_INET */
-       switch (level) {
-       case SOL_SOCKET:
-               switch (optname) {
-               case SO_RTABLE:
-                       return (EPERM);
-               }
-               return (0);
-       }
-
-       if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
-               return (EPERM);
-
-       switch (level) {
-       case IPPROTO_TCP:
-               switch (optname) {
-               case TCP_NODELAY:
-               case TCP_MD5SIG:
-               case TCP_SACK_ENABLE:
-               case TCP_MAXSEG:
-               case TCP_NOPUSH:
-                       return (0);
-               }
-               break;
-       case IPPROTO_IP:
-               switch (optname) {
-               case IP_TOS:
-               case IP_TTL:
-               case IP_MINTTL:
-               case IP_PORTRANGE:
-               case IP_RECVDSTADDR:
-                       return (0);
-               case IP_MULTICAST_IF:
-               case IP_ADD_MEMBERSHIP:
-               case IP_DROP_MEMBERSHIP:
-                       if ((p->p_p->ps_pledge & PLEDGE_MCAST) == 0)
-                               return (0);
-                       break;
-               }               
-               break;
-       case IPPROTO_ICMP:
-               break;
-       case IPPROTO_IPV6:
-               switch (optname) {
-               case IPV6_UNICAST_HOPS:
-               case IPV6_RECVHOPLIMIT:
-               case IPV6_PORTRANGE:
-               case IPV6_RECVPKTINFO:
-#ifdef notyet
-               case IPV6_V6ONLY:
-#endif
-                       return (0);
-               case IPV6_MULTICAST_IF:
-               case IPV6_JOIN_GROUP:
-               case IPV6_LEAVE_GROUP:
-                       if ((p->p_p->ps_pledge & PLEDGE_MCAST) == 0)
-                               return (0);
-                       break;
-               }
-               break;
-       case IPPROTO_ICMPV6:
-               break;
-       }
-       return (EPERM);
-}
-
-int
-pledge_dns_check(struct proc *p, in_port_t port)
-{
-       if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
-               return (0);
-
-       if ((p->p_p->ps_pledge & PLEDGE_INET))
-               return (0);
-       if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && port == htons(53))
-               return (0);     /* Allow a DNS connect outbound */
-       return (EPERM);
-}
-
-void
-pledge_dropwpaths(struct process *pr)
-{
-       if (pr->ps_pledgepaths && --pr->ps_pledgepaths->wl_ref == 0) {
-               struct whitepaths *wl = pr->ps_pledgepaths;
-               int i;
-
-               for (i = 0; i < wl->wl_count; i++)
-                       free(wl->wl_paths[i].name, M_TEMP, wl->wl_paths[i].len);
-               free(wl, M_TEMP, wl->wl_size);
-       }
-       pr->ps_pledgepaths = NULL;
-}
-
-int
-canonpath(const char *input, char *buf, size_t bufsize)
-{
-       char *p, *q, *s, *end;
-
-       /* can't canon relative paths, don't bother */
-       if (input[0] != '/') {
-               if (strlcpy(buf, input, bufsize) >= bufsize)
-                       return (ENAMETOOLONG);
-               return (0);
-       }
-
-       /* easiest to work with strings always ending in '/' */
-       if (snprintf(buf, bufsize, "%s/", input) >= bufsize)
-               return (ENAMETOOLONG);
-
-       /* after this we will only be shortening the string. */
-       p = buf;
-       q = p;
-       while (*p) {
-               if (p[0] == '/' && p[1] == '/') {
-                       p += 1;
-               } else if (p[0] == '/' && p[1] == '.' &&
-                   p[2] == '/') {
-                       p += 2;
-               } else {
-                       *q++ = *p++;
-               }
-       }
-       *q = 0;
-
-       end = buf + strlen(buf);
-       s = buf;
-       p = s;
-       while (1) {
-               /* find "/../" (where's strstr when you need it?) */
-               while (p < end) {
-                       if (p[0] == '/' && strncmp(p + 1, "../", 3) == 0)
-                               break;
-                       p++;
-               }
-               if (p == end)
-                       break;
-               if (p == s) {
-                       memmove(s, p + 3, end - p - 3 + 1);
-                       end -= 3;
-               } else {
-                       /* s starts with '/', so we know there's one
-                        * somewhere before p. */
-                       q = p - 1;
-                       while (*q != '/')
-                               q--;
-                       memmove(q, p + 3, end - p - 3 + 1);
-                       end -= p + 3 - q;
-                       p = q;
-               }
-       }
-       if (end > s + 1)
-               *(end - 1) = 0; /* remove trailing '/' */
-
-       return 0;
-}
index b57af10..2c5ea05 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sys_generic.c,v 1.103 2015/09/11 15:29:47 deraadt Exp $       */
+/*     $OpenBSD: sys_generic.c,v 1.104 2015/10/09 01:17:21 deraadt Exp $       */
 /*     $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $     */
 
 /*
@@ -56,7 +56,7 @@
 #include <sys/ktrace.h>
 #endif
 #include <sys/sched.h>
-#include <sys/tame.h>
+#include <sys/pledge.h>
 
 #include <sys/mount.h>
 #include <sys/syscallargs.h>
@@ -404,8 +404,8 @@ sys_ioctl(struct proc *p, void *v, register_t *retval)
        fdp = p->p_fd;
        fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE);
 
-       if (tame_ioctl_check(p, com, fp))
-               return (tame_fail(p, EPERM, TAME_IOCTL));
+       if (pledge_ioctl_check(p, com, fp))
+               return (pledge_fail(p, EPERM, PLEDGE_IOCTL));
 
        if (fp == NULL)
                return (EBADF);
index 7ae8572..0219db0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscall_mi.h,v 1.10 2015/09/12 16:22:46 deraadt Exp $ */
+/*     $OpenBSD: syscall_mi.h,v 1.11 2015/10/09 01:17:18 deraadt Exp $ */
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -31,7 +31,7 @@
  *     @(#)kern_xxx.c  8.2 (Berkeley) 11/14/93
  */
 
-#include <sys/tame.h>
+#include <sys/pledge.h>
 
 #ifdef KTRACE
 #include <sys/ktrace.h>
@@ -51,7 +51,7 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp,
     register_t *argp, register_t retval[2])
 {
        int lock = !(callp->sy_flags & SY_NOLOCK);
-       int error, tamed, tval;
+       int error, pledged, tval;
 
        /* refresh the thread's cache of the process's creds */
        refreshcreds(p);
@@ -71,16 +71,16 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp,
 
        if (lock)
                KERNEL_LOCK();
-       tamed = (p->p_p->ps_flags & PS_TAMED);
-       if (tamed && !(tval = tame_check(p, code))) {
+       pledged = (p->p_p->ps_flags & PS_PLEDGE);
+       if (pledged && !(tval = pledge_check(p, code))) {
                if (!lock)
                        KERNEL_LOCK();
-               error = tame_fail(p, EPERM, tval);
+               error = pledge_fail(p, EPERM, tval);
                KERNEL_UNLOCK();
                return (error);
        }
 #if NSYSTRACE > 0
-       if (!tamed && ISSET(p->p_flag, P_SYSTRACE)) {
+       if (!pledged && ISSET(p->p_flag, P_SYSTRACE)) {
                if (!lock)
                        KERNEL_LOCK();
                error = systrace_redirect(code, p, argp, retval);
@@ -89,8 +89,8 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp,
        }
 #endif
        error = (*callp->sy_call)(p, argp, retval);
-       if (tamed && p->p_tameafter)
-               tame_aftersyscall(p, code, error);
+       if (pledged && p->p_pledgeafter)
+               pledge_aftersyscall(p, code, error);
        if (lock)
                KERNEL_UNLOCK();