diff options
author | 2015-07-19 02:35:35 +0000 | |
---|---|---|
committer | 2015-07-19 02:35:35 +0000 | |
commit | 586b470f3a48386e9005eb2372f8b7d7b2210f1f (patch) | |
tree | 08b5d85af5fb101552c8de4e8c5ebb6d8e87b6f8 | |
parent | Remove the logic responsible for outputting most AES-NI instructions as (diff) | |
download | wireguard-openbsd-586b470f3a48386e9005eb2372f8b7d7b2210f1f.tar.xz wireguard-openbsd-586b470f3a48386e9005eb2372f8b7d7b2210f1f.zip |
tame(2) is a subsystem which restricts programs into a "reduced feature
operating model". This is the kernel component; various changes should
proceed in-tree for a while before userland programs start using it.
ok miod, discussions and help from many
-rw-r--r-- | sys/conf/files | 3 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_tame.c | 784 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 6 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 14 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 4 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 36 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 10 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 27 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 7 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 8 | ||||
-rw-r--r-- | sys/sys/proc.h | 48 | ||||
-rw-r--r-- | sys/sys/syscall_mi.h | 27 | ||||
-rw-r--r-- | sys/sys/tame.h | 90 |
16 files changed, 1035 insertions, 42 deletions
diff --git a/sys/conf/files b/sys/conf/files index 46676604e37..1a2d343b102 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.596 2015/07/18 15:51:16 mpi Exp $ +# $OpenBSD: files,v 1.597 2015/07/19 02:35:35 deraadt Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -666,6 +666,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_sched.c file kern/kern_sensors.c file kern/kern_sig.c diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index ec92be51948..e7f7c1b138d 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_fork.c,v 1.180 2015/03/14 07:33:42 jsg Exp $ */ +/* $OpenBSD: kern_fork.c,v 1.181 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */ /* @@ -203,7 +203,7 @@ process_new(struct proc *p, struct process *parent, int flags) if (pr->ps_textvp) vref(pr->ps_textvp); - pr->ps_flags = parent->ps_flags & (PS_SUGID | PS_SUGIDEXEC); + pr->ps_flags = parent->ps_flags & (PS_SUGID | PS_SUGIDEXEC | PS_TAMED); if (parent->ps_session->s_ttyvp != NULL) pr->ps_flags |= parent->ps_flags & PS_CONTROLT; diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 501d4011689..2c3b6ea13f2 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.180 2015/05/05 02:13:46 guenther Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.181 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1420,6 +1420,7 @@ sigexit(struct proc *p, int signum) TAILQ_NEXT(p, p_thr_link) != NULL) single_thread_set(p, SINGLE_SUSPEND, 0); + atomic_clearbits_int(&p->p_p->ps_flags, PS_TAMED); if (coredump(p) == 0) signum |= WCOREFLAG; } diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index bb7ef9fc210..2347af3d18c 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.285 2015/05/18 19:10:35 bluhm Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.286 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -70,6 +70,7 @@ #include <sys/domain.h> #include <sys/protosw.h> #include <sys/timetc.h> +#include <sys/tame.h> #include <sys/evcount.h> #include <sys/un.h> #include <sys/unpcb.h> @@ -170,6 +171,9 @@ sys___sysctl(struct proc *p, void *v, register_t *retval) if (error) return (error); + if (tame_sysctl_check(p, SCARG(uap, namelen), name, SCARG(uap, new))) + return (tame_fail(p, EPERM, _TM_SELF)); + switch (name[0]) { case CTL_KERN: fn = kern_sysctl; diff --git a/sys/kern/kern_tame.c b/sys/kern/kern_tame.c new file mode 100644 index 00000000000..5a07d1a4eb6 --- /dev/null +++ b/sys/kern/kern_tame.c @@ -0,0 +1,784 @@ +/* $OpenBSD: kern_tame.c,v 1.1 2015/07/19 02:35:35 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 MIND, 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/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/tame.h> + +#include <sys/signalvar.h> +#include <sys/syscall.h> +#include <sys/syscallargs.h> +#include <sys/systm.h> + +const u_int tame_syscalls[SYS_MAXSYSCALL] = { + [SYS_exit] = 0xffffffff, + + [SYS_getuid] = _TM_SELF, + [SYS_geteuid] = _TM_SELF, + [SYS_getresuid] = _TM_SELF, + [SYS_getgid] = _TM_SELF, + [SYS_getegid] = _TM_SELF, + [SYS_getresgid] = _TM_SELF, + [SYS_getgroups] = _TM_SELF, + [SYS_getlogin] = _TM_SELF, + [SYS_getpgrp] = _TM_SELF, + [SYS_getpgid] = _TM_SELF, + [SYS_getppid] = _TM_SELF, + [SYS_getsid] = _TM_SELF, + [SYS_getthrid] = _TM_SELF, + [SYS_getrlimit] = _TM_SELF, + [SYS_gettimeofday] = _TM_SELF, + [SYS_getdtablecount] = _TM_SELF, + [SYS_issetugid] = _TM_SELF, + [SYS_clock_getres] = _TM_SELF, + [SYS_clock_gettime] = _TM_SELF, + [SYS_getpid] = _TM_SELF, + [SYS_umask] = _TM_SELF, + [SYS___sysctl] = _TM_SELF, /* read-only; narrow subset */ + [SYS_adjtime] = _TM_SELF, /* read-only */ + + [SYS_chdir] = _TM_RPATH, + + [SYS_fchdir] = _TM_SELF, /* careful of directory fd inside jails */ + + [SYS_sendsyslog] = _TM_SELF, + [SYS_nanosleep] = _TM_SELF, + [SYS_sigprocmask] = _TM_SELF, + [SYS_sigaction] = _TM_SELF, + [SYS_sigreturn] = _TM_SELF, + [SYS_getitimer] = _TM_SELF, + [SYS_setitimer] = _TM_SELF, + + [SYS_tame] = _TM_SELF, + + [SYS_wait4] = _TM_SELF, + + [SYS_poll] = _TM_RW, + [SYS_kevent] = _TM_RW, + [SYS_kqueue] = _TM_RW, + [SYS_select] = _TM_RW, + + [SYS_close] = _TM_RW, + [SYS_dup] = _TM_RW, + [SYS_dup2] = _TM_RW, + [SYS_dup3] = _TM_RW, + [SYS_closefrom] = _TM_RW, + [SYS_shutdown] = _TM_RW, + [SYS_read] = _TM_RW, + [SYS_readv] = _TM_RW, + [SYS_pread] = _TM_RW, + [SYS_preadv] = _TM_RW, + [SYS_write] = _TM_RW, + [SYS_writev] = _TM_RW, + [SYS_pwrite] = _TM_RW, + [SYS_pwritev] = _TM_RW, + [SYS_ftruncate] = _TM_RW, + [SYS_lseek] = _TM_RW, + + [SYS_utimes] = _TM_RW, + [SYS_futimes] = _TM_RW, + [SYS_utimensat] = _TM_RW, + [SYS_futimens] = _TM_RW, + + [SYS_fcntl] = _TM_RW, + [SYS_fsync] = _TM_RW, + [SYS_pipe] = _TM_RW, + [SYS_pipe2] = _TM_RW, + [SYS_socketpair] = _TM_RW, + + [SYS_getdents] = _TM_RW, + + [SYS_sendto] = _TM_RW | _TM_DNS_ACTIVE | _TM_YP_ACTIVE, + [SYS_sendmsg] = _TM_RW, + [SYS_recvmsg] = _TM_RW, + [SYS_recvfrom] = _TM_RW | _TM_DNS_ACTIVE | _TM_YP_ACTIVE, + + [SYS_fork] = _TM_PROC, + [SYS_vfork] = _TM_PROC, + [SYS_kill] = _TM_PROC, + + [SYS_setresgid] = _TM_PROC, + [SYS_setresuid] = _TM_PROC, + + [SYS_ioctl] = _TM_IOCTL, /* very limited subset */ + + [SYS_getentropy] = _TM_MALLOC, + [SYS_madvise] = _TM_MALLOC, + [SYS_minherit] = _TM_MALLOC, + [SYS_mmap] = _TM_MALLOC, + [SYS_mprotect] = _TM_MALLOC, + [SYS_mquery] = _TM_MALLOC, + [SYS_munmap] = _TM_MALLOC, + + [SYS___getcwd] = _TM_RPATH | _TM_WPATH, + [SYS_open] = _TM_SELF, + [SYS_openat] = _TM_RPATH | _TM_WPATH, + [SYS_stat] = _TM_SELF, + [SYS_fstatat] = _TM_RPATH | _TM_WPATH, + [SYS_access] = _TM_SELF, + [SYS_faccessat] = _TM_RPATH | _TM_WPATH, + [SYS_readlink] = _TM_SELF, + [SYS_readlinkat] = _TM_RPATH | _TM_WPATH, + [SYS_lstat] = _TM_RPATH | _TM_WPATH | _TM_TMPPATH | _TM_DNSPATH, + [SYS_chmod] = _TM_RPATH | _TM_WPATH | _TM_TMPPATH, + [SYS_fchmod] = _TM_RPATH | _TM_WPATH, + [SYS_fchmodat] = _TM_RPATH | _TM_WPATH, + [SYS_chflags] = _TM_RPATH | _TM_WPATH | _TM_TMPPATH, + [SYS_chflagsat] = _TM_RPATH | _TM_WPATH, + [SYS_chown] = _TM_RPATH | _TM_WPATH | _TM_TMPPATH, + [SYS_fchown] = _TM_RPATH | _TM_WPATH, + [SYS_fchownat] = _TM_RPATH | _TM_WPATH, + [SYS_rename] = _TM_CPATH, + [SYS_rmdir] = _TM_CPATH, + [SYS_renameat] = _TM_CPATH, + [SYS_link] = _TM_CPATH, + [SYS_linkat] = _TM_CPATH, + [SYS_symlink] = _TM_CPATH, + [SYS_unlink] = _TM_CPATH | _TM_TMPPATH, + [SYS_unlinkat] = _TM_CPATH, + [SYS_mkdir] = _TM_CPATH, + [SYS_mkdirat] = _TM_CPATH, + + [SYS_fstat] = _TM_RW | _TM_RPATH | _TM_WPATH | _TM_TMPPATH, /* rare */ + + [SYS_socket] = _TM_INET | _TM_UNIX | _TM_DNS_ACTIVE | _TM_YP_ACTIVE, + [SYS_listen] = _TM_INET | _TM_UNIX, + [SYS_bind] = _TM_INET | _TM_UNIX, + [SYS_connect] = _TM_INET | _TM_UNIX | _TM_DNS_ACTIVE | _TM_YP_ACTIVE, + [SYS_accept4] = _TM_INET | _TM_UNIX, + [SYS_accept] = _TM_INET | _TM_UNIX, + [SYS_getpeername] = _TM_INET | _TM_UNIX, + [SYS_getsockname] = _TM_INET | _TM_UNIX, + [SYS_setsockopt] = _TM_INET | _TM_UNIX, /* small subset */ + [SYS_getsockopt] = _TM_INET | _TM_UNIX, + + [SYS_flock] = _TM_GETPW, +}; + +int +sys_tame(struct proc *p, void *v, register_t *retval) +{ + struct sys_tame_args /* { + syscallarg(int) flags; + } */ *uap = v; + int flags = SCARG(uap, flags); + + flags &= _TM_USERSET; + if ((p->p_p->ps_flags & PS_TAMED) == 0) { + p->p_p->ps_flags |= PS_TAMED; + p->p_p->ps_tame = flags; + return (0); + } + + /* May not set new bits */ + if (((flags | p->p_p->ps_tame) & _TM_USERSET) != + (p->p_p->ps_tame & _TM_USERSET)) + return (EPERM); + + /* More tame bits being cleared. Force re-learning of _ACTIVE things */ + p->p_p->ps_tame &= flags; + p->p_p->ps_tame &= _TM_USERSET; + return (0); +} + +int +tame_check(struct proc *p, int code) +{ + p->p_tamenote = p->p_tameafter = 0; /* XX optimise? */ + p->p_tame_syscall = code; + + if (code < 0 || code > SYS_MAXSYSCALL - 1) + return (0); + + if (p->p_p->ps_tame == 0) + return (code == SYS_exit); + return (p->p_p->ps_tame & tame_syscalls[code]); +} + +int +tame_fail(struct proc *p, int error, int code) +{ + printf("tame: pid %d %s syscall %d\n", p->p_pid, p->p_comm, + p->p_tame_syscall); +#ifdef KTRACE + if (KTRPOINT(p, KTR_PSIG)) { + siginfo_t si; + + memset(&si, 0, sizeof(si)); + if (p->p_p->ps_tame & _TM_ABORT) + si.si_signo = SIGABRT; + else + si.si_signo = SIGKILL; + si.si_code = code; + // si.si_syscall = p->p_tame_syscall; + /// si.si_nsysarg ... + ktrpsig(p, si.si_signo, SIG_DFL, p->p_sigmask, code, &si); + } +#endif + if (p->p_p->ps_tame & _TM_ABORT) { + /* Core dump requested */ + atomic_clearbits_int(&p->p_sigmask, sigmask(SIGABRT)); + atomic_clearbits_int(&p->p_p->ps_flags, PS_TAMED); + psignal(p, SIGABRT); + } else + psignal(p, SIGKILL); + return (error); +} + +/* + * Need to make it more obvious that one cannot get through here + * without the right flags set + */ +int +tame_namei(struct proc *p, char *path) +{ + /* Detect what looks like a mkstemp(3) family operation */ + if ((p->p_p->ps_tame & _TM_TMPPATH) && + (p->p_tame_syscall == SYS_open) && + (p->p_tamenote & (TMN_CREAT | TMN_IMODIFY)) == TMN_CREAT && + strncmp(path, "/tmp/", 5) == 0) { + return (0); + } + + /* Allow unlinking of a mkstemp(3) file... + * Good opportunity for strict checks here. + */ + if ((p->p_p->ps_tame & _TM_TMPPATH) && + (p->p_tame_syscall == SYS_unlink) && + strncmp(path, "/tmp/", 5) == 0) { + return (0); + } + + /* open, mkdir, or other path creation operation */ + if ((p->p_tamenote & (TMN_CREAT | TMN_IMODIFY)) == TMN_CREAT && + ((p->p_p->ps_tame & _TM_CPATH) == 0)) + return (tame_fail(p, EPERM, TAME_CPATH)); + + /* inode change operation, issued against a path */ + if ((p->p_tamenote & (TMN_CREAT | TMN_IMODIFY)) == TMN_IMODIFY && + ((p->p_p->ps_tame & _TM_CPATH) == 0)) { + // XXX should _TM_CPATH be a seperate check? + return (tame_fail(p, EPERM, TAME_CPATH)); + } + + if ((p->p_tamenote & TMN_WRITE) && + (p->p_p->ps_tame & _TM_WPATH) == 0) + return (tame_fail(p, EPERM, TAME_WPATH)); + + if (p->p_p->ps_tame & _TM_RPATH) + return (0); + + if (p->p_p->ps_tame & _TM_WPATH) + return (0); + + /* All remaining cases are RPATH */ + switch (p->p_tame_syscall) { + case SYS_access: + /* tzset() needs this. */ + if (strcmp(path, "/etc/localtime") == 0) + return (0); + break; + case SYS_open: + /* getpw* and friends need a few files */ + if (p->p_p->ps_tame & _TM_GETPW) { + if (strcmp(path, "/etc/spwd.db") == 0) + return (0); + 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_p->ps_tame & _TM_DNSPATH) { + if (strcmp(path, "/etc/resolv.conf") == 0) { + p->p_tamenote |= TMN_DNSRESOLV; + p->p_tameafter = 1; + return (0); + } + if (strcmp(path, "/etc/hosts") == 0) + return (0); + if (strcmp(path, "/etc/services") == 0) + return (0); + } + if (p->p_p->ps_tame & _TM_GETPW) { + if (strcmp(path, "/var/run/ypbind.lock") == 0) { + p->p_tamenote |= TMN_YPLOCK; + p->p_tameafter = 1; + return (0); + } + if (strncmp(path, "/var/yp/binding/", 14) == 0) + return (0); + } + /* tzset() needs these. */ + if (strncmp(path, "/usr/share/zoneinfo/", 20) == 0) + return (0); + if (strcmp(path, "/etc/localtime") == 0) + return (0); + + /* /usr/share/nls/../libc.cat returns EPERM, for strerror(3). */ + if (strncmp(path, "/usr/share/nls/", 15) == 0 && + strcmp(path + strlen(path) - 9, "/libc.cat") == 0) + return (EPERM); + break; + case SYS_readlink: + /* Allow /etc/malloc.conf for malloc(3). */ + if (strcmp(path, "/etc/malloc.conf") == 0) + return (0); + break; + case SYS_stat: + /* DNS needs /etc/resolv.conf. */ + if (p->p_p->ps_tame & _TM_DNSPATH) { + if (strcmp(path, "/etc/resolv.conf") == 0) { + p->p_tamenote |= TMN_DNSRESOLV; + p->p_tameafter = 1; + return (0); + } + } + break; + } + + return (tame_fail(p, EPERM, TAME_RPATH)); +} + +void +tame_aftersyscall(struct proc *p, int code, int error) +{ + if ((p->p_tamenote & TMN_YPLOCK) && error == 0) + atomic_setbits_int(&p->p_p->ps_tame, _TM_YP_ACTIVE | TAME_INET); + if ((p->p_tamenote & TMN_DNSRESOLV) && error == 0) + atomic_setbits_int(&p->p_p->ps_tame, _TM_DNS_ACTIVE); +} + +/* + * By default, only the advisory cmsg's can be received from the kernel, + * such as TIMESTAMP ntpd. + * + * If TAME_CMSG is set SCM_RIGHTS is also allowed through 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 +tame_cmsg_recv(struct proc *p, void *v, int controllen) +{ + struct mbuf *control = v; + struct msghdr tmp; + struct cmsghdr *cmsg; + struct file **rp, *fp; + int nfds, i; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + /* Scan the cmsg */ + memset(&tmp, 0, sizeof(tmp)); + tmp.msg_control = mtod(control, struct cmsghdr *); + tmp.msg_controllen = controllen; + 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_tame & _TM_CMSG) == 0) + return tame_fail(p, EPERM, TAME_CMSG); + + /* In OpenBSD, a CMSG only contains one SCM_RIGHTS. Check it. */ + rp = (struct file **)CMSG_DATA(cmsg); + nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) / + sizeof(struct file *); + for (i = 0; i < nfds; i++) { + struct vnode *vp; + + fp = *rp++; + + /* Only allow passing of sockets, pipes, and pure files */ + printf("f_type %d\n", fp->f_type); + switch (fp->f_type) { + case DTYPE_SOCKET: + case DTYPE_PIPE: + continue; + case DTYPE_VNODE: + vp = (struct vnode *)fp->f_data; + printf("v_type %d\n", vp->v_type); + if (vp->v_type == VREG) + continue; + break; + default: + break; + } + printf("bad fd type\n"); + return tame_fail(p, EPERM, TAME_CMSG); + } + return (0); +} + +/* + * When tamed, default prevents sending of a cmsg. + * If CMSG flag is set, + */ +int +tame_cmsg_send(struct proc *p, void *v, int controllen) +{ + struct mbuf *control = v; + struct msghdr tmp; + struct cmsghdr *cmsg; + struct file **rp, *fp; + int nfds, i; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if ((p->p_p->ps_tame & _TM_CMSG) == 0) + return tame_fail(p, EPERM, TAME_CMSG); + + /* Scan the cmsg */ + memset(&tmp, 0, sizeof(tmp)); + tmp.msg_control = mtod(control, struct cmsghdr *); + tmp.msg_controllen = controllen; + cmsg = CMSG_FIRSTHDR(&tmp); + + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) + break; + cmsg = CMSG_NXTHDR(&tmp, cmsg); + } + + /* Contains no SCM_RIGHTS, so OK */ + if (cmsg == NULL) + return (0); + + /* In OpenBSD, a CMSG only contains one SCM_RIGHTS. Check it. */ + rp = (struct file **)CMSG_DATA(cmsg); + nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) / + sizeof(struct file *); + for (i = 0; i < nfds; i++) { + struct vnode *vp; + + fp = *rp++; + + /* Only allow passing of sockets, pipes, and pure files */ + printf("f_type %d\n", fp->f_type); + switch (fp->f_type) { + case DTYPE_SOCKET: + case DTYPE_PIPE: + continue; + case DTYPE_VNODE: + vp = (struct vnode *)fp->f_data; + printf("v_type %d\n", vp->v_type); + if (vp->v_type == VREG) + continue; + break; + default: + break; + } + /* Not allowed to send a bad fd type */ + return tame_fail(p, EPERM, TAME_CMSG); + } + return (0); +} + +int +tame_sysctl_check(struct proc *p, int namelen, int *name, void *new) +{ + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if (new) + return (EFAULT); + + /* getifaddrs() */ + if ((p->p_p->ps_tame & _TM_INET) && + namelen == 6 && + name[0] == CTL_NET && name[1] == PF_ROUTE && + name[2] == 0 && name[3] == 0 && + name[4] == NET_RT_IFLIST && name[5] == 0) + return (0); + + /* used by arp(8). Exposes MAC addresses known on local nets */ + /* XXX Put into a special catagory. */ + if ((p->p_p->ps_tame & _TM_INET) && + namelen == 7 && + name[0] == CTL_NET && name[1] == PF_ROUTE && + name[2] == 0 && name[3] == AF_INET && + name[4] == NET_RT_FLAGS && name[5] == RTF_LLINFO) + return (0); + + /* used by ntpd(8) to read sensors. */ + /* XXX Put into a special catagory. */ + if (namelen >= 3 && + name[0] == CTL_HW && name[1] == HW_SENSORS) + return (0); + + if (namelen == 2 && + name[0] == CTL_KERN && name[1] == KERN_DOMAINNAME) + return (0); + if (namelen == 2 && + name[0] == CTL_KERN && name[1] == KERN_HOSTNAME) + return (0); + + printf("tame: pid %d %s sysctl %d: %d %d %d %d %d %d\n", + p->p_pid, p->p_comm, namelen, name[0], name[1], + name[2], name[3], name[4], name[5]); + return (EFAULT); +} + +int +tame_adjtime_check(struct proc *p, const void *v) +{ + const struct timeval *delta = v; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if (delta) + return (EFAULT); + return (0); +} + +int +tame_connect_check(struct proc *p) +{ + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if ((p->p_p->ps_tame & _TM_DNS_ACTIVE)) + return (0); /* A port check happens inside sys_connect() */ + + if ((p->p_p->ps_tame & (_TM_INET | _TM_UNIX))) + return (0); + return (EPERM); +} + +int +tame_recvfrom_check(struct proc *p, void *v) +{ + struct sockaddr *from = v; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if ((p->p_p->ps_tame & _TM_DNS_ACTIVE) && from == NULL) + return (0); + if (p->p_p->ps_tame & _TM_INET) + return (0); + if (p->p_p->ps_tame & _TM_UNIX) + return (0); + if (from == NULL) + return (0); /* behaves just like write */ + return (EPERM); +} + +int +tame_sendto_check(struct proc *p, const void *v) +{ + const struct sockaddr *to = v; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if ((p->p_p->ps_tame & _TM_DNS_ACTIVE) && to == NULL) + return (0); + + if ((p->p_p->ps_tame & _TM_INET)) + return (0); + if ((p->p_p->ps_tame & _TM_UNIX)) + return (0); + if (to == NULL) + return (0); /* behaves just like write */ + return (EPERM); +} + +int +tame_socket_check(struct proc *p, int domain) +{ + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + if ((p->p_p->ps_tame & (_TM_INET | _TM_UNIX))) + return (0); + if ((p->p_p->ps_tame & _TM_DNS_ACTIVE) && domain == AF_INET) + return (0); + return (EPERM); +} + +int +tame_bind_check(struct proc *p, const void *v) +{ + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + if ((p->p_p->ps_tame & _TM_INET)) + return (0); + return (EPERM); +} + +int +tame_ioctl_check(struct proc *p, long com, void *v) +{ + struct file *fp = v; + struct vnode *vp = (struct vnode *)fp->f_data; + + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + switch (com) { + + /* + * This is a set of "get" info ioctls at the top layer. Hopefully + * a safe list, since they are used a lot. + */ + case FIOCLEX: + case FIONCLEX: + case FIONREAD: + case FIONBIO: + case FIOGETOWN: + return (0); + case FIOASYNC: + case FIOSETOWN: + return (EPERM); + + /* tty subsystem */ + case TIOCSWINSZ: /* various programs */ + case TIOCSTI: /* ksh? csh? */ + if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY)) + return (0); + break; + + default: + break; + } + + if ((p->p_p->ps_tame & _TM_IOCTL) == 0) + return (EPERM); + + /* + * Further sets of ioctl become available, but are checked a + * bit more carefully against the vnode. + */ + + switch (com) { + case TIOCSETAF: /* tcsetattr TCSAFLUSH, script */ + if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY)) + 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_tame & _TM_INET) && + fp->f_type == DTYPE_SOCKET) + return (0); + break; + + default: + printf("ioctl %lx\n", com); + break; + } + return (EPERM); +} + +int +tame_setsockopt_check(struct proc *p, int level, int optname) +{ + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_RTABLE: + return (EPERM); + } + return (0); + case IPPROTO_TCP: + switch (optname) { + case TCP_NODELAY: + case TCP_MD5SIG: + case TCP_SACK_ENABLE: + case TCP_MAXSEG: + case TCP_NOPUSH: + return (0); + } + case IPPROTO_IP: + switch (optname) { + case IP_TOS: + case IP_TTL: + case IP_MINTTL: + case IP_PORTRANGE: + case IP_RECVDSTADDR: + return (0); + } + case IPPROTO_ICMP: + break; + case IPPROTO_IPV6: + case IPPROTO_ICMPV6: + break; + } + return (EPERM); +} + +int +tame_dns_check(struct proc *p, in_port_t port) +{ + if ((p->p_p->ps_flags & PS_TAMED) == 0) + return (0); + + if ((p->p_p->ps_tame & _TM_INET)) + return (0); + if ((p->p_p->ps_tame & _TM_DNS_ACTIVE) && port == htons(53)) + return (0); /* Allow a DNS connect outbound */ + return (EPERM); +} diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 453790b3682..1e7553924ce 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.90 2015/04/28 20:54:18 kettenis Exp $ */ +/* $OpenBSD: kern_time.c,v 1.91 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -40,6 +40,7 @@ #include <sys/ktrace.h> #include <sys/vnode.h> #include <sys/signalvar.h> +#include <sys/tame.h> #include <sys/timetc.h> #include <sys/mount.h> @@ -432,6 +433,9 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) struct timeval atv; int error; + if (tame_adjtime_check(p, delta)) + return (EPERM); + if (olddelta) { memset(&atv, 0, sizeof(atv)); atv.tv_sec = adjtimedelta / 1000000; diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index cefcf9f7a5f..b6752bb5c40 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_generic.c,v 1.98 2015/05/10 22:35:38 millert Exp $ */ +/* $OpenBSD: sys_generic.c,v 1.99 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */ /* @@ -52,6 +52,7 @@ #include <sys/stat.h> #include <sys/malloc.h> #include <sys/poll.h> +#include <sys/tame.h> #ifdef KTRACE #include <sys/ktrace.h> #endif @@ -384,7 +385,7 @@ sys_ioctl(struct proc *p, void *v, register_t *retval) } */ *uap = v; struct file *fp; struct filedesc *fdp; - u_long com; + u_long com = SCARG(uap, com); int error; u_int size; caddr_t data, memp; @@ -393,10 +394,15 @@ sys_ioctl(struct proc *p, void *v, register_t *retval) long long stkbuf[STK_PARAMS / sizeof(long long)]; fdp = p->p_fd; - if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL) + fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE); + + if (tame_ioctl_check(p, com, fp)) + return (tame_fail(p, EPERM, _TM_IOCTL)); + + if (fp == NULL) return (EBADF); - switch (com = SCARG(uap, com)) { + switch (com) { case FIONCLEX: case FIOCLEX: fdplock(fdp); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 327bcc8d337..aa713512e33 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.153 2015/05/06 11:20:07 jsg Exp $ +; $OpenBSD: syscalls.master,v 1.154 2015/07/19 02:35:35 deraadt Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -224,7 +224,7 @@ 106 STD { int sys_listen(int s, int backlog); } 107 STD { int sys_chflagsat(int fd, const char *path, \ u_int flags, int atflags); } -108 OBSOL osigvec +108 STD { int sys_tame(int flags); } 109 STD { int sys_ppoll(struct pollfd *fds, \ u_int nfds, const struct timespec *ts, \ const sigset_t *mask); } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index fcd37c8ccd4..339da68650a 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.103 2015/07/17 15:23:59 guenther Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.104 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -45,6 +45,7 @@ #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/signalvar.h> +#include <sys/tame.h> #include <sys/unpcb.h> #include <sys/un.h> #ifdef KTRACE @@ -78,6 +79,9 @@ sys_socket(struct proc *p, void *v, register_t *retval) int type = SCARG(uap, type); int fd, error; + if (tame_socket_check(p, SCARG(uap, domain))) + return (tame_fail(p, EPERM, _TM_UNIX)); + fdplock(fdp); error = falloc(p, &fp, &fd); if (error == 0 && (type & SOCK_CLOEXEC)) @@ -120,6 +124,9 @@ sys_bind(struct proc *p, void *v, register_t *retval) struct mbuf *nam; int error; + if (tame_bind_check(p, SCARG(uap, name))) + return (tame_fail(p, EPERM, _TM_UNIX)); + if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), @@ -315,6 +322,9 @@ sys_connect(struct proc *p, void *v, register_t *retval) struct mbuf *nam = NULL; int error, s; + if (tame_connect_check(p)) + return (tame_fail(p, EPERM, _TM_UNIX)); + if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); so = fp->f_data; @@ -455,6 +465,9 @@ sys_sendto(struct proc *p, void *v, register_t *retval) struct msghdr msg; struct iovec aiov; + if (tame_sendto_check(p, SCARG(uap, to))) + return (tame_fail(p, EPERM, _TM_UNIX)); + msg.msg_name = (caddr_t)SCARG(uap, to); msg.msg_namelen = SCARG(uap, tolen); msg.msg_iov = &aiov; @@ -479,6 +492,10 @@ sys_sendmsg(struct proc *p, void *v, register_t *retval) int error; error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); + + if (tame_sendto_check(p, msg.msg_name)) + return (tame_fail(p, EPERM, _TM_UNIX)); + if (error) return (error); if (msg.msg_iovlen > IOV_MAX) @@ -555,6 +572,11 @@ sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize) mp->msg_controllen, MT_CONTROL); if (error) goto bad; + + if (tame_cmsg_send(p, control, mp->msg_controllen)) { + m_free(control); + goto bad; + } } else control = 0; #ifdef KTRACE @@ -609,6 +631,9 @@ sys_recvfrom(struct proc *p, void *v, register_t *retval) struct iovec aiov; int error; + if (tame_recvfrom_check(p, SCARG(uap, from))) + return (tame_fail(p, EPERM, _TM_UNIX)); + if (SCARG(uap, fromlenaddr)) { error = copyin(SCARG(uap, fromlenaddr), &msg.msg_namelen, sizeof (msg.msg_namelen)); @@ -640,6 +665,10 @@ sys_recvmsg(struct proc *p, void *v, register_t *retval) int error; error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); + + if (tame_recvfrom_check(p, msg.msg_name)) + return (tame_fail(p, EPERM, _TM_UNIX)); + if (error) return (error); if (msg.msg_iovlen > IOV_MAX) @@ -767,6 +796,8 @@ recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, mp->msg_flags |= MSG_CTRUNC; i = len; } + if (tame_cmsg_recv(p, control, mp->msg_controllen)) + goto out; error = copyout(mtod(m, caddr_t), cp, i); if (m->m_next) i = ALIGN(i); @@ -825,6 +856,9 @@ sys_setsockopt(struct proc *p, void *v, register_t *retval) struct mbuf *m = NULL; int error; + if (tame_setsockopt_check(p, SCARG(uap, level), SCARG(uap, name))) + return (tame_fail(p, EPERM, _TM_INET)); + if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); if (SCARG(uap, valsize) > MCLBYTES) { diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 9a758aa1fa1..c7648e3af94 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_lookup.c,v 1.53 2015/04/23 02:55:15 jsg Exp $ */ +/* $OpenBSD: vfs_lookup.c,v 1.54 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */ /* @@ -51,6 +51,7 @@ #include <sys/proc.h> #include <sys/file.h> #include <sys/fcntl.h> +#include <sys/tame.h> #ifdef KTRACE #include <sys/ktrace.h> @@ -126,6 +127,7 @@ namei(struct nameidata *ndp) error = ENOENT; if (error) { +fail: pool_put(&namei_pool, cnp->cn_pnbuf); ndp->ni_vp = NULL; return (error); @@ -164,6 +166,12 @@ namei(struct nameidata *ndp) */ if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) ndp->ni_rootdir = rootvnode; + if ((p->p_p->ps_flags & PS_TAMED)) { + error = tame_namei(p, cnp->cn_pnbuf); + if (error) + goto fail; + } + /* * Check if starting from root directory or current directory. */ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 2934999a963..4161cd5d275 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.220 2015/05/07 08:53:33 mpi Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.221 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -812,6 +812,16 @@ sys_open(struct proc *p, void *v, register_t *retval) syscallarg(int) flags; syscallarg(mode_t) mode; } */ *uap = v; + int flags = SCARG(uap, flags); + + switch (flags & O_ACCMODE) { + case O_WRONLY: + case O_RDWR: + p->p_tamenote |= TMN_WRITE; + break; + } + if (flags & O_CREAT) + p->p_tamenote |= TMN_CREAT; return (doopenat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags), SCARG(uap, mode), retval)); @@ -1186,6 +1196,7 @@ sys_mknod(struct proc *p, void *v, register_t *retval) syscallarg(int) dev; } */ *uap = v; + p->p_tamenote |= TMN_IMODIFY; return (domknodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), SCARG(uap, dev))); } @@ -1280,6 +1291,7 @@ sys_mkfifo(struct proc *p, void *v, register_t *retval) syscallarg(mode_t) mode; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (domknodat(p, AT_FDCWD, SCARG(uap, path), (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0)); } @@ -1309,6 +1321,7 @@ sys_link(struct proc *p, void *v, register_t *retval) syscallarg(const char *) link; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (dolinkat(p, AT_FDCWD, SCARG(uap, path), AT_FDCWD, SCARG(uap, link), AT_SYMLINK_FOLLOW)); } @@ -1382,6 +1395,7 @@ sys_symlink(struct proc *p, void *v, register_t *retval) syscallarg(const char *) link; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (dosymlinkat(p, SCARG(uap, path), AT_FDCWD, SCARG(uap, link))); } @@ -1442,6 +1456,7 @@ sys_unlink(struct proc *p, void *v, register_t *retval) syscallarg(const char *) path; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), 0)); } @@ -1835,6 +1850,7 @@ sys_chflags(struct proc *p, void *v, register_t *retval) syscallarg(u_int) flags; } */ *uap = v; + p->p_tamenote |= TMN_IMODIFY; return (dochflagsat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags), 0)); } @@ -1933,6 +1949,7 @@ sys_chmod(struct proc *p, void *v, register_t *retval) syscallarg(mode_t) mode; } */ *uap = v; + p->p_tamenote |= TMN_IMODIFY; return (dofchmodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), 0)); } @@ -2028,6 +2045,7 @@ sys_chown(struct proc *p, void *v, register_t *retval) syscallarg(gid_t) gid; } */ *uap = v; + p->p_tamenote |= TMN_IMODIFY; return (dofchownat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, uid), SCARG(uap, gid), 0)); } @@ -2111,6 +2129,7 @@ sys_lchown(struct proc *p, void *v, register_t *retval) uid_t uid = SCARG(uap, uid); gid_t gid = SCARG(uap, gid); + p->p_tamenote |= TMN_IMODIFY; NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); @@ -2207,6 +2226,7 @@ sys_utimes(struct proc *p, void *v, register_t *retval) const struct timeval *tvp; int error; + p->p_tamenote |= TMN_IMODIFY; tvp = SCARG(uap, tptr); if (tvp != NULL) { error = copyin(tvp, tv, sizeof(tv)); @@ -2402,6 +2422,7 @@ sys_truncate(struct proc *p, void *v, register_t *retval) int error; struct nameidata nd; + p->p_tamenote |= TMN_IMODIFY; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); @@ -2501,6 +2522,7 @@ sys_rename(struct proc *p, void *v, register_t *retval) syscallarg(const char *) to; } */ *uap = v; + p->p_tamenote |= TMN_IMODIFY; return (dorenameat(p, AT_FDCWD, SCARG(uap, from), AT_FDCWD, SCARG(uap, to))); } @@ -2609,6 +2631,7 @@ sys_mkdir(struct proc *p, void *v, register_t *retval) syscallarg(mode_t) mode; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode))); } @@ -2667,6 +2690,7 @@ sys_rmdir(struct proc *p, void *v, register_t *retval) syscallarg(const char *) path; } */ *uap = v; + p->p_tamenote |= TMN_CREAT; return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR)); } @@ -2761,6 +2785,7 @@ sys_revoke(struct proc *p, void *v, register_t *retval) int error; struct nameidata nd; + p->p_tamenote |= TMN_CREAT; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 043a0049978..c292213405d 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.171 2015/07/15 22:16:42 deraadt Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.172 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -79,6 +79,7 @@ #include <sys/proc.h> #include <sys/domain.h> #include <sys/pool.h> +#include <sys/tame.h> #include <net/if.h> #include <net/if_var.h> @@ -442,6 +443,7 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) { struct in_addr *ina = NULL; struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + struct proc *p = curproc; int error; #ifdef INET6 @@ -458,6 +460,9 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) if (sin->sin_port == 0) return (EADDRNOTAVAIL); + if (tame_dns_check(p, sin->sin_port)) + return (tame_fail(p, EPERM, TAME_DNS)); + error = in_selectsrc(&ina, sin, inp->inp_moptions, &inp->inp_route, &inp->inp_laddr, inp->inp_rtableid); if (error) diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index d99bb5f1c0f..1d963ed8091 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.68 2015/06/08 22:19:28 krw Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.69 2015/07/19 02:35:35 deraadt Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -108,6 +108,8 @@ #include <sys/socketvar.h> #include <sys/errno.h> #include <sys/time.h> +#include <sys/proc.h> +#include <sys/tame.h> #include <net/if.h> #include <net/if_var.h> @@ -388,6 +390,7 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) struct in6_addr *in6a = NULL; struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); struct ifnet *ifp = NULL; /* outgoing interface */ + struct proc *p = curproc; int error = 0; struct sockaddr_in6 tmp; @@ -400,6 +403,9 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) if (sin6->sin6_port == 0) return (EADDRNOTAVAIL); + if (tame_dns_check(p, sin6->sin6_port)) + return (tame_fail(p, EPERM, TAME_DNS)); + /* reject IPv4 mapped address, we have no support for it */ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) return EADDRNOTAVAIL; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index b388d13cb7c..d212a6f3c40 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.200 2015/07/18 00:15:10 mpi Exp $ */ +/* $OpenBSD: proc.h,v 1.201 2015/07/19 02:35:35 deraadt Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -211,6 +211,8 @@ struct process { u_short ps_acflag; /* Accounting flags. */ + u_int ps_tame; + /* End area that is copied on creation. */ #define ps_endcopy ps_refcnt int ps_refcnt; /* Number of references. */ @@ -248,13 +250,14 @@ struct process { #define PS_EMBRYO 0x00020000 /* New process, not yet fledged */ #define PS_ZOMBIE 0x00040000 /* Dead and ready to be waited for */ #define PS_NOBROADCASTKILL 0x00080000 /* Process excluded from kill -1. */ +#define PS_TAMED 0x00100000 /* Has called tame(2) */ #define PS_BITS \ ("\20" "\01CONTROLT" "\02EXEC" "\03INEXEC" "\04EXITING" "\05SUGID" \ "\06SUGIDEXEC" "\07PPWAIT" "\010ISPWAIT" "\011PROFIL" "\012TRACED" \ "\013WAITED" "\014COREDUMP" "\015SINGLEEXIT" "\016SINGLEUNWIND" \ "\017NOZOMBIE" "\020STOPPED" "\021SYSTEM" "\022EMBRYO" "\023ZOMBIE" \ - "\024NOBROADCASTKILL") + "\024NOBROADCASTKILL" "\025TAMED") struct proc { @@ -318,6 +321,15 @@ struct proc { u_char p_usrpri; /* User-priority based on p_cpu and ps_nice. */ char p_comm[MAXCOMLEN+1]; + int p_tame_syscall; /* Cache of current syscall */ + int p_tamenote; /* Observance during syscall */ +#define TMN_CREAT 0x00000001 +#define TMN_WRITE 0x00000002 +#define TMN_IMODIFY 0x00000004 +#define TMN_YPLOCK 0x00000008 +#define TMN_DNSRESOLV 0x00000010 + int p_tameafter; + #ifndef __HAVE_MD_TCB void *p_tcb; /* user-space thread-control-block address */ # define TCB_SET(p, addr) ((p)->p_tcb = (addr)) @@ -358,22 +370,22 @@ struct proc { /* * These flags are per-thread and kept in p_flag */ -#define P_INKTR 0x000001 /* In a ktrace op, don't recurse */ -#define P_PROFPEND 0x000002 /* SIGPROF needs to be posted */ -#define P_ALRMPEND 0x000004 /* SIGVTALRM needs to be posted */ -#define P_SIGSUSPEND 0x000008 /* Need to restore before-suspend mask*/ -#define P_CANTSLEEP 0x000010 /* insomniac thread */ -#define P_SELECT 0x000040 /* Selecting; wakeup/waiting danger. */ -#define P_SINTR 0x000080 /* Sleep is interruptible. */ -#define P_SYSTEM 0x000200 /* No sigs, stats or swapping. */ -#define P_TIMEOUT 0x000400 /* Timing out during sleep. */ -#define P_WEXIT 0x002000 /* Working on exiting. */ -#define P_OWEUPC 0x008000 /* Owe proc an addupc() at next ast. */ -#define P_SUSPSINGLE 0x080000 /* Need to stop for single threading. */ -#define P_SYSTRACE 0x400000 /* Process system call tracing active*/ -#define P_CONTINUED 0x800000 /* Proc has continued from a stopped state. */ -#define P_THREAD 0x4000000 /* Only a thread, not a real process */ -#define P_SUSPSIG 0x8000000 /* Stopped from signal. */ +#define P_INKTR 0x00000001 /* In a ktrace op, don't recurse */ +#define P_PROFPEND 0x00000002 /* SIGPROF needs to be posted */ +#define P_ALRMPEND 0x00000004 /* SIGVTALRM needs to be posted */ +#define P_SIGSUSPEND 0x00000008 /* Need to restore before-suspend mask*/ +#define P_CANTSLEEP 0x00000010 /* insomniac thread */ +#define P_SELECT 0x00000040 /* Selecting; wakeup/waiting danger. */ +#define P_SINTR 0x00000080 /* Sleep is interruptible. */ +#define P_SYSTEM 0x00000200 /* No sigs, stats or swapping. */ +#define P_TIMEOUT 0x00000400 /* Timing out during sleep. */ +#define P_WEXIT 0x00002000 /* Working on exiting. */ +#define P_OWEUPC 0x00008000 /* Owe proc an addupc() at next ast. */ +#define P_SUSPSINGLE 0x00080000 /* Need to stop for single threading. */ +#define P_SYSTRACE 0x00400000 /* Process system call tracing active*/ +#define P_CONTINUED 0x00800000 /* Proc has continued from a stopped state. */ +#define P_THREAD 0x04000000 /* Only a thread, not a real process */ +#define P_SUSPSIG 0x08000000 /* Stopped from signal. */ #define P_SOFTDEP 0x10000000 /* Stuck processing softdep worklist */ #define P_CPUPEG 0x40000000 /* Do not move to another cpu. */ diff --git a/sys/sys/syscall_mi.h b/sys/sys/syscall_mi.h index 3cbf788a58a..d8c32ec4f57 100644 --- a/sys/sys/syscall_mi.h +++ b/sys/sys/syscall_mi.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall_mi.h,v 1.5 2014/05/11 00:12:44 guenther Exp $ */ +/* $OpenBSD: syscall_mi.h,v 1.6 2015/07/19 02:35:35 deraadt Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -33,6 +33,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/tame.h> #include <sys/proc.h> #ifdef KTRACE @@ -53,7 +54,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; + int error, tamed, tval; /* refresh the thread's cache of the process's creds */ refreshcreds(p); @@ -76,15 +77,27 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp, KERNEL_LOCK(); error = systrace_redirect(code, p, argp, retval); KERNEL_UNLOCK(); - } else + return (error); + } #endif - { - if (lock) + + if (lock) + KERNEL_LOCK(); + tamed = (p->p_p->ps_flags & PS_TAMED); + if (tamed && !(tval = tame_check(p, code))) { + if (!lock) KERNEL_LOCK(); - error = (*callp->sy_call)(p, argp, retval); - if (lock) + error = tame_fail(p, EPERM, tval); + if (!lock) KERNEL_UNLOCK(); + } + else { + error = (*callp->sy_call)(p, argp, retval); + if (tamed && p->p_tameafter) + tame_aftersyscall(p, code, error); } + if (lock) + KERNEL_UNLOCK(); return (error); } diff --git a/sys/sys/tame.h b/sys/sys/tame.h new file mode 100644 index 00000000000..01a7f3453c1 --- /dev/null +++ b/sys/sys/tame.h @@ -0,0 +1,90 @@ +/* $OpenBSD: tame.h,v 1.1 2015/07/19 02:35:35 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 MIND, 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. + */ + +#ifndef _SYS_TAME_H_ +#define _SYS_TAME_H_ + +#include <sys/cdefs.h> + +#define _TM_SELF 0x00000001 /* operate on own pid */ +#define _TM_RW 0x00000002 /* basic io operations */ +#define _TM_MALLOC 0x00000004 /* enough for malloc */ +#define _TM_DNSPATH 0x00000008 /* access to DNS pathnames */ +#define _TM_RPATH 0x00000010 /* allow open for read */ +#define _TM_WPATH 0x00000020 /* allow open for write */ +#define _TM_TMPPATH 0x00000040 /* for mk*temp() */ +#define _TM_INET 0x00000080 /* AF_INET/AF_INET6 sockets */ +#define _TM_UNIX 0x00000100 /* AF_UNIX sockets */ +#define _TM_CMSG 0x00000200 /* AF_UNIX CMSG fd passing */ +#define _TM_IOCTL 0x00000400 /* scary */ +#define _TM_GETPW 0x00000800 /* enough to enable YP */ +#define _TM_PROC 0x00001000 /* fork, waitpid, etc */ +#define _TM_CPATH 0x00002000 /* allow create, mkdir, or inode mods */ + +#define _TM_ABORT 0x08000000 /* SIGABRT instea of SIGKILL */ + +/* Following flags are set by kernel, as it learns things. + * Not user settable. Should be moved to a seperate variable */ +#define _TM_USERSET 0x0fffffff +#define _TM_YP_ACTIVE 0x10000000 /* YP use detected and allowed */ +#define _TM_DNS_ACTIVE 0x20000000 /* DNS use detected and allowed */ + +#define TAME_MALLOC (_TM_SELF | _TM_MALLOC) +#define TAME_RW (_TM_SELF | _TM_RW) +#define TAME_STDIO (_TM_SELF | _TM_MALLOC | _TM_RW) +#define TAME_RPATH (_TM_SELF | _TM_RW | _TM_RPATH) +#define TAME_WPATH (_TM_SELF | _TM_RW | _TM_WPATH) +#define TAME_TMPPATH (_TM_SELF | _TM_RW | _TM_TMPPATH) +#define TAME_INET (_TM_SELF | _TM_RW | _TM_INET) +#define TAME_UNIX (_TM_SELF | _TM_RW | _TM_UNIX) +#define TAME_CMSG (TAME_UNIX | _TM_CMSG) +#define TAME_DNS (TAME_MALLOC | _TM_DNSPATH) +#define TAME_IOCTL (_TM_IOCTL) +#define TAME_GETPW (TAME_STDIO | _TM_GETPW) +#define TAME_PROC (_TM_PROC) +#define TAME_CPATH (_TM_CPATH) +#define TAME_ABORT (_TM_ABORT) + +#ifdef _KERNEL + +int tame_check(struct proc *, int); +int tame_fail(struct proc *, int, int); +int tame_namei(struct proc *, char *); +void tame_aftersyscall(struct proc *, int, int); + +int tame_cmsg_send(struct proc *p, void *v, int controllen); +int tame_cmsg_recv(struct proc *p, void *v, int controllen); +int tame_sysctl_check(struct proc *p, int namelen, int *name, void *new); +int tame_adjtime_check(struct proc *p, const void *v); +int tame_recvfrom_check(struct proc *p, void *from); +int tame_sendto_check(struct proc *p, const void *to); +int tame_bind_check(struct proc *p, const void *v); +int tame_connect_check(struct proc *p); +int tame_socket_check(struct proc *p, int domain); +int tame_setsockopt_check(struct proc *p, int level, int optname); +int tame_dns_check(struct proc *p, in_port_t port); +int tame_ioctl_check(struct proc *p, long com, void *); + +#else /* _KERNEL */ + +int tame(int); + +#endif /* _KERNEL */ + +#endif /* _SYS_TAME_H_ */ |