diff options
-rw-r--r-- | lib/libc/sys/tame.2 | 72 | ||||
-rw-r--r-- | sys/kern/init_sysent.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 12 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_ktrace.c | 27 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_tame.c | 327 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 3 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 3 | ||||
-rw-r--r-- | sys/kern/syscalls.c | 2 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 4 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 3 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 4 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 3 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 65 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 3 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 3 | ||||
-rw-r--r-- | sys/sys/proc.h | 17 | ||||
-rw-r--r-- | sys/sys/syscall.h | 4 | ||||
-rw-r--r-- | sys/sys/syscall_mi.h | 31 | ||||
-rw-r--r-- | sys/sys/syscallargs.h | 3 | ||||
-rw-r--r-- | sys/sys/tame.h | 20 |
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 */ |