Sync with OpenBSD systrace 1.6d.

XXX: Some of the compat-linux systrace is disabled.
From elad.
This commit is contained in:
christos 2006-12-10 01:22:02 +00:00
parent ba06ad7411
commit ddbf1b0dd9
12 changed files with 508 additions and 142 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: filter.c,v 1.31 2005/08/24 19:09:03 elad Exp $ */
/* $NetBSD: filter.c,v 1.32 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: filter.c,v 1.16 2002/08/08 21:18:20 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -30,7 +30,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: filter.c,v 1.31 2005/08/24 19:09:03 elad Exp $");
__RCSID("$NetBSD: filter.c,v 1.32 2006/12/10 01:22:02 christos Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -400,6 +400,10 @@ filter_modifypolicy(int fd, int policynr, const char *emulation,
{
struct systrace_revalias *reverse = NULL;
/*
* Check if we are dealing with a system call that really
* is an alias for something else.
*/
if (!noalias)
reverse = systrace_find_reverse(emulation, name);
if (reverse == NULL) {
@ -444,6 +448,11 @@ filter_quickpredicate(struct filter *filter)
return (1);
}
/*
* Processes the filters for a policy that have not been applied yet.
* Pre-filters get installed when reading a policy. This function
* installs a fast-path in the kernel.
*/
int
filter_prepolicy(int fd, struct policy *policy)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: intercept.c,v 1.26 2005/12/31 12:33:41 elad Exp $ */
/* $NetBSD: intercept.c,v 1.27 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: intercept.c,v 1.29 2002/08/28 03:30:27 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -30,7 +30,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: intercept.c,v 1.26 2005/12/31 12:33:41 elad Exp $");
__RCSID("$NetBSD: intercept.c,v 1.27 2006/12/10 01:22:02 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -555,6 +555,9 @@ intercept_get_string(int fd, pid_t pid, void *addr)
static char name[8192];
int off = 0, done = 0, stride;
if (addr == NULL)
return (NULL);
stride = 32;
do {
if (intercept.io(fd, pid, INTERCEPT_READ, (char *)addr + off,
@ -642,7 +645,6 @@ normalize_filename(int fd, pid_t pid, char *name, int userp)
havecwd = 1;
}
/* Need concatenated path for simplifypath */
if (havecwd && name[0] != '/') {
if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd))
return (NULL);
@ -707,7 +709,7 @@ normalize_filename(int fd, pid_t pid, char *name, int userp)
*/
if (userp != ICLINK_NOLAST) {
if (lstat(rcwd, &st) == -1 ||
!(st.st_mode & S_IFDIR))
!S_ISDIR(st.st_mode))
failed = 1;
}
}
@ -891,6 +893,12 @@ intercept_assignpolicy(int fd, pid_t pid, int policynr)
return (intercept.assignpolicy(fd, pid, policynr));
}
int
intercept_modifypolicy_nr(int fd, int policynr, int code, short policy)
{
return (intercept.policy(fd, policynr, code, policy));
}
int
intercept_modifypolicy(int fd, int policynr, const char *emulation,
const char *name, short policy)
@ -964,13 +972,28 @@ intercept_ugid(struct intercept_pid *icpid, uid_t uid, gid_t gid)
icpid->gid = gid;
}
/*
* Returns the number of a system call
*/
int
intercept_getsyscallnumber(const char *emulation, const char *name)
{
int nr = intercept.getsyscallnumber(emulation, name);
if (nr >= INTERCEPT_MAXSYSCALLNR)
err(1, "%s: system call number too high: %d", __func__, nr);
return (nr);
}
/*
* Checks if the given emulation has a certain system call.
* This is a very slow function.
*/
int
intercept_isvalidsystemcall(char *emulation, char *name)
intercept_isvalidsystemcall(const char *emulation, const char *name)
{
int res;

View File

@ -1,4 +1,4 @@
/* $NetBSD: intercept.h,v 1.19 2006/04/16 05:19:02 provos Exp $ */
/* $NetBSD: intercept.h,v 1.20 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: intercept.h,v 1.11 2002/08/04 04:15:50 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -111,6 +111,7 @@ struct intercept_pid {
struct elevate *elevate; /* privilege elevation request */
};
#define INTERCEPT_MAXSYSCALLNR 512
#define INTERCEPT_MAXSYSCALLARGS 10
struct intercept_translate {
@ -126,6 +127,7 @@ struct intercept_translate {
size_t trans_size;
char *trans_print;
u_int trans_flags;
void *user;
TAILQ_ENTRY(intercept_translate) next;
};
@ -149,6 +151,7 @@ int intercept_read(int);
int intercept_newpolicy(int);
int intercept_assignpolicy(int, pid_t, int);
int intercept_modifypolicy(int, int, const char *, const char *, short);
int intercept_modifypolicy_nr(int, int, int, short);
void intercept_child_info(pid_t, pid_t);
void intercept_policy_free(int);
@ -197,12 +200,13 @@ void intercept_syscall(int, pid_t, u_int16_t, int, const char *, int,
const char *, void *, int);
void intercept_syscall_result(int, pid_t, u_int16_t, int, const char *, int,
const char *, void *, int, int, void *);
void intercept_ugid(struct intercept_pid *, uid_t, gid_t);
void intercept_setpid(struct intercept_pid *, uid_t, gid_t);
void intercept_newimage(int, pid_t, int, const char *, char *,
struct intercept_pid *);
void intercept_ugid(struct intercept_pid *, uid_t, gid_t);
void intercept_setpid(struct intercept_pid *, uid_t, gid_t);
int intercept_isvalidsystemcall(char *, char *);
int intercept_getsyscallnumber(const char *, const char *);
int intercept_isvalidsystemcall(const char *, const char *);
char *intercept_realpath(const char *, char *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: netbsd-syscalls.c,v 1.19 2005/06/27 17:11:20 elad Exp $ */
/* $NetBSD: netbsd-syscalls.c,v 1.20 2006/12/10 01:22:02 christos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: netbsd-syscalls.c,v 1.19 2005/06/27 17:11:20 elad Exp $");
__RCSID("$NetBSD: netbsd-syscalls.c,v 1.20 2006/12/10 01:22:02 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -466,6 +466,8 @@ nbsd_replace(int fd, pid_t pid, u_int16_t seqnr,
size_t len, off;
int i, ret;
memset(&replace, 0, sizeof(replace));
for (i = 0, len = 0; i < repl->num; i++) {
len += repl->len[i];
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: openbsd-syscalls.c,v 1.9 2003/08/25 09:12:45 cb Exp $ */
/* $NetBSD: openbsd-syscalls.c,v 1.10 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: openbsd-syscalls.c,v 1.12 2002/08/28 03:30:27 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -436,6 +436,8 @@ obsd_replace(int fd, pid_t pid, u_int16_t seqnr,
size_t len, off;
int i, ret;
memset(&replace, 0, sizeof(replace));
for (i = 0, len = 0; i < repl->num; i++) {
len += repl->len[i];
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: policy.c,v 1.21 2006/03/18 00:35:02 peter Exp $ */
/* $NetBSD: policy.c,v 1.22 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: policy.c,v 1.15 2002/08/07 00:34:17 vincent Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -30,7 +30,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: policy.c,v 1.21 2006/03/18 00:35:02 peter Exp $");
__RCSID("$NetBSD: policy.c,v 1.22 2006/12/10 01:22:02 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -46,6 +46,7 @@ __RCSID("$NetBSD: policy.c,v 1.21 2006/03/18 00:35:02 peter Exp $");
#include <fcntl.h>
#include <ctype.h>
#include <err.h>
#include <libgen.h>
#include "intercept.h"
#include "systrace.h"
@ -132,7 +133,7 @@ systrace_setupdir(char *path)
if (stat(policydir, &sb) != -1) {
if (!(sb.st_mode & S_IFDIR))
if (!S_ISDIR(sb.st_mode))
errx(1, "Not a directory: \"%s\"", policydir);
} else if (mkdir(policydir, 0700) == -1)
err(1, "mkdir(%s)", policydir);
@ -150,11 +151,39 @@ systrace_initpolicy(char *file, char *path)
}
if (file != NULL)
return (systrace_readpolicy(file));
return (systrace_readpolicy(file) != NULL ? 0 : -1);
return (0);
}
struct policy *
systrace_findpolicy_wildcard(const char *name)
{
struct policy tmp, *res;
static char path[MAXPATHLEN], lookup[MAXPATHLEN];
if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
errx(1, "%s: path name overflow", __func__);
strlcpy(lookup, "*/", sizeof(lookup));
strlcat(lookup, basename(path), sizeof(lookup));
tmp.name = lookup;
res = SPLAY_FIND(policytree, &policyroot, &tmp);
if (res == NULL)
return (NULL);
/* we found the wildcarded policy; now remove it and bind it */
SPLAY_REMOVE(policytree, &policyroot, res);
free(__UNCONST(res->name));
if ((res->name = strdup(name)) == NULL)
err(1, "%s: strdup", __func__);
SPLAY_INSERT(policytree, &policyroot, res);
return (res);
}
struct policy *
systrace_findpolicy(const char *name)
{
@ -195,10 +224,14 @@ struct policy *
systrace_newpolicy(const char *emulation, const char *name)
{
struct policy *tmp;
int i;
if ((tmp = systrace_findpolicy(name)) != NULL)
return (tmp);
if ((tmp = systrace_findpolicy_wildcard(name)) != NULL)
return (tmp);
tmp = calloc(1, sizeof(struct policy));
if (tmp == NULL)
return (NULL);
@ -215,20 +248,23 @@ systrace_newpolicy(const char *emulation, const char *name)
TAILQ_INIT(&tmp->filters);
TAILQ_INIT(&tmp->prefilters);
/* Set the default policy to ask */
for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++)
tmp->kerneltable[i] = ICPOLICY_ASK;
return (tmp);
}
void
systrace_freepolicy(struct policy *policy)
systrace_cleanpolicy(struct policy *policy)
{
struct filter *filter;
struct policy_syscall *pflq;
int i;
if (policy->flags & POLICY_CHANGED) {
if (systrace_writepolicy(policy) == -1)
fprintf(stderr, "Failed to write policy for %s\n",
policy->name);
}
/* Set the default policy to ask */
for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++)
policy->kerneltable[i] = ICPOLICY_ASK;
while ((filter = TAILQ_FIRST(&policy->prefilters)) != NULL) {
TAILQ_REMOVE(&policy->prefilters, filter, policy_next);
@ -250,6 +286,18 @@ systrace_freepolicy(struct policy *policy)
free(pflq);
}
}
void
systrace_freepolicy(struct policy *policy)
{
if (policy->flags & POLICY_CHANGED) {
if (systrace_writepolicy(policy) == -1)
fprintf(stderr, "Failed to write policy for %s\n",
policy->name);
}
systrace_cleanpolicy(policy);
SPLAY_REMOVE(policytree, &policyroot, policy);
if (policy->policynr != -1)
@ -289,7 +337,7 @@ int
systrace_modifypolicy(int fd, int policynr, const char *name, short action)
{
struct policy *policy;
int res;
int res, nr;
if ((policy = systrace_findpolnr(policynr)) == NULL)
return (-1);
@ -297,20 +345,29 @@ systrace_modifypolicy(int fd, int policynr, const char *name, short action)
res = intercept_modifypolicy(fd, policynr, policy->emulation,
name, action);
/* Remember the kernel policy */
if (res != -1 &&
(nr = intercept_getsyscallnumber(policy->emulation, name)) != -1)
policy->kerneltable[nr] = action;
return (res);
}
/*
* Converts an executable name into the corresponding filename that contains
* the policy.
*/
char *
systrace_policyfilename(const char *dirname, const char *name)
systrace_policyfilename(const char *pdirname, const char *name)
{
static char file[2*MAXPATHLEN];
const char *p;
int i, plen;
if (strlen(name) + strlen(dirname) + 1 >= sizeof(file))
if (strlen(name) + strlen(pdirname) + 1 >= sizeof(file))
return (NULL);
strlcpy(file, dirname, sizeof(file));
strlcpy(file, pdirname, sizeof(file));
i = strlen(file);
file[i++] = '/';
plen = i;
@ -331,7 +388,7 @@ systrace_policyfilename(const char *dirname, const char *name)
}
char *
systrace_getpolicyfilename(const char *name)
systrace_getpolicyname(const char *name)
{
char *file = NULL;
@ -354,10 +411,10 @@ systrace_addpolicy(const char *name)
{
char *file = NULL;
if ((file = systrace_getpolicyfilename(name)) == NULL)
if ((file = systrace_getpolicyname(name)) == NULL)
return (-1);
return (systrace_readpolicy(file));
return (systrace_readpolicy(file) != NULL ? 0 : -1);
}
/*
@ -387,7 +444,7 @@ systrace_templatedir(void)
goto error;
/* Check if template directory exists */
if (stat(filename, &sb) != -1 && (sb.st_mode & S_IFDIR))
if (stat(filename, &sb) != -1 && S_ISDIR(sb.st_mode))
dir = opendir(filename);
}
@ -395,7 +452,7 @@ systrace_templatedir(void)
if (dir == NULL) {
strlcpy(filename, POLICY_PATH, sizeof(filename));
strlcat(filename, "/templates", sizeof(filename));
if (stat(filename, &sb) != -1 && (sb.st_mode & S_IFDIR))
if (stat(filename, &sb) != -1 && S_ISDIR(sb.st_mode))
dir = opendir(filename);
if (dir == NULL)
return (-1);
@ -411,7 +468,7 @@ systrace_templatedir(void)
sizeof(filename))
goto error;
if (stat(filename, &sb) == -1 || !(sb.st_mode & S_IFREG))
if (stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode))
continue;
template = systrace_readtemplate(filename, NULL, NULL);
@ -426,6 +483,8 @@ systrace_templatedir(void)
error:
errx(1, "%s: template name too long", __func__);
/*NOTREACHED*/
}
struct template *
@ -507,8 +566,9 @@ systrace_readtemplate(char *filename, struct policy *policy,
goto out;
}
/* Removes trailing whitespace and comments from the input line */
/*
* Removes trailing whitespace and comments from the input line.
*/
static char *
systrace_policyline(char *line)
{
@ -594,7 +654,8 @@ systrace_policyprocess(struct policy *policy, char *p)
} else if (filter_parse_simple(rule, &action, &future) == 0)
resolved = 1;
/* For now, everything that does not seem to be a valid syscall
/*
* For now, everything that does not seem to be a valid syscall
* does not get fast kernel policies even though the aliasing
* system supports it.
*/
@ -628,8 +689,13 @@ systrace_policyprocess(struct policy *policy, char *p)
return (0);
}
int
systrace_readpolicy(char *filename)
/*
* Reads policy from specified file.
* If policy exists already, this function appends new statements from the
* file to the existing policy.
*/
struct policy *
systrace_readpolicy(const char *filename)
{
FILE *fp;
struct policy *policy;
@ -639,7 +705,7 @@ systrace_readpolicy(char *filename)
int res = -1;
if ((fp = fopen(filename, "r")) == NULL)
return (-1);
return (NULL);
policy = NULL;
while (fgets(line, sizeof(line), fp)) {
@ -655,6 +721,8 @@ systrace_readpolicy(char *filename)
continue;
if (!strncasecmp(p, "Policy: ", 8)) {
struct timeval now;
p += 8;
name = strsep(&p, ",");
if (p == NULL)
@ -667,6 +735,10 @@ systrace_readpolicy(char *filename)
policy = systrace_newpolicy(emulation, name);
if (policy == NULL)
goto error;
/* Update access time */
gettimeofday(&now, NULL);
TIMEVAL_TO_TIMESPEC(&now, &policy->ts_last);
continue;
}
@ -686,13 +758,64 @@ systrace_readpolicy(char *filename)
out:
fclose(fp);
return (res);
return (res == -1 ? NULL : policy);
error:
fprintf(stderr, "%s:%d: syntax error.\n", filename, linenumber);
goto out;
}
/*
* Appends new policy statements if the policy has been updated by
* another process. Assumes that policies are append-only.
*
* Returns:
* -1 if the policy could not be updated.
* 0 if the policy has been updated.
*/
int
systrace_updatepolicy(int fd, struct policy *policy)
{
struct stat sb;
struct timespec mtimespec;
int i, policynr = policy->policynr;
char *file;
if ((file = systrace_getpolicyname(policy->name)) == NULL)
return (-1);
if (stat(file, &sb) == -1)
return (-1);
mtimespec = sb.st_mtimespec;
/* Policy does not need updating */
if (timespeccmp(&mtimespec, &policy->ts_last, <=))
return (-1);
/* Reset the existing policy */
for (i = 0; i < INTERCEPT_MAXSYSCALLNR; i++) {
if (policy->kerneltable[i] == ICPOLICY_ASK)
continue;
if (intercept_modifypolicy_nr(fd, policynr, i,
ICPOLICY_ASK) == -1)
errx(1, "%s: failed to modify policy for %d",
__func__, i);
}
/* Now clean up all filter structures in this policy */
systrace_cleanpolicy(policy);
/* XXX - This does not deal with Detached and Automatic */
if (systrace_readpolicy(file) == NULL)
return (-1);
/* Resets the changed flag */
filter_prepolicy(fd, policy);
return (0);
}
int
systrace_writepolicy(struct policy *policy)
{
@ -702,6 +825,7 @@ systrace_writepolicy(struct policy *policy)
char tmpname[2*MAXPATHLEN];
char finalname[2*MAXPATHLEN];
struct filter *filter;
struct timeval now;
if ((p = systrace_policyfilename(policydir, policy->name)) == NULL)
return (-1);
@ -741,11 +865,33 @@ systrace_writepolicy(struct policy *policy)
return (-1);
}
/* Update access time */
gettimeofday(&now, NULL);
TIMEVAL_TO_TIMESPEC(&now, &policy->ts_last);
return (0);
}
int
systrace_dumppolicy(void)
systrace_updatepolicies(int fd)
{
struct policy *policy;
SPLAY_FOREACH(policy, policytree, &policyroot) {
/* Check if the policy has been updated */
systrace_updatepolicy(fd, policy);
}
return (0);
}
/*
* Write policy to disk if it has been changed. We need to
* call systrace_updatepolicies() before this, so that we
* don't clobber changes.
*/
int
systrace_dumppolicies(int fd)
{
struct policy *policy;

View File

@ -1,4 +1,4 @@
/* $NetBSD: register.c,v 1.19 2006/08/21 01:35:11 christos Exp $ */
/* $NetBSD: register.c,v 1.20 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: register.c,v 1.11 2002/08/05 14:49:27 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -37,9 +37,13 @@
#include <unistd.h>
#include <stdio.h>
#include <err.h>
#include <time.h>
#include "intercept.h"
#include "systrace.h"
#ifdef notyet /* XXX we don't have the required headers for this */
#include "linux_socketcall.h"
#endif
#define X(x) if ((x) == -1) \
err(1, "%s:%d: intercept failed", __func__, __LINE__)
@ -425,7 +429,7 @@ systrace_initcb(void)
intercept_register_translation("native", "seteuid", 0, &ic_uname);
#endif
#if !(defined(__NetBSD__) && !defined(HAVE_LINUX_FCNTL_H))
#if !(defined(__NetBSD__) || !defined(HAVE_LINUX_FCNTL_H))
/* 5: open [fswrite] */
X(intercept_register_sccb("linux", "open", trans_cb, NULL));
tl = intercept_register_translink("linux", "open", 0);
@ -459,6 +463,11 @@ systrace_initcb(void)
alias = systrace_new_alias("linux", "access", "linux", "fsread");
systrace_alias_add_trans(alias, tl);
/* 37: kill */
X(intercept_register_sccb("linux", "kill", trans_cb, NULL));
intercept_register_translation("linux", "kill", 0, &ic_pidname);
intercept_register_translation("linux", "kill", 1, &ic_signame);
/* 38: rename */
X(intercept_register_sccb("linux", "rename", trans_cb, NULL));
intercept_register_translink("linux", "rename", 0);
@ -487,6 +496,20 @@ systrace_initcb(void)
alias = systrace_new_alias("linux", "readlink", "linux", "fsread");
systrace_alias_add_trans(alias, tl);
/* 102: socketcall */
X(intercept_register_sccb("linux", "socketcall", trans_cb, NULL));
alias = systrace_new_alias("linux", "socketcall", "linux", "_socketcall");
tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_socket_sockdom);
systrace_alias_add_trans(alias, tl);
tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_socket_socktype);
systrace_alias_add_trans(alias, tl);
tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_connect_sockaddr);
systrace_alias_add_trans(alias, tl);
tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_bind_sockaddr);
systrace_alias_add_trans(alias, tl);
tl = intercept_register_translation("linux", "socketcall", 0, &ic_linux_socketcall_catchall);
systrace_alias_add_trans(alias, tl);
/* 106: stat [fsread] */
X(intercept_register_sccb("linux", "stat", trans_cb, NULL));
tl = intercept_register_translink("linux", "stat", 0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: systrace-error.c,v 1.3 2005/06/24 23:21:09 christos Exp $ */
/* $NetBSD: systrace-error.c,v 1.4 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: systrace-error.c,v 1.1 2002/06/04 17:20:04 provos Exp $ */
/*
@ -31,7 +31,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: systrace-error.c,v 1.3 2005/06/24 23:21:09 christos Exp $");
__RCSID("$NetBSD: systrace-error.c,v 1.4 2006/12/10 01:22:02 christos Exp $");
#include <sys/types.h>
#include <sys/wait.h>
@ -40,6 +40,7 @@ __RCSID("$NetBSD: systrace-error.c,v 1.3 2005/06/24 23:21:09 christos Exp $");
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "intercept.h"
#include "systrace.h"

View File

@ -1,4 +1,4 @@
/* $NetBSD: systrace-translate.c,v 1.18 2006/11/12 23:29:37 cbiere Exp $ */
/* $NetBSD: systrace-translate.c,v 1.19 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: systrace-translate.c,v 1.10 2002/08/01 20:50:17 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -211,15 +211,15 @@ print_sockdom(char *buf, size_t buflen, struct intercept_translate *tl)
case AF_INET6:
what = "AF_INET6";
break;
case AF_IPX:
what = "AF_IPX";
break;
case AF_ISO:
what = "AF_ISO";
break;
case AF_NS:
what = "AF_NS";
break;
case AF_IPX:
what = "AF_IPX";
break;
case AF_IMPLINK:
what = "AF_IMPLINK";
break;
@ -287,12 +287,18 @@ print_pidname(char *buf, size_t buflen, struct intercept_translate *tl)
if (pid != 0) {
icpid = intercept_getpid(pid);
strlcpy(buf, icpid->name != NULL ? icpid->name
: "<unknown>", buflen);
if (icpid->name == NULL)
intercept_freepid(pid);
} else
strlcpy(buf, icpid != NULL ? icpid->name : "<unknown>", buflen);
} else if (pid == 0) {
strlcpy(buf, "<own process group>", buflen);
} else if (pid == -1) {
strlcpy(buf, "<every process: -1>", buflen);
} else {
/* pid is negative but not -1 - trying to signal pgroup */
pid = -pid;
icpid = intercept_findpid(pid);
strlcpy(buf, "pg:", buflen);
strlcat(buf, icpid != NULL ? icpid->name : "unknown", buflen);
}
return (0);
}
@ -443,6 +449,32 @@ print_fcntlcmd(char *buf, size_t buflen, struct intercept_translate *tl)
return (0);
}
struct linux_i386_mmap_arg_struct {
unsigned long addr;
unsigned long len;
unsigned long prot;
unsigned long flags;
unsigned long fd;
unsigned long offset;
};
static int
get_linux_memprot(struct intercept_translate *trans, int fd, pid_t pid,
void *addr)
{
struct linux_i386_mmap_arg_struct arg;
size_t len = sizeof(arg);
extern struct intercept_system intercept;
if (intercept.io(fd, pid, INTERCEPT_READ, addr,
(void *)&arg, len) == -1)
return (-1);
trans->trans_addr = (void *)arg.prot;
return (0);
}
static int
print_memprot(char *buf, size_t buflen, struct intercept_translate *tl)
{
@ -625,3 +657,8 @@ struct intercept_translate ic_memprot = {
.translate = NULL,
.print = print_memprot,
};
struct intercept_translate ic_linux_memprot = {
"prot",
get_linux_memprot, print_memprot,
};

View File

@ -1,4 +1,4 @@
.\" $NetBSD: systrace.1,v 1.33 2005/09/03 11:44:45 elad Exp $
.\" $NetBSD: systrace.1,v 1.34 2006/12/10 01:22:02 christos Exp $
.\" $OpenBSD: systrace.1,v 1.27 2002/08/05 23:27:53 provos Exp $
.\"
.\" Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -40,7 +40,7 @@
.Sh SYNOPSIS
.Nm systrace
.Bk -words
.Op Fl AaCitUu
.Op Fl AaCitUuV
.Op Fl c Ar user:group
.Op Fl d Ar policydir
.Op Fl f Ar file
@ -104,12 +104,22 @@ root privilege.
.It Fl d Ar policydir
Specifies an alternative location for the user's directory from
which policies are loaded and to which changed policies are stored.
.It Fl E Ar logfile
Logs all policy violations or specifically logged system calls to
.Ar logfile .
.It Fl f Ar file
The policies specified in
.Ar file
are added to the policies that
.Nm
knows about.
The
.Dq dirname
inthe policy may contain a
.Sq \*
to match any possible pathname.
The wildcard is removed from the policy database the first time that a
filename matches.
.It Fl g Ar gui
Specifies an alternative location for the notification user interface.
.It Fl i
@ -135,6 +145,9 @@ and
.Fn access
are translated to
.Fn fsread .
.It Fl V
Prints the version number of
.Nm .
.El
.Ss POLICY
The policy is specified via the following grammar:

View File

@ -1,4 +1,4 @@
/* $NetBSD: systrace.c,v 1.33 2006/05/10 21:53:14 mrg Exp $ */
/* $NetBSD: systrace.c,v 1.34 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: systrace.c,v 1.32 2002/08/05 23:27:53 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -47,6 +47,8 @@
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <event.h>
#include <stdarg.h>
#include "intercept.h"
#include "systrace.h"
@ -55,6 +57,8 @@
#define CRADLE_SERVER "cradle_server"
#define CRADLE_UI "cradle_ui"
#define VERSION "1.6d (NetBSD)"
pid_t trpid;
int trfd;
int connected = 0; /* Connected to GUI */
@ -64,15 +68,23 @@ int allow = 0; /* Allow all and generate */
int userpolicy = 1; /* Permit user defined policies */
int noalias = 0; /* Do not do system call aliasing */
int iamroot = 0; /* Set if we are running as root */
int cradle = 0; /* Set if we are running in cradle mode */
int cradle = 0; /* Set if we are running in cradle mode */
int logtofile = 0; /* Log to file instead of syslog */
FILE *logfile; /* Default logfile to send to if enabeld */
char cwd[MAXPATHLEN]; /* Current working directory */
char home[MAXPATHLEN]; /* Home directory of user */
char username[LOGIN_NAME_MAX]; /* Username: predicate match and expansion */
const char *guipath = _PATH_XSYSTRACE; /* Path to GUI executable */
char dirpath[MAXPATHLEN];
static struct event ev_read;
static struct event ev_timeout;
static void child_handler(int);
static void log_msg(int, const char *, ...);
static void usage(void);
static void systrace_read(int, short, void *);
static void systrace_timeout(int, short, void *);
void
systrace_parameters(void)
@ -162,7 +174,7 @@ trans_cb(int fd, pid_t pid, int policynr,
const char *binname = NULL;
char output[_POSIX2_LINE_MAX];
pid_t ppid;
int dolog = 0;
int done = 0, dolog = 0;
ipid = NULL; /* XXXGCC -Wuninitialized [dreamcast] */
@ -181,48 +193,63 @@ trans_cb(int fd, pid_t pid, int policynr,
ppid = ipid->ppid;
/* Required to set up replacements */
make_output(output, sizeof(output), binname, pid, ppid, policynr,
policy->name, policy->nfilters, emulation, name, code,
tls, repl);
do {
make_output(output, sizeof(output), binname, pid, ppid,
policynr, policy->name, policy->nfilters, emulation,
name, code, tls, repl);
if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
/* Fast-path checking */
if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
goto out;
action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto done;
/* Do aliasing here */
if (!noalias)
alias = systrace_find_alias(emulation, name);
if (alias != NULL) {
int i;
/* Set up variables for further filter actions */
tls = &alitls;
emulation = alias->aemul;
name = alias->aname;
/* Create an aliased list for filter_evaluate */
TAILQ_INIT(tls);
for (i = 0; i < alias->nargs; i++) {
memcpy(&alitl[i], alias->arguments[i],
sizeof(struct intercept_translate));
TAILQ_INSERT_TAIL(tls, &alitl[i], next);
}
if ((pflq = systrace_policyflq(policy,
alias->aemul, alias->aname)) == NULL)
pflq = systrace_policyflq(policy, emulation, name);
if (pflq == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto done;
make_output(output, sizeof(output), binname, pid, ppid,
policynr, policy->name, policy->nfilters,
alias->aemul, alias->aname, code, tls, NULL);
}
/* Do aliasing here */
if (!noalias)
alias = systrace_find_alias(emulation, name);
if (alias != NULL) {
int i;
/* Set up variables for further filter actions */
tls = &alitls;
emulation = alias->aemul;
name = alias->aname;
/* Create an aliased list for filter_evaluate */
TAILQ_INIT(tls);
for (i = 0; i < alias->nargs; i++) {
memcpy(&alitl[i], alias->arguments[i],
sizeof(struct intercept_translate));
TAILQ_INSERT_TAIL(tls, &alitl[i], next);
}
if ((pflq = systrace_policyflq(policy,
alias->aemul, alias->aname)) == NULL)
errx(1, "%s:%d: no filter queue",
__func__, __LINE__);
action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto done;
make_output(output, sizeof(output), binname, pid, ppid,
policynr, policy->name, policy->nfilters,
alias->aemul, alias->aname, code, tls, NULL);
}
/*
* At this point, we have to ask the user, but we may check
* if the policy has been updated in the meanwhile.
*/
if (systrace_updatepolicy(fd, policy) == -1)
done = 1;
} while (!done);
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
@ -251,7 +278,7 @@ trans_cb(int fd, pid_t pid, int policynr,
out:
if (dolog)
syslog(LOG_WARNING, "%s user: %s, prog: %s",
log_msg(LOG_WARNING, "%s user: %s, prog: %s",
action < ICPOLICY_NEVER ? "permit" : "deny",
ipid->username, output);
@ -270,7 +297,8 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
struct filterq *pflq = NULL;
short action = ICPOLICY_PERMIT;
short future;
int len, off, dolog = 0;
int off, done = 0, dolog = 0;
size_t len;
ipid = NULL; /* XXXGCC -Wuninitialized [dreamcast] */
@ -298,18 +326,28 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
action = filter_evaluate(NULL, pflq, ipid);
do {
/* Fast-path checking */
if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
goto out;
if (ipid->uflags & SYSCALL_LOG)
dolog = 1;
if (action != ICPOLICY_ASK)
goto out;
action = filter_evaluate(NULL, pflq, ipid);
if (action != ICPOLICY_ASK)
goto haveresult;
/*
* At this point, we have to ask the user, but we may check
* if the policy has been updated in the meanwhile.
*/
if (systrace_updatepolicy(fd, policy) == -1)
done = 1;
} while (!done);
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
dolog = 1;
goto out;
goto haveresult;
}
action = filter_ask(fd, NULL, pflq, policynr, emulation, name,
@ -324,12 +362,16 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
kill(pid, SIGKILL);
return (ICPOLICY_NEVER);
}
out:
haveresult:
if (ipid->uflags & SYSCALL_LOG)
dolog = 1;
if (dolog)
syslog(LOG_WARNING, "%s user: %s, prog: %s",
action < ICPOLICY_NEVER ? "permit" : "deny",
ipid->username, output);
out:
return (action);
}
@ -414,17 +456,35 @@ child_handler(int sig)
}
while (wait4(-1, &status, WNOHANG, NULL) > 0)
;
continue;
errno = s;
}
static void
log_msg(int priority, const char *fmt, ...)
{
char buf[_POSIX2_LINE_MAX];
va_list ap;
va_start(ap, fmt);
if (logtofile) {
vsnprintf(buf, sizeof(buf), fmt, ap);
fprintf(logfile, "%s: %s\n", getprogname(), buf);
} else
vsyslog(priority, fmt, ap);
va_end(ap);
}
static void
usage(void)
{
fprintf(stderr,
"usage: systrace [-AaCitUu] [-c uid:gid] [-d policydir] [-f file]\n"
"\t [-g gui] [-p pid] command ...\n");
"Usage: %s [-AaCeitUuV] [-c user:group] [-d policydir] "
"[-E logfile]\n\t [-f file] [-g gui] [-p pid] command ...\n",
getprogname());
exit(1);
}
@ -560,6 +620,35 @@ get_uid_gid(const char *argument, uid_t *uid, gid_t *gid)
return (0);
}
static void
systrace_timeout(int fd, short what, void *arg)
{
struct timeval tv;
/* Reschedule timeout */
timerclear(&tv);
tv.tv_sec = SYSTRACE_UPDATETIME;
evtimer_add(&ev_timeout, &tv);
systrace_updatepolicies(trfd);
if (userpolicy)
systrace_dumppolicies(trfd);
}
/*
* Read from the kernel if something happened.
*/
static void
systrace_read(int fd, short what, void *arg)
{
intercept_read(fd);
if (!intercept_existpids()) {
event_del(&ev_read);
event_del(&ev_timeout);
}
}
int
main(int argc, char **argv)
{
@ -567,9 +656,9 @@ main(int argc, char **argv)
char **args;
char *filename = NULL;
char *policypath = NULL;
struct timeval tv, tv_wait;
struct timeval tv;
pid_t pidattach = 0;
int usex11 = 1, count;
int usex11 = 1;
int background;
int setcredentials = 0;
uid_t cr_uid;
@ -578,11 +667,11 @@ main(int argc, char **argv)
cr_uid = 0; /* XXX gcc */
cr_gid = 0; /* XXX gcc */
tv_wait.tv_sec = 60;
tv_wait.tv_usec = 0;
while ((c = getopt(argc, argv, "c:aAituUCd:g:f:p:")) != -1) {
while ((c = getopt(argc, argv, "Vc:aAeE:ituUCd:g:f:p:")) != -1) {
switch (c) {
case 'V':
fprintf(stderr, "%s V%s\n", argv[0], VERSION);
exit(0);
case 'c':
setcredentials = 1;
if (get_uid_gid(optarg, &cr_uid, &cr_gid) == -1)
@ -596,6 +685,16 @@ main(int argc, char **argv)
case 'd':
policypath = optarg;
break;
case 'e':
logtofile = 1;
logfile = stderr;
break;
case 'E':
logtofile = 1;
logfile = fopen(optarg, "a");
if (logfile == NULL)
err(1, "Cannot open `%s' for writing", optarg);
break;
case 'A':
if (automatic)
usage();
@ -648,6 +747,10 @@ main(int argc, char **argv)
usage();
}
/* Initialize libevent but without kqueue because of systrace fd */
setenv("EVENT_NOKQUEUE", "yes", 0);
event_init();
/* Local initalization */
systrace_initalias();
systrace_initpolicy(filename, policypath);
@ -696,6 +799,9 @@ main(int argc, char **argv)
if (signal(SIGCHLD, child_handler) == SIG_ERR)
err(1, "signal");
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
/* Start the policy gui or cradle if necessary */
if (usex11 && (!automatic && !allow)) {
if (cradle)
@ -705,34 +811,22 @@ main(int argc, char **argv)
}
/* Loop on requests */
count = 0;
while (intercept_read(trfd) != -1) {
if (!intercept_existpids())
break;
if (userpolicy) {
/* Periodically save modified policies */
if (count == 0) {
/* Set new wait time */
gettimeofday(&tv, NULL);
timeradd(&tv, &tv_wait, &tv);
} else if (count > 10) {
struct timeval now;
gettimeofday(&now, NULL);
/* Register read events */
event_set(&ev_read, trfd, EV_READ|EV_PERSIST, systrace_read, NULL);
event_add(&ev_read, NULL);
count = 0;
if (timercmp(&now, &tv, >)) {
/* Dump policy and cause new time */
systrace_dumppolicy();
continue;
}
}
count++;
}
if (userpolicy || automatic) {
evtimer_set(&ev_timeout, systrace_timeout, &ev_timeout);
timerclear(&tv);
tv.tv_sec = SYSTRACE_UPDATETIME;
evtimer_add(&ev_timeout, &tv);
}
/* Wait for events */
event_dispatch();
if (userpolicy)
systrace_dumppolicy();
systrace_dumppolicies(trfd);
close(trfd);

View File

@ -1,4 +1,4 @@
/* $NetBSD: systrace.h,v 1.21 2005/08/10 18:19:21 elad Exp $ */
/* $NetBSD: systrace.h,v 1.22 2006/12/10 01:22:02 christos Exp $ */
/* $OpenBSD: systrace.h,v 1.14 2002/08/05 23:27:53 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -99,9 +99,12 @@ struct policy {
const char *name;
char emulation[16];
struct timespec ts_last;
SPLAY_HEAD(syscalltree, policy_syscall) pflqs;
int policynr;
short kerneltable[INTERCEPT_MAXSYSCALLNR];
int flags;
struct filterq filters;
@ -132,6 +135,8 @@ TAILQ_HEAD(tmplqueue, template);
#define SYSCALL_LOG 0x04 /* Log this system call */
#define PROCESS_PROMPT 0x08 /* Prompt but nothing else */
#define SYSTRACE_UPDATETIME 30 /* update policies every 30 seconds */
void systrace_parameters(void);
int systrace_initpolicy(char *, char *);
void systrace_setupdir(char *);
@ -139,20 +144,25 @@ struct template *systrace_readtemplate(char *, struct policy *,
struct template *);
void systrace_initcb(void);
struct policy *systrace_newpolicy(const char *, const char *);
void systrace_cleanpolicy(struct policy *);
void systrace_freepolicy(struct policy *);
int systrace_newpolicynr(int, struct policy *);
int systrace_modifypolicy(int, int, const char *, short);
struct policy *systrace_findpolicy(const char *);
struct policy *systrace_findpolicy_wildcard(const char *);
struct policy *systrace_findpolnr(int);
int systrace_dumppolicy(void);
int systrace_readpolicy(char *);
int systrace_dumppolicies(int);
int systrace_updatepolicies(int);
struct policy *systrace_readpolicy(const char *);
char *systrace_getpolicyfilename(const char *);
int systrace_addpolicy(const char *);
int systrace_updatepolicy(int, struct policy *);
struct filterq *systrace_policyflq(struct policy *, const char *, const char *);
char *systrace_getpolicyname(const char *);
int systrace_error_translate(char *);
#define SYSTRACE_MAXALIAS 5
#define SYSTRACE_MAXALIAS 10
struct systrace_alias {
SPLAY_ENTRY(systrace_alias) node;
@ -235,8 +245,10 @@ extern struct intercept_translate ic_pidname;
extern struct intercept_translate ic_signame;
extern struct intercept_translate ic_fcntlcmd;
extern struct intercept_translate ic_memprot;
#ifdef notyet
extern struct intercept_translate ic_linux_memprot;
extern struct intercept_translate ic_linux_oflags;
#endif
int requestor_start(const char *, int);