summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/tame.272
-rw-r--r--sys/kern/init_sysent.c4
-rw-r--r--sys/kern/kern_exit.c12
-rw-r--r--sys/kern/kern_fork.c5
-rw-r--r--sys/kern/kern_ktrace.c27
-rw-r--r--sys/kern/kern_sysctl.c3
-rw-r--r--sys/kern/kern_tame.c327
-rw-r--r--sys/kern/kern_time.c3
-rw-r--r--sys/kern/sys_generic.c3
-rw-r--r--sys/kern/syscalls.c2
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/kern/uipc_syscalls.c3
-rw-r--r--sys/kern/uipc_usrreq.c4
-rw-r--r--sys/kern/vfs_lookup.c3
-rw-r--r--sys/kern/vfs_syscalls.c65
-rw-r--r--sys/netinet/in_pcb.c3
-rw-r--r--sys/netinet6/in6_pcb.c3
-rw-r--r--sys/sys/proc.h17
-rw-r--r--sys/sys/syscall.h4
-rw-r--r--sys/sys/syscall_mi.h31
-rw-r--r--sys/sys/syscallargs.h3
-rw-r--r--sys/sys/tame.h20
22 files changed, 439 insertions, 179 deletions
diff --git a/lib/libc/sys/tame.2 b/lib/libc/sys/tame.2
index d517210cb46..0e3ebe7b75f 100644
--- a/lib/libc/sys/tame.2
+++ b/lib/libc/sys/tame.2
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tame.2,v 1.16 2015/08/21 07:26:09 doug Exp $
+.\" $OpenBSD: tame.2,v 1.17 2015/08/22 20:18:50 deraadt Exp $
.\"
.\" Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 21 2015 $
+.Dd $Mdocdate: August 22 2015 $
.Dt TAME 2
.Os
.Sh NAME
@@ -23,23 +23,25 @@
.Sh SYNOPSIS
.In sys/tame.h
.Ft int
-.Fn tame "int flags"
+.Fn tame "int flags" "char *paths[]"
.Sh DESCRIPTION
The current process is forced into a restricted-service operating mode.
A few subsets are available, roughly described as computation, memory
management, read-write operations on file descriptors, opening of files,
networking.
In general, these modes were selected by studying the operation
-of many programs using libc and other such interfaces.
+of many programs using libc and other such interfaces, and setting
+.Ar flags
+or
+.Ar paths .
.Pp
Use of
.Fn tame
in an application will require at least some study and understanding
of the interfaces called.
-.Pp
Subsequent calls to
.Fn tame
-can reduce abilities further, but abilities can never be regained.
+can reduce the abilities further, but abilities can never be regained.
.Pp
A process which attempts a restricted operation is killed with
.Dv SIGKILL .
@@ -98,7 +100,7 @@ permit the following system calls:
.Xr wait4 2 .
.Ed
.Pp
-Calls allowed with restrictions include:
+Some system calls, when allowed, have restrictions applied to them:
.Pp
.Bl -tag -width TAME_TMPPATH -offset indent -compact
.It Xr access 2
@@ -107,6 +109,15 @@ May check for existence of
.It Xr adjtime 2
Read-only, for
.Xr ntpd 8 .
+.It Xr chmod 2
+.It Xr fchmod 2
+.It Xr fchmodat 2
+.It Xr chown 2
+.It Xr lchown 2
+.It Xr fchown 2
+.It Xr fchownat 2
+Setuid/setgid bits do not work, nor can the user or group be changed
+on a file.
.It Xr open 2
May open
.Pa /etc/localtime ,
@@ -128,7 +139,9 @@ support:
.Xr uname 3 ,
system sensor readings.
.It Xr tame 2
-Can only reduce permissions.
+Can only reduce permissions; can only set a list of
+.Pa paths
+once.
.El
.Pp
The
@@ -172,10 +185,6 @@ libevent or handwritten async IO loops:
.Xr pwritev 2 ,
.Xr ftruncate 2 ,
.Xr lseek 2 ,
-.Xr utimes 2 ,
-.Xr futimes 2 ,
-.Xr utimensat 2 ,
-.Xr futimens 2 ,
.Xr fcntl 2 ,
.Xr fsync 2 ,
.Xr pipe 2 ,
@@ -192,8 +201,8 @@ This subset is simply the combination of
.Dv TAME_MALLOC
and
.Dv TAME_RW .
-As a result, all functionalities of libc
-stdio works.
+As a result, all the expected functionalities of libc
+stdio work.
.It Dv TAME_RPATH
A number of system calls are allowed if they only cause
read-only effects on the filesystem:
@@ -279,6 +288,26 @@ domains:
.Pp
.Xr setsockopt 2
has been reduced in functionality substantially.
+.It Dv TAME_FATTR
+The following system calls are allowed to make explicit changes
+to fields in
+.Va struct stat
+relating to a file:
+.Pp
+.Xr utimes 2 ,
+.Xr futimes 2 ,
+.Xr utimensat 2 ,
+.Xr futimens 2 ,
+.Xr chmod 2 ,
+.Xr fchmod 2 ,
+.Xr fchmodat 2 ,
+.Xr chflags 2 ,
+.Xr chflagsat 2 ,
+.Xr chown 2 ,
+.Xr fchownat 2 ,
+.Xr lchown 2 ,
+.Xr fchown 2 ,
+.Xr utimes 2 .
.It Dv TAME_UNIX
The following system calls are allowed to operate in the
.Dv AF_UNIX
@@ -358,14 +387,29 @@ Deliver an unblockable
upon violation instead of
.Dv SIGKILL .
.El
+.Pp
+A whitelist of permitted paths may be provided in
+.Ar paths .
+All other paths will return
+.Er ENOENT .
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS
.Fn tame
will fail if:
.Bl -tag -width Er
+.It Bq Er EFAULT
+.Fa paths
+points outside the process's allocated address space.
.It Bq Er EPERM
This process is attempting to increase permissions.
+.It Bq Er E2BIG
+The
+.Ar paths
+array is too large, or the total number of bytes exceeds a
+system-imposed limit.
+The limit in the system as released is 262144 bytes
+.Pf ( Dv ARG_MAX ) .
.El
.Sh HISTORY
The
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 9d0218d156d..68a8cf63796 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: init_sysent.c,v 1.168 2015/07/20 00:57:06 guenther Exp $ */
+/* $OpenBSD: init_sysent.c,v 1.169 2015/08/22 20:18:49 deraadt Exp $ */
/*
* System call switch table.
@@ -248,7 +248,7 @@ struct sysent sysent[] = {
sys_listen }, /* 106 = listen */
{ 4, s(struct sys_chflagsat_args), 0,
sys_chflagsat }, /* 107 = chflagsat */
- { 1, s(struct sys_tame_args), 0,
+ { 2, s(struct sys_tame_args), 0,
sys_tame }, /* 108 = tame */
{ 4, s(struct sys_ppoll_args), 0,
sys_ppoll }, /* 109 = ppoll */
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index ab9b157fc09..7ee0872bd72 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.149 2015/03/14 03:38:50 jsg Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.150 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -649,6 +649,16 @@ process_zap(struct process *pr)
*/
(void)chgproccnt(pr->ps_ucred->cr_ruid, -1);
+ if (pr->ps_tamepaths && --pr->ps_tamepaths->wl_ref == 0) {
+ struct whitepaths *wl = pr->ps_tamepaths;
+ 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_tamepaths = NULL;
+
/*
* Release reference to text vnode
*/
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index e7f7c1b138d..abcb77ba615 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.181 2015/07/19 02:35:35 deraadt Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.182 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -224,6 +224,9 @@ process_new(struct proc *p, struct process *parent, int flags)
else
pr->ps_vmspace = uvmspace_fork(parent);
+ if (pr->ps_tamepaths)
+ pr->ps_tamepaths->wl_ref++;
+
if (parent->ps_flags & PS_PROFIL)
startprofclock(pr);
if (flags & FORK_PTRACE)
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c
index aedc96f77fc..b4e930149b2 100644
--- a/sys/kern/kern_ktrace.c
+++ b/sys/kern/kern_ktrace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_ktrace.c,v 1.75 2015/08/01 20:12:34 guenther Exp $ */
+/* $OpenBSD: kern_ktrace.c,v 1.76 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: kern_ktrace.c,v 1.23 1996/02/09 18:59:36 christos Exp $ */
/*
@@ -384,7 +384,7 @@ ktruser(struct proc *p, const char *id, const void *addr, size_t len)
*/
/* ARGSUSED */
int
-sys_ktrace(struct proc *curp, void *v, register_t *retval)
+sys_ktrace(struct proc *p, void *v, register_t *retval)
{
struct sys_ktrace_args /* {
syscallarg(const char *) fname;
@@ -407,14 +407,15 @@ sys_ktrace(struct proc *curp, void *v, register_t *retval)
/*
* an operation which requires a file argument.
*/
- cred = curp->p_ucred;
+ cred = p->p_ucred;
+ p->p_tamenote = TMN_CPATH;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
- curp);
+ p);
if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0)
goto done;
vp = nd.ni_vp;
- VOP_UNLOCK(vp, 0, curp);
+ VOP_UNLOCK(vp, 0, p);
if (vp->v_type != VREG) {
error = EACCES;
goto done;
@@ -426,7 +427,7 @@ sys_ktrace(struct proc *curp, void *v, register_t *retval)
if (ops == KTROP_CLEARFILE) {
LIST_FOREACH(pr, &allprocess, ps_list) {
if (pr->ps_tracevp == vp) {
- if (ktrcanset(curp, pr))
+ if (ktrcanset(p, pr))
ktrcleartrace(pr);
else
error = EPERM;
@@ -442,9 +443,9 @@ sys_ktrace(struct proc *curp, void *v, register_t *retval)
goto done;
}
if (ops == KTROP_SET) {
- if (suser(curp, 0) == 0)
+ if (suser(p, 0) == 0)
facs |= KTRFAC_ROOT;
- ktrstart(curp, vp, cred);
+ ktrstart(p, vp, cred);
}
/*
* do it
@@ -460,10 +461,10 @@ sys_ktrace(struct proc *curp, void *v, register_t *retval)
}
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
if (descend)
- ret |= ktrsetchildren(curp, pr, ops, facs, vp,
+ ret |= ktrsetchildren(p, pr, ops, facs, vp,
cred);
else
- ret |= ktrops(curp, pr, ops, facs, vp, cred);
+ ret |= ktrops(p, pr, ops, facs, vp, cred);
}
} else {
/*
@@ -475,15 +476,15 @@ sys_ktrace(struct proc *curp, void *v, register_t *retval)
goto done;
}
if (descend)
- ret |= ktrsetchildren(curp, pr, ops, facs, vp, cred);
+ ret |= ktrsetchildren(p, pr, ops, facs, vp, cred);
else
- ret |= ktrops(curp, pr, ops, facs, vp, cred);
+ ret |= ktrops(p, pr, ops, facs, vp, cred);
}
if (!ret)
error = EPERM;
done:
if (vp != NULL)
- (void) vn_close(vp, FREAD|FWRITE, cred, curp);
+ (void) vn_close(vp, FREAD|FWRITE, cred, p);
return (error);
}
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index e00b101c01a..f62760c0718 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.287 2015/08/03 14:20:39 bluhm Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.288 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -70,7 +70,6 @@
#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>
diff --git a/sys/kern/kern_tame.c b/sys/kern/kern_tame.c
index 6aeef3c0f16..7a10752dae0 100644
--- a/sys/kern/kern_tame.c
+++ b/sys/kern/kern_tame.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_tame.c,v 1.20 2015/08/21 07:26:09 doug Exp $ */
+/* $OpenBSD: kern_tame.c,v 1.21 2015/08/22 20:18:49 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -39,8 +39,6 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
-#include <sys/tame.h>
-
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
@@ -77,8 +75,6 @@ const u_int tame_syscalls[SYS_MAXSYSCALL] = {
[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 */
/* needed by threaded programs */
@@ -121,18 +117,13 @@ const u_int tame_syscalls[SYS_MAXSYSCALL] = {
[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_fstat] = _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,
@@ -158,24 +149,18 @@ const u_int tame_syscalls[SYS_MAXSYSCALL] = {
[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_chdir] = _TM_RPATH,
+ [SYS___getcwd] = _TM_RPATH | _TM_WPATH,
+ [SYS_openat] = _TM_RPATH | _TM_WPATH,
+ [SYS_fstatat] = _TM_RPATH | _TM_WPATH,
+ [SYS_faccessat] = _TM_RPATH | _TM_WPATH,
[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,
@@ -187,17 +172,31 @@ const u_int tame_syscalls[SYS_MAXSYSCALL] = {
[SYS_mkdir] = _TM_CPATH,
[SYS_mkdirat] = _TM_CPATH,
- [SYS_fstat] = _TM_RW | _TM_RPATH | _TM_WPATH | _TM_TMPPATH, /* rare */
+ [SYS_utimes] = _TM_FATTR,
+ [SYS_futimes] = _TM_FATTR,
+ [SYS_utimensat] = _TM_FATTR,
+ [SYS_futimens] = _TM_FATTR,
+ [SYS_chmod] = _TM_FATTR,
+ [SYS_fchmod] = _TM_FATTR,
+ [SYS_fchmodat] = _TM_FATTR,
+ [SYS_chflags] = _TM_FATTR,
+ [SYS_chflagsat] = _TM_FATTR,
+ [SYS_chown] = _TM_FATTR,
+ [SYS_fchownat] = _TM_FATTR,
+ [SYS_lchown] = _TM_FATTR,
+ [SYS_fchown] = _TM_FATTR,
+ [SYS_utimes] = _TM_FATTR,
[SYS_socket] = _TM_INET | _TM_UNIX | _TM_DNS_ACTIVE | _TM_YP_ACTIVE,
+ [SYS_connect] = _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_setsockopt] = _TM_INET | _TM_UNIX,
[SYS_getsockopt] = _TM_INET | _TM_UNIX,
[SYS_flock] = _TM_GETPW,
@@ -208,24 +207,139 @@ sys_tame(struct proc *p, void *v, register_t *retval)
{
struct sys_tame_args /* {
syscallarg(int) flags;
+ syscallarg(char **)paths;
} */ *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);
+ if (flags & ~_TM_USERSET)
+ return (EINVAL);
+
+ if ((p->p_p->ps_flags & PS_TAMED)) {
+ /* Already tamed, only allow reductions */
+ if (((flags | p->p_p->ps_tame) & _TM_USERSET) !=
+ (p->p_p->ps_tame & _TM_USERSET)) {
+ printf("%s(%d): fail change %x %x\n", p->p_comm, p->p_pid,
+ flags, p->p_p->ps_tame);
+ return (EPERM);
+ }
+
+ flags &= p->p_p->ps_tame;
+ flags &= _TM_USERSET; /* Relearn _ACTIVE */
}
- /* May not set new bits */
- if (((flags | p->p_p->ps_tame) & _TM_USERSET) !=
- (p->p_p->ps_tame & _TM_USERSET))
- return (EPERM);
+ if (SCARG(uap, paths)) {
+ char **u = SCARG(uap, paths), *sp;
+ struct whitepaths *wl;
+ char *ipath, *path;
+ size_t len, maxargs = 0;
+ int i, error;
+
+ if (p->p_p->ps_tamepaths)
+ return (EPERM);
+
+ /* Count paths */
+ for (i = 0; i < TAME_MAXPATHS; i++) {
+ if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
+ return (error);
+ if (sp == NULL)
+ break;
+ }
+ if (i == TAME_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;
+
+ ipath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+
+ /* Copy in */
+ for (i = 0; i < wl->wl_count; i++) {
+ char *fullpath = path, *builtpath = NULL;
+ size_t builtlen;
+
+ if ((error = copyin(u + i, &sp, sizeof(sp))) != 0)
+ break;
+ if (sp == NULL)
+ break;
+ if ((error = copyinstr(sp, ipath, MAXPATHLEN, &len)) != 0)
+ break;
+
+ if (canonpath(ipath, path, MAXPATHLEN) != 0) {
+ free(ipath, M_TEMP, MAXPATHLEN);
+ free(path, M_TEMP, MAXPATHLEN);
+ return (tame_fail(p, EPERM, TAME_RPATH));
+ }
- /* More tame bits being cleared. Force re-learning of _ACTIVE things */
- p->p_p->ps_tame &= flags;
- p->p_p->ps_tame &= _TM_USERSET;
+ /* If path is relative, prepend cwd */
+ if (path[0] != '/') {
+ char *cwdpath, *bp, *bpend;
+ size_t cwdlen = MAXPATHLEN * 4;
+
+ cwdpath = malloc(cwdlen, M_TEMP, M_WAITOK);
+ bp = &cwdpath[cwdlen];
+ bpend = bp;
+ *(--bp) = '\0';
+
+ error = vfs_getcwd_common(p->p_fd->fd_cdir, NULL, &bp,
+ cwdpath, cwdlen/2, GETCWD_CHECK_ACCESS, p);
+ if (error) {
+ free(cwdpath, M_TEMP, cwdlen);
+ printf("getcwd: %d\n", error);
+ break;
+ }
+
+ /* NUL included in cwd component */
+ builtlen = (bpend - bp) + 1 + strlen(path);
+ if (builtlen > PATH_MAX) {
+ free(cwdpath, M_TEMP, cwdlen);
+ error = ENAMETOOLONG;
+ break;
+ }
+ builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
+ snprintf(builtpath, builtlen, "%s/%s", bp, path);
+ // printf("builtpath = %s\n", builtpath);
+ free(cwdpath, M_TEMP, cwdlen);
+ fullpath = builtpath;
+ len = builtlen;
+ }
+
+ if (maxargs += len > ARG_MAX) {
+ if (builtpath)
+ free(builtpath, M_TEMP, len);
+ error = E2BIG;
+ break;
+ }
+ wl->wl_paths[i].name = malloc(len, M_TEMP, M_WAITOK);
+ memcpy(wl->wl_paths[i].name, fullpath, len);
+ wl->wl_paths[i].len = len;
+ if (builtpath)
+ free(builtpath, M_TEMP, len);
+ }
+ free(ipath, M_TEMP, MAXPATHLEN);
+ free(path, M_TEMP, MAXPATHLEN);
+
+ if (error) {
+ printf("%s(%d): path load error %d\n",
+ p->p_comm, p->p_pid, 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_tamepaths = wl;
+ printf("%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("%d=%s\n", i, wl->wl_paths[i].name);
+ }
+
+ p->p_p->ps_tame = flags;
+ p->p_p->ps_flags |= PS_TAMED;
return (0);
}
@@ -246,8 +360,7 @@ tame_check(struct proc *p, int 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);
+ printf("%s(%d): syscall %d\n", p->p_comm, p->p_pid, p->p_tame_syscall);
if (p->p_p->ps_tame & _TM_ABORT) { /* Core dump requested */
struct sigaction sa;
@@ -277,10 +390,17 @@ tame_namei(struct proc *p, char *origpath)
if (canonpath(origpath, path, sizeof(path)) != 0)
return (tame_fail(p, EPERM, TAME_RPATH));
+ if ((p->p_tamenote & TMN_FATTR) &&
+ (p->p_p->ps_tame & _TM_FATTR) == 0) {
+ printf("%s(%d): inode syscall%d, not allowed\n",
+ p->p_comm, p->p_pid, p->p_tame_syscall);
+ return (tame_fail(p, EPERM, TAME_FATTR));
+ }
+
/* 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 &&
+ (p->p_tamenote & TMN_CPATH) &&
strncmp(path, "/tmp/", sizeof("/tmp/") - 1) == 0) {
return (0);
}
@@ -295,37 +415,26 @@ tame_namei(struct proc *p, char *origpath)
}
/* open, mkdir, or other path creation operation */
- if ((p->p_tamenote & (TMN_CREAT | TMN_IMODIFY)) == TMN_CREAT &&
+ if ((p->p_tamenote & TMN_CPATH) &&
((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) &&
+ if ((p->p_tamenote & TMN_WPATH) &&
(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 */
+ /* Read-only paths used occasionally by libc */
switch (p->p_tame_syscall) {
case SYS_access:
/* tzset() needs this. */
- if (strcmp(path, "/etc/localtime") == 0)
+ if ((p->p_tamenote == TMN_RPATH) &&
+ 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 ((p->p_tamenote == TMN_RPATH) &&
+ (p->p_p->ps_tame & _TM_GETPW)) {
if (strcmp(path, "/etc/spwd.db") == 0)
return (0);
if (strcmp(path, "/etc/pwd.db") == 0)
@@ -335,10 +444,10 @@ tame_namei(struct proc *p, char *origpath)
}
/* DNS needs /etc/{resolv.conf,hosts,services}. */
- if (p->p_p->ps_tame & _TM_DNSPATH) {
+ if ((p->p_tamenote == TMN_RPATH) &&
+ (p->p_p->ps_tame & _TM_DNSPATH)) {
if (strcmp(path, "/etc/resolv.conf") == 0) {
- p->p_tamenote |= TMN_DNSRESOLV;
- p->p_tameafter = 1;
+ p->p_tameafter |= TMA_DNSRESOLV;
return (0);
}
if (strcmp(path, "/etc/hosts") == 0)
@@ -346,10 +455,10 @@ tame_namei(struct proc *p, char *origpath)
if (strcmp(path, "/etc/services") == 0)
return (0);
}
- if (p->p_p->ps_tame & _TM_GETPW) {
+ if ((p->p_tamenote == TMN_RPATH) &&
+ (p->p_p->ps_tame & _TM_GETPW)) {
if (strcmp(path, "/var/run/ypbind.lock") == 0) {
- p->p_tamenote |= TMN_YPLOCK;
- p->p_tameafter = 1;
+ p->p_tameafter |= TMA_YPLOCK;
return (0);
}
if (strncmp(path, "/var/yp/binding/",
@@ -357,44 +466,108 @@ tame_namei(struct proc *p, char *origpath)
return (0);
}
/* tzset() needs these. */
- if (strncmp(path, "/usr/share/zoneinfo/",
+ if ((p->p_tamenote == TMN_RPATH) &&
+ strncmp(path, "/usr/share/zoneinfo/",
sizeof("/usr/share/zoneinfo/") - 1) == 0)
return (0);
- if (strcmp(path, "/etc/localtime") == 0)
+ if ((p->p_tamenote == TMN_RPATH) &&
+ strcmp(path, "/etc/localtime") == 0)
return (0);
/* /usr/share/nls/../libc.cat returns EPERM, for strerror(3). */
- if (strncmp(path, "/usr/share/nls/",
+ if ((p->p_tamenote == TMN_RPATH) &&
+ strncmp(path, "/usr/share/nls/",
sizeof("/usr/share/nls/") - 1) == 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)
+ if ((p->p_tamenote == TMN_RPATH) &&
+ 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;
+ if ((p->p_tamenote == TMN_RPATH) &&
+ (p->p_p->ps_tame & _TM_DNSPATH)) {
+ if (strcmp(path, "/etc/resolv.conf") == 0) {
+ p->p_tameafter |= 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_tamepaths) {
+ struct whitepaths *wl = p->p_p->ps_tamepaths;
+ char *fullpath = path, *builtpath = NULL;
+ size_t builtlen;
+ int i, error;
+
+ if (path[0] != '/') {
+ char *cwdpath, *bp, *bpend;
+ size_t cwdlen = MAXPATHLEN * 4;
+
+ cwdpath = malloc(cwdlen, M_TEMP, M_WAITOK);
+ bp = &cwdpath[cwdlen];
+ bpend = bp;
+ *(--bp) = '\0';
+
+ error = vfs_getcwd_common(p->p_fd->fd_cdir, NULL, &bp,
+ cwdpath, cwdlen/2, GETCWD_CHECK_ACCESS, p);
+ if (error) {
+ free(cwdpath, M_TEMP, cwdlen);
+ printf("getcwd: %d\n", error);
+ return (error);
+ }
+
+ /* NUL included in cwd component */
+ builtlen = (bpend - bp) + 1 + strlen(path);
+ builtpath = malloc(builtlen, M_TEMP, M_WAITOK);
+ snprintf(builtpath, builtlen, "%s/%s", bp, path);
+ // printf("builtpath = %s\n", builtpath);
+ free(cwdpath, M_TEMP, cwdlen);
+ fullpath = builtpath;
+ }
+
+ error = EACCES;
+ for (i = 0; i < wl->wl_count && wl->wl_paths[i].name && error; i++) {
+ if (strncmp(fullpath, wl->wl_paths[i].name,
+ wl->wl_paths[i].len - 1) == 0) {
+ char term = fullpath[wl->wl_paths[i].len];
+
+ if (term == '\0' || term == '/')
+ error = 0;
+ }
+ }
+ if (error)
+ printf("bad path: %s\n", fullpath);
+ if (builtpath)
+ free(builtpath, M_TEMP, builtlen);
+ if (error)
+ return (ENOENT); /* Don't hint why it failed */
+ }
+
+ if (p->p_p->ps_tame & _TM_RPATH)
+ return (0);
+
+ if (p->p_p->ps_tame & _TM_WPATH)
+ return (0);
+
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)
+ if ((p->p_tameafter & TMA_YPLOCK) && error == 0)
atomic_setbits_int(&p->p_p->ps_tame, _TM_YP_ACTIVE | TAME_INET);
- if ((p->p_tamenote & TMN_DNSRESOLV) && error == 0)
+ if ((p->p_tameafter & TMA_DNSRESOLV) && error == 0)
atomic_setbits_int(&p->p_p->ps_tame, _TM_DNS_ACTIVE);
}
@@ -603,8 +776,8 @@ tame_sysctl_check(struct proc *p, int namelen, int *name, void *new)
name[0] == CTL_HW && name[1] == HW_PAGESIZE)
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],
+ printf("%s(%d): sysctl %d: %d %d %d %d %d %d\n",
+ p->p_comm, p->p_pid, namelen, name[0], name[1],
name[2], name[3], name[4], name[5]);
return (EFAULT);
}
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 1e7553924ce..f8eccb3b98d 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_time.c,v 1.91 2015/07/19 02:35:35 deraadt Exp $ */
+/* $OpenBSD: kern_time.c,v 1.92 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */
/*
@@ -40,7 +40,6 @@
#include <sys/ktrace.h>
#include <sys/vnode.h>
#include <sys/signalvar.h>
-#include <sys/tame.h>
#include <sys/timetc.h>
#include <sys/mount.h>
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index d1c89d52c98..13491d425a2 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_generic.c,v 1.100 2015/07/28 05:50:41 guenther Exp $ */
+/* $OpenBSD: sys_generic.c,v 1.101 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */
/*
@@ -52,7 +52,6 @@
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/poll.h>
-#include <sys/tame.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index be9a837c740..2830e8d7374 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscalls.c,v 1.167 2015/07/20 00:57:06 guenther Exp $ */
+/* $OpenBSD: syscalls.c,v 1.168 2015/08/22 20:18:49 deraadt Exp $ */
/*
* System call names.
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 3ff01bd523c..3df64cd17c5 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.155 2015/07/20 00:56:10 guenther Exp $
+; $OpenBSD: syscalls.master,v 1.156 2015/08/22 20:18:49 deraadt Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -225,7 +225,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 STD { int sys_tame(int flags); }
+108 STD { int sys_tame(int flags, char **paths); }
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 9b785a06559..a283508101f 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_syscalls.c,v 1.106 2015/07/28 05:50:41 guenther Exp $ */
+/* $OpenBSD: uipc_syscalls.c,v 1.107 2015/08/22 20:18:49 deraadt Exp $ */
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
/*
@@ -45,7 +45,6 @@
#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
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index dcb64b05b1e..067a4310cc1 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_usrreq.c,v 1.83 2015/07/28 14:20:10 bluhm Exp $ */
+/* $OpenBSD: uipc_usrreq.c,v 1.84 2015/08/22 20:18:50 deraadt Exp $ */
/* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */
/*
@@ -421,6 +421,7 @@ unp_bind(struct unpcb *unp, struct mbuf *nam, struct proc *p)
/* Fixup sun_len to keep it in sync with m_len. */
soun->sun_len = nam2->m_len;
+ p->p_tamenote = TMN_CPATH;
NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE,
soun->sun_path, p);
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
@@ -479,6 +480,7 @@ unp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
else if (memchr(soun->sun_path, '\0', sizeof(soun->sun_path)) == NULL)
return (EINVAL);
+ p->p_tamenote = TMN_RPATH;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
if ((error = namei(&nd)) != 0)
return (error);
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index c7648e3af94..806fa1f6f61 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_lookup.c,v 1.54 2015/07/19 02:35:35 deraadt Exp $ */
+/* $OpenBSD: vfs_lookup.c,v 1.55 2015/08/22 20:18:50 deraadt Exp $ */
/* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */
/*
@@ -51,7 +51,6 @@
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/fcntl.h>
-#include <sys/tame.h>
#ifdef KTRACE
#include <sys/ktrace.h>
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index b5ac7b74bfb..45d8a1085e1 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_syscalls.c,v 1.222 2015/07/20 21:31:57 deraadt Exp $ */
+/* $OpenBSD: vfs_syscalls.c,v 1.223 2015/08/22 20:18:50 deraadt Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
/*
@@ -562,6 +562,7 @@ sys_statfs(struct proc *p, void *v, register_t *retval)
int error;
struct nameidata nd;
+ p->p_tamenote = TMN_RPATH;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -845,13 +846,18 @@ doopenat(struct proc *p, int fd, const char *path, int oflags, mode_t mode,
struct nameidata nd;
switch (oflags & O_ACCMODE) {
+ case O_RDONLY:
+ p->p_tamenote = TMN_RPATH;
+ break;
case O_WRONLY:
+ p->p_tamenote = TMN_WPATH;
+ break;
case O_RDWR:
- p->p_tamenote |= TMN_WRITE;
+ p->p_tamenote = TMN_RPATH | TMN_WPATH;
break;
}
if (oflags & O_CREAT)
- p->p_tamenote |= TMN_CREAT;
+ p->p_tamenote |= TMN_CPATH;
fdplock(fdp);
@@ -1195,7 +1201,6 @@ 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)));
}
@@ -1290,7 +1295,7 @@ sys_mkfifo(struct proc *p, void *v, register_t *retval)
syscallarg(mode_t) mode;
} */ *uap = v;
- p->p_tamenote |= TMN_CREAT;
+ p->p_tamenote = TMN_CPATH | TMN_RPATH;
return (domknodat(p, AT_FDCWD, SCARG(uap, path),
(SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0));
}
@@ -1320,7 +1325,6 @@ 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));
}
@@ -1353,6 +1357,7 @@ dolinkat(struct proc *p, int fd1, const char *path1, int fd2,
return (EINVAL);
follow = (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW;
+ p->p_tamenote = TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd1, path1, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -1363,6 +1368,7 @@ dolinkat(struct proc *p, int fd1, const char *path1, int fd2,
flags |= STRIPSLASHES;
}
+ p->p_tamenote = TMN_CPATH;
NDINITAT(&nd, CREATE, flags, UIO_USERSPACE, fd2, path2, p);
if ((error = namei(&nd)) != 0)
goto out;
@@ -1394,7 +1400,6 @@ 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)));
}
@@ -1423,6 +1428,7 @@ dosymlinkat(struct proc *p, const char *upath, int fd, const char *link)
error = copyinstr(upath, path, MAXPATHLEN, NULL);
if (error)
goto out;
+ p->p_tamenote = TMN_CPATH;
NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, link, p);
if ((error = namei(&nd)) != 0)
goto out;
@@ -1455,7 +1461,6 @@ 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));
}
@@ -1482,6 +1487,7 @@ dounlinkat(struct proc *p, int fd, const char *path, int flag)
if (flag & ~AT_REMOVEDIR)
return (EINVAL);
+ p->p_tamenote = TMN_CPATH;
NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
fd, path, p);
if ((error = namei(&nd)) != 0)
@@ -1602,6 +1608,7 @@ sys_access(struct proc *p, void *v, register_t *retval)
syscallarg(int) amode;
} */ *uap = v;
+ p->p_tamenote = TMN_RPATH;
return (dofaccessat(p, AT_FDCWD, SCARG(uap, path),
SCARG(uap, amode), 0));
}
@@ -1648,6 +1655,7 @@ dofaccessat(struct proc *p, int fd, const char *path, int amode, int flag)
newcred->cr_gid = newcred->cr_rgid;
}
+ p->p_tamenote = TMN_RPATH;
NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
goto out;
@@ -1716,7 +1724,9 @@ dofstatat(struct proc *p, int fd, const char *path, struct stat *buf, int flag)
if (flag & ~AT_SYMLINK_NOFOLLOW)
return (EINVAL);
+
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ p->p_tamenote = TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -1815,6 +1825,7 @@ doreadlinkat(struct proc *p, int fd, const char *path, char *buf,
int error;
struct nameidata nd;
+ p->p_tamenote = TMN_RPATH;
NDINITAT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -1849,7 +1860,6 @@ 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));
}
@@ -1878,6 +1888,7 @@ dochflagsat(struct proc *p, int fd, const char *path, u_int flags, int atflags)
return (EINVAL);
follow = (atflags & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -1948,7 +1959,6 @@ 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));
}
@@ -1976,10 +1986,14 @@ dofchmodat(struct proc *p, int fd, const char *path, mode_t mode, int flag)
if (mode & ~(S_IFMT | ALLPERMS))
return (EINVAL);
+ if ((p->p_p->ps_flags & PS_TAMED) &&
+ (mode & (S_ISUID|S_ISGID|S_ISTXT)))
+ return (tame_fail(p, EPERM, TAME_FATTR));
if (flag & ~AT_SYMLINK_NOFOLLOW)
return (EINVAL);
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2010,10 +2024,14 @@ sys_fchmod(struct proc *p, void *v, register_t *retval)
struct vattr vattr;
struct vnode *vp;
struct file *fp;
+ mode_t mode = SCARG(uap, mode);
int error;
- if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
+ if (mode & ~(S_IFMT | ALLPERMS))
return (EINVAL);
+ if ((p->p_p->ps_flags & PS_TAMED) &&
+ (mode & (S_ISUID|S_ISGID|S_ISTXT)))
+ return (tame_fail(p, EPERM, TAME_FATTR));
if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
return (error);
@@ -2023,7 +2041,7 @@ sys_fchmod(struct proc *p, void *v, register_t *retval)
error = EROFS;
else {
VATTR_NULL(&vattr);
- vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
+ vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
}
VOP_UNLOCK(vp, 0, p);
@@ -2044,7 +2062,6 @@ 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));
}
@@ -2078,6 +2095,7 @@ dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid,
return (EINVAL);
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2087,7 +2105,7 @@ dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid,
error = EROFS;
else {
if ((uid != -1 || gid != -1) &&
- (suser(p, 0) || suid_clear)) {
+ (suser(p, 0) || (p->p_p->ps_flags & PS_TAMED) || suid_clear)) {
error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
if (error)
goto out;
@@ -2128,7 +2146,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;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2138,7 +2156,7 @@ sys_lchown(struct proc *p, void *v, register_t *retval)
error = EROFS;
else {
if ((uid != -1 || gid != -1) &&
- (suser(p, 0) || suid_clear)) {
+ (suser(p, 0) || (p->p_p->ps_flags & PS_TAMED) || suid_clear)) {
error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
if (error)
goto out;
@@ -2187,7 +2205,7 @@ sys_fchown(struct proc *p, void *v, register_t *retval)
error = EROFS;
else {
if ((uid != -1 || gid != -1) &&
- (suser(p, 0) || suid_clear)) {
+ (suser(p, 0) || (p->p_p->ps_flags & PS_TAMED) || suid_clear)) {
error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
if (error)
goto out;
@@ -2225,7 +2243,6 @@ 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));
@@ -2277,6 +2294,7 @@ doutimensat(struct proc *p, int fd, const char *path,
return (EINVAL);
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2421,7 +2439,7 @@ sys_truncate(struct proc *p, void *v, register_t *retval)
int error;
struct nameidata nd;
- p->p_tamenote |= TMN_IMODIFY;
+ p->p_tamenote = TMN_FATTR | TMN_RPATH;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2521,7 +2539,6 @@ 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)));
}
@@ -2549,6 +2566,7 @@ dorenameat(struct proc *p, int fromfd, const char *from, int tofd,
int error;
int flags;
+ p->p_tamenote = TMN_RPATH | TMN_CPATH;
NDINITAT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
fromfd, from, p);
if ((error = namei(&fromnd)) != 0)
@@ -2562,6 +2580,7 @@ dorenameat(struct proc *p, int fromfd, const char *from, int tofd,
if (fvp->v_type == VDIR)
flags |= STRIPSLASHES;
+ p->p_tamenote = TMN_CPATH;
NDINITAT(&tond, RENAME, flags, UIO_USERSPACE, tofd, to, p);
if ((error = namei(&tond)) != 0) {
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
@@ -2630,7 +2649,7 @@ sys_mkdir(struct proc *p, void *v, register_t *retval)
syscallarg(mode_t) mode;
} */ *uap = v;
- p->p_tamenote |= TMN_CREAT;
+ p->p_tamenote = TMN_CPATH | TMN_RPATH;
return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode)));
}
@@ -2655,6 +2674,7 @@ domkdirat(struct proc *p, int fd, const char *path, mode_t mode)
int error;
struct nameidata nd;
+ p->p_tamenote = TMN_CPATH | TMN_RPATH;
NDINITAT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, UIO_USERSPACE,
fd, path, p);
if ((error = namei(&nd)) != 0)
@@ -2689,7 +2709,7 @@ sys_rmdir(struct proc *p, void *v, register_t *retval)
syscallarg(const char *) path;
} */ *uap = v;
- p->p_tamenote |= TMN_CREAT;
+ p->p_tamenote = TMN_CPATH | TMN_RPATH;
return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR));
}
@@ -2784,7 +2804,6 @@ 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 8b671259b28..000b0459c6c 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.173 2015/08/19 13:27:38 bluhm Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.174 2015/08/22 20:18:50 deraadt Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -79,7 +79,6 @@
#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>
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 1d963ed8091..8f47205ec36 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_pcb.c,v 1.69 2015/07/19 02:35:35 deraadt Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.70 2015/08/22 20:18:50 deraadt Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -109,7 +109,6 @@
#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>
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index dab3840a45c..95fe0d6f458 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.203 2015/07/27 18:22:37 deraadt Exp $ */
+/* $OpenBSD: proc.h,v 1.204 2015/08/22 20:18:50 deraadt Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -47,6 +47,7 @@
#include <sys/timeout.h> /* For struct timeout */
#include <sys/event.h> /* For struct klist */
#include <sys/mutex.h> /* For struct mutex */
+#include <sys/tame.h>
#include <sys/resource.h> /* For struct rusage */
#include <machine/atomic.h>
@@ -212,6 +213,7 @@ struct process {
u_short ps_acflag; /* Accounting flags. */
u_int ps_tame;
+ struct whitepaths *ps_tamepaths;
int64_t ps_kbind_cookie;
u_long ps_kbind_addr;
@@ -326,13 +328,14 @@ struct proc {
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
-#define TMN_COREDUMP 0x00000020
+#define TMN_RPATH 0x00000001
+#define TMN_WPATH 0x00000002
+#define TMN_CPATH 0x00000004
+#define TMN_FATTR 0x00000008
+#define TMN_COREDUMP 0x00000010
int p_tameafter;
+#define TMA_YPLOCK 0x00000001
+#define TMA_DNSRESOLV 0x00000002
#ifndef __HAVE_MD_TCB
void *p_tcb; /* user-space thread-control-block address */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 3b40f4f492a..773a1123a12 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.166 2015/07/20 00:57:06 guenther Exp $ */
+/* $OpenBSD: syscall.h,v 1.167 2015/08/22 20:18:50 deraadt Exp $ */
/*
* System call numbers.
@@ -331,7 +331,7 @@
/* syscall: "chflagsat" ret: "int" args: "int" "const char *" "u_int" "int" */
#define SYS_chflagsat 107
-/* syscall: "tame" ret: "int" args: "int" */
+/* syscall: "tame" ret: "int" args: "int" "char **" */
#define SYS_tame 108
/* syscall: "ppoll" ret: "int" args: "struct pollfd *" "u_int" "const struct timespec *" "const sigset_t *" */
diff --git a/sys/sys/syscall_mi.h b/sys/sys/syscall_mi.h
index babc70a6eac..49391c28a55 100644
--- a/sys/sys/syscall_mi.h
+++ b/sys/sys/syscall_mi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall_mi.h,v 1.7 2015/07/19 04:45:25 guenther Exp $ */
+/* $OpenBSD: syscall_mi.h,v 1.8 2015/08/22 20:18:50 deraadt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -33,7 +33,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/tame.h>
#include <sys/proc.h>
#ifdef KTRACE
@@ -72,15 +71,6 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp,
}
#endif
-#if NSYSTRACE > 0
- if (ISSET(p->p_flag, P_SYSTRACE)) {
- KERNEL_LOCK();
- error = systrace_redirect(code, p, argp, retval);
- KERNEL_UNLOCK();
- return (error);
- }
-#endif
-
if (lock)
KERNEL_LOCK();
tamed = (p->p_p->ps_flags & PS_TAMED);
@@ -88,14 +78,21 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp,
if (!lock)
KERNEL_LOCK();
error = tame_fail(p, EPERM, tval);
+ KERNEL_UNLOCK();
+ return (error);
+ }
+#if NSYSTRACE > 0
+ if (!tamed && ISSET(p->p_flag, P_SYSTRACE)) {
if (!lock)
- KERNEL_UNLOCK();
- }
- else {
- error = (*callp->sy_call)(p, argp, retval);
- if (tamed && p->p_tameafter)
- tame_aftersyscall(p, code, error);
+ KERNEL_LOCK();
+ error = systrace_redirect(code, p, argp, retval);
+ KERNEL_UNLOCK();
+ return (error);
}
+#endif
+ error = (*callp->sy_call)(p, argp, retval);
+ if (tamed && p->p_tameafter)
+ tame_aftersyscall(p, code, error);
if (lock)
KERNEL_UNLOCK();
diff --git a/sys/sys/syscallargs.h b/sys/sys/syscallargs.h
index 7344a9cfc95..04aff28c321 100644
--- a/sys/sys/syscallargs.h
+++ b/sys/sys/syscallargs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscallargs.h,v 1.168 2015/07/20 00:57:06 guenther Exp $ */
+/* $OpenBSD: syscallargs.h,v 1.169 2015/08/22 20:18:50 deraadt Exp $ */
/*
* System call argument lists.
@@ -546,6 +546,7 @@ struct sys_chflagsat_args {
struct sys_tame_args {
syscallarg(int) flags;
+ syscallarg(char **) paths;
};
struct sys_ppoll_args {
diff --git a/sys/sys/tame.h b/sys/sys/tame.h
index 25010d4a23b..7346f439d99 100644
--- a/sys/sys/tame.h
+++ b/sys/sys/tame.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tame.h,v 1.3 2015/07/28 15:22:25 deraadt Exp $ */
+/* $OpenBSD: tame.h,v 1.4 2015/08/22 20:18:50 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -35,7 +35,8 @@
#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_CPATH 0x00002000 /* allow creat, mkdir, path creations */
+#define _TM_FATTR 0x00004000 /* allow explicit file st_* mods */
#define _TM_ABORT 0x08000000 /* SIGABRT instead of SIGKILL */
@@ -60,6 +61,7 @@
#define TAME_PROC (_TM_PROC)
#define TAME_CPATH (_TM_CPATH)
#define TAME_ABORT (_TM_ABORT)
+#define TAME_FATTR (_TM_FATTR)
#ifdef _KERNEL
@@ -81,9 +83,21 @@ 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 *);
+#define TAME_MAXPATHS 8192
+
+struct whitepaths {
+ size_t wl_size;
+ int wl_count;
+ int wl_ref;
+ struct whitepath {
+ char *name;
+ size_t len;
+ } wl_paths[0];
+};
+
#else /* _KERNEL */
-int tame(int);
+int tame(int, char **);
#endif /* _KERNEL */