summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2015-07-19 02:35:36 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2015-07-19 02:35:36 +0000
commitfe1980211f7663761eef0f79f3da7c2e6f040a0e (patch)
treec5574907a81a62734e4791da9c41f3193589233b /sys/kern
parent486443bb5d46e04bbe12808b344844c6257983d9 (diff)
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
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_fork.c4
-rw-r--r--sys/kern/kern_sig.c3
-rw-r--r--sys/kern/kern_sysctl.c6
-rw-r--r--sys/kern/kern_tame.c784
-rw-r--r--sys/kern/kern_time.c6
-rw-r--r--sys/kern/sys_generic.c14
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/kern/uipc_syscalls.c36
-rw-r--r--sys/kern/vfs_lookup.c10
-rw-r--r--sys/kern/vfs_syscalls.c27
10 files changed, 880 insertions, 14 deletions
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);