summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/systrace/filter.c152
-rw-r--r--bin/systrace/intercept.c72
-rw-r--r--bin/systrace/intercept.h13
-rw-r--r--bin/systrace/lex.l8
-rw-r--r--bin/systrace/openbsd-syscalls.c13
-rw-r--r--bin/systrace/parse.y78
-rw-r--r--bin/systrace/policy.c91
-rw-r--r--bin/systrace/systrace.c57
-rw-r--r--bin/systrace/systrace.h25
-rw-r--r--bin/systrace/util.c18
-rw-r--r--bin/systrace/util.h8
11 files changed, 364 insertions, 171 deletions
diff --git a/bin/systrace/filter.c b/bin/systrace/filter.c
index f27a5e09b87..10249d4734e 100644
--- a/bin/systrace/filter.c
+++ b/bin/systrace/filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: filter.c,v 1.18 2002/10/08 03:06:45 itojun Exp $ */
+/* $OpenBSD: filter.c,v 1.19 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -50,33 +50,38 @@ extern int allow;
extern int noalias;
extern int connected;
extern char cwd[];
+extern char home[];
+extern char username[];
static void logic_free(struct logic *);
-static int filter_match(struct intercept_tlq *, struct logic *);
+static int filter_match(struct intercept_pid *, struct intercept_tlq *,
+ struct logic *);
static void filter_review(struct filterq *);
static void filter_templates(const char *);
static int filter_template(int, struct policy *, int);
+static int filter_quickpredicate(struct filter *);
static void filter_policyrecord(struct policy *, struct filter *, const char *,
const char *, char *);
static void filter_replace(char *, size_t, char *, char *);
static int
-filter_match(struct intercept_tlq *tls, struct logic *logic)
+filter_match(struct intercept_pid *icpid, struct intercept_tlq *tls,
+ struct logic *logic)
{
struct intercept_translate *tl;
- int off = 0;
+ int off = 0, res;
switch (logic->op) {
case LOGIC_NOT:
- return (!filter_match(tls, logic->left));
+ return (!filter_match(icpid, tls, logic->left));
case LOGIC_OR:
- if (filter_match(tls, logic->left))
+ if (filter_match(icpid, tls, logic->left))
return (1);
- return (filter_match(tls, logic->right));
+ return (filter_match(icpid, tls, logic->right));
case LOGIC_AND:
- if (!filter_match(tls, logic->left))
+ if (!filter_match(icpid, tls, logic->left))
return (0);
- return (filter_match(tls, logic->right));
+ return (filter_match(icpid, tls, logic->right));
default:
break;
}
@@ -85,6 +90,9 @@ filter_match(struct intercept_tlq *tls, struct logic *logic)
if (logic->type == NULL)
goto match;
+ if (tls == NULL)
+ errx(1, "filter_match has no translators");
+
TAILQ_FOREACH(tl, tls, next) {
if (!tl->trans_valid)
return (0);
@@ -102,11 +110,47 @@ filter_match(struct intercept_tlq *tls, struct logic *logic)
return (0);
match:
- return (logic->filter_match(tl, logic));
+ /* We need to do dynamic expansion on the data */
+ if (logic->filterdata && (logic->flags & LOGIC_NEEDEXPAND)) {
+ char *old = logic->filterdata;
+ size_t oldlen = logic->filterlen;
+
+ logic->filterdata = filter_dynamicexpand(icpid, old);
+ logic->filterlen = strlen(logic->filterdata) + 1;
+
+ res = logic->filter_match(tl, logic);
+
+ logic->filterdata = old;
+ logic->filterlen = oldlen;
+ } else
+ res = logic->filter_match(tl, logic);
+
+ return (res);
+}
+
+/* Evaluate filter predicate */
+
+int
+filter_predicate(struct intercept_pid *icpid, struct predicate *pdc)
+{
+ int negative;
+ int res = 0;
+
+ if (!pdc->p_flags)
+ return (1);
+
+ negative = pdc->p_flags & PREDIC_NEGATIVE;
+ if (pdc->p_flags & PREDIC_UID)
+ res = icpid->uid == pdc->p_uid;
+ else if (pdc->p_flags & PREDIC_GID)
+ res = icpid->uid == pdc->p_uid;
+
+ return (negative ? !res : res);
}
short
-filter_evaluate(struct intercept_tlq *tls, struct filterq *fls, int *pflags)
+filter_evaluate(struct intercept_tlq *tls, struct filterq *fls,
+ struct intercept_pid *icpid)
{
struct filter *filter, *last = NULL;
short action, laction = 0;
@@ -114,7 +158,8 @@ filter_evaluate(struct intercept_tlq *tls, struct filterq *fls, int *pflags)
TAILQ_FOREACH(filter, fls, next) {
action = filter->match_action;
- if (filter_match(tls, filter->logicroot)) {
+ if (filter_predicate(icpid, &filter->match_predicate) &&
+ filter_match(icpid, tls, filter->logicroot)) {
/* Profile feedback optimization */
filter->match_count++;
if (last != NULL && last->match_action == action &&
@@ -125,7 +170,7 @@ filter_evaluate(struct intercept_tlq *tls, struct filterq *fls, int *pflags)
if (action == ICPOLICY_NEVER)
action = filter->match_error;
- *pflags = filter->match_flags;
+ icpid->uflags = filter->match_flags;
return (action);
}
@@ -348,6 +393,28 @@ filter_modifypolicy(int fd, int policynr, const char *emulation,
}
}
+/* In non-root case, evaluate predicates early */
+
+static int
+filter_quickpredicate(struct filter *filter)
+{
+ struct predicate *pdc;
+ struct intercept_pid icpid;
+
+ pdc = &filter->match_predicate;
+ if (!pdc->p_flags)
+ return (1);
+
+ intercept_setpid(&icpid);
+
+ if (!filter_predicate(&icpid, pdc))
+ return (0);
+
+ memset(pdc, 0, sizeof(filter->match_predicate));
+
+ return (1);
+}
+
int
filter_prepolicy(int fd, struct policy *policy)
{
@@ -355,6 +422,7 @@ filter_prepolicy(int fd, struct policy *policy)
struct filter *filter, *parsed;
struct filterq *fls;
short action, future;
+ extern int iamroot;
/* Commit all matching pre-filters */
for (filter = TAILQ_FIRST(&policy->prefilters);
@@ -373,9 +441,11 @@ filter_prepolicy(int fd, struct policy *policy)
__func__, __LINE__, filter->rule);
if (future == ICPOLICY_ASK) {
- fls = systrace_policyflq(policy, policy->emulation,
- filter->name);
- TAILQ_INSERT_TAIL(fls, parsed, next);
+ if (iamroot || filter_quickpredicate(parsed)) {
+ fls = systrace_policyflq(policy,
+ policy->emulation, filter->name);
+ TAILQ_INSERT_TAIL(fls, parsed, next);
+ }
} else {
filter_modifypolicy(fd, policy->policynr,
policy->emulation, filter->name, future);
@@ -395,7 +465,7 @@ filter_prepolicy(int fd, struct policy *policy)
short
filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
int policynr, const char *emulation, const char *name,
- char *output, short *pfuture, int *pflags)
+ char *output, short *pfuture, struct intercept_pid *icpid)
{
char line[2*MAXPATHLEN], *p;
struct filter *filter;
@@ -404,7 +474,7 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
int first = 1;
*pfuture = ICPOLICY_ASK;
- *pflags = 0;
+ icpid->uflags = 0;
if ((policy = systrace_findpolnr(policynr)) == NULL)
errx(1, "%s:%d: no policy %d", __func__, __LINE__, policynr);
@@ -503,7 +573,7 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
}
if (fls != NULL)
- action = filter_evaluate(tls, fls, pflags);
+ action = filter_evaluate(tls, fls, icpid);
else
action = ICPOLICY_PERMIT;
if (action == ICPOLICY_ASK) {
@@ -529,7 +599,7 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
continue;
TAILQ_INSERT_TAIL(fls, filter, next);
- action = filter_evaluate(tls, fls, pflags);
+ action = filter_evaluate(tls, fls, icpid);
if (action == ICPOLICY_ASK) {
TAILQ_REMOVE(fls, filter, next);
printf("Filter unmatched. Freeing it\n");
@@ -560,23 +630,45 @@ char *
filter_expand(char *data)
{
static char expand[2*MAXPATHLEN];
- char *what;
-
- if (data != NULL)
- strlcpy(expand, data, sizeof(expand));
- what = getenv("HOME");
- if (what != NULL)
- filter_replace(expand, sizeof(expand), "$HOME", what);
- what = getenv("USER");
- if (what != NULL)
- filter_replace(expand, sizeof(expand), "$USER", what);
+ strlcpy(expand, data, sizeof(expand));
+ filter_replace(expand, sizeof(expand), "$HOME", home);
+ filter_replace(expand, sizeof(expand), "$USER", username);
filter_replace(expand, sizeof(expand), "$CWD", cwd);
return (expand);
}
+char *
+filter_dynamicexpand(struct intercept_pid *icpid, char *data)
+{
+ static char expand[2*MAXPATHLEN];
+
+ strlcpy(expand, data, sizeof(expand));
+
+ filter_replace(expand, sizeof(expand), "$HOME", icpid->home);
+ filter_replace(expand, sizeof(expand), "$USER", icpid->username);
+ filter_replace(expand, sizeof(expand), "$CWD", icpid->cwd);
+
+ return (expand);
+}
+
+/* Checks if the string needs expansion */
+
+int
+filter_needexpand(char *data)
+{
+ if (strstr(data, "$HOME") != NULL)
+ return (1);
+ if (strstr(data, "$USER") != NULL)
+ return (1);
+ if (strstr(data, "$CWD") != NULL)
+ return (1);
+
+ return (0);
+}
+
int
filter_fnmatch(struct intercept_translate *tl, struct logic *logic)
{
diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c
index e99649d9c8f..ed5ad4882c4 100644
--- a/bin/systrace/intercept.c
+++ b/bin/systrace/intercept.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.c,v 1.31 2002/09/17 04:57:53 itojun Exp $ */
+/* $OpenBSD: intercept.c,v 1.32 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -45,6 +45,7 @@
#include <errno.h>
#include <err.h>
#include <libgen.h>
+#include <pwd.h>
#include "intercept.h"
@@ -230,6 +231,21 @@ sigusr1_handler(int signum)
/* all we need to do is pretend to handle it */
}
+void
+intercept_setpid(struct intercept_pid *icpid)
+{
+ struct passwd *pw;
+
+ icpid->uid = getuid();
+ icpid->gid = getgid();
+ if (getcwd(icpid->cwd, sizeof(icpid->cwd)) == NULL)
+ err(1, "getcwd");
+ if ((pw = getpwuid(icpid->uid)) == NULL)
+ err(1, "getpwuid");
+ strlcpy(icpid->username, pw->pw_name, sizeof(icpid->username));
+ strlcpy(icpid->home, pw->pw_dir, sizeof(icpid->home));
+}
+
pid_t
intercept_run(int bg, int fd, char *path, char *const argv[])
{
@@ -297,10 +313,8 @@ intercept_run(int bg, int fd, char *path, char *const argv[])
if ((icpid = intercept_getpid(pid)) == NULL)
err(1, "intercept_getpid");
- /* Set uid and gid information */
- icpid->uid = getuid();
- icpid->gid = getgid();
- icpid->flags |= ICFLAGS_UIDKNOWN | ICFLAGS_GIDKNOWN;
+ /* Set up user related information */
+ intercept_setpid(icpid);
/* Setup done, restore signal handling state */
if (signal(SIGUSR1, ohandler) == SIG_ERR) {
@@ -526,6 +540,7 @@ char *
intercept_filename(int fd, pid_t pid, void *addr, int userp)
{
static char cwd[2*MAXPATHLEN];
+ struct intercept_pid *icpid;
char *name;
name = intercept_get_string(fd, pid, addr);
@@ -541,6 +556,12 @@ intercept_filename(int fd, pid_t pid, void *addr, int userp)
err(1, "%s: getcwd", __func__);
}
+ /* Update cwd for process */
+ if ((icpid = intercept_getpid(pid)) == NULL)
+ err(1, "intercept_getpid");
+ if (strlcpy(icpid->cwd, cwd, sizeof(icpid->cwd)) >= sizeof(icpid->cwd))
+ errx(1, "cwd too long");
+
if (name[0] != '/') {
if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd))
goto error;
@@ -668,8 +689,6 @@ intercept_syscall(int fd, pid_t pid, u_int16_t seqnr, int policynr,
/* We need to know the result from this system call */
flags = ICFLAGS_RESULT;
- } else if (!strcmp(name, "setuid") || !strcmp(name, "setgid")) {
- flags = ICFLAGS_RESULT;
}
sc = intercept_sccb_find(emulation, name);
@@ -724,19 +743,8 @@ intercept_syscall_result(int fd, pid_t pid, u_int16_t seqnr, int policynr,
(*intercept_newimagecb)(fd, pid, policynr, emulation,
icpid->name, intercept_newimagecbarg);
- } else if (!strcmp("setuid", name)) {
- register_t reg;
-
- intercept.getarg(0, args, argsize, (void **)&reg);
- icpid->uid = reg;
- icpid->flags |= ICFLAGS_UIDKNOWN;
- } else if (!strcmp("setgid", name)) {
- register_t reg;
-
- intercept.getarg(0, args, argsize, (void **)&reg);
- icpid->gid = reg;
- icpid->flags |= ICFLAGS_GIDKNOWN;
}
+
out:
/* Resume execution of the process */
intercept.answer(fd, pid, seqnr, 0, 0, 0);
@@ -800,10 +808,34 @@ intercept_child_info(pid_t opid, pid_t npid)
inpid->ppid = opid;
/* Copy some information */
- inpid->flags = ipid->flags;
inpid->uid = ipid->uid;
inpid->gid = ipid->gid;
+ strlcpy(inpid->username, ipid->username, sizeof(inpid->username));
+ strlcpy(inpid->home, ipid->home, sizeof(inpid->home));
+ strlcpy(inpid->cwd, ipid->cwd, sizeof(inpid->cwd));
/* XXX - keeps track of emulation */
intercept.clonepid(ipid, inpid);
}
+
+void
+intercept_ugid(struct intercept_pid *icpid, uid_t uid, gid_t gid)
+{
+ /* Update current home dir */
+ if (icpid->uid != uid) {
+ struct passwd *pw;
+
+ if ((pw = getpwuid(uid)) == NULL) {
+ snprintf(icpid->username, sizeof(icpid->username),
+ "uid %d", uid);
+ strlcpy(icpid->home, "/", sizeof(icpid->home));
+ } else {
+ strlcpy(icpid->username, pw->pw_name,
+ sizeof(icpid->username));
+ strlcpy(icpid->home, pw->pw_dir, sizeof(icpid->home));
+ }
+ }
+
+ icpid->uid = uid;
+ icpid->gid = gid;
+}
diff --git a/bin/systrace/intercept.h b/bin/systrace/intercept.h
index fdc7649eac0..f5987f10d7c 100644
--- a/bin/systrace/intercept.h
+++ b/bin/systrace/intercept.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.h,v 1.11 2002/08/04 04:15:50 provos Exp $ */
+/* $OpenBSD: intercept.h,v 1.12 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -31,6 +31,7 @@
#ifndef _INTERCEPT_H_
#define _INTERCEPT_H_
+#include <sys/param.h>
#include <sys/queue.h>
struct intercept_pid;
@@ -83,13 +84,13 @@ struct intercept_pid {
char *name; /* name of current process image */
char *newname; /* image name to be committed by execve */
-#define ICFLAGS_UIDKNOWN 0x01
-#define ICFLAGS_GIDKNOWN 0x02
- int flags;
-
uid_t uid; /* current uid */
gid_t gid; /* current gid */
+ char username[MAXLOGNAME];
+ char home[MAXPATHLEN]; /* current home dir for uid */
+ char cwd[MAXPATHLEN]; /* current working directory */
+
void *data;
int uflags; /* Flags that can be used by external application */
@@ -174,5 +175,7 @@ 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 *);
#endif /* _INTERCEPT_H_ */
diff --git a/bin/systrace/lex.l b/bin/systrace/lex.l
index e09d31df598..6370fd373a0 100644
--- a/bin/systrace/lex.l
+++ b/bin/systrace/lex.l
@@ -1,4 +1,4 @@
-/* $OpenBSD: lex.l,v 1.9 2002/08/04 04:15:50 provos Exp $ */
+/* $OpenBSD: lex.l,v 1.10 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -86,6 +86,12 @@ true { return TRUE; }
"->" { return THEN; }
\( { return LBRACE; }
\) { return RBRACE; }
+if { return IF; }
+user { return USER; }
+group { return GROUP; }
+"," { return COMMA; }
+"=" { return EQUAL; }
+"!=" { return NEQUAL; }
[\$A-Za-z][\.\(\)\/A-Za-z_\-0-9]* { yylval.string = strdup(yytext); return STRING; }
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
\"[^\"]+\" { char line[1024];
diff --git a/bin/systrace/openbsd-syscalls.c b/bin/systrace/openbsd-syscalls.c
index 35984efe19d..b2eb36eae64 100644
--- a/bin/systrace/openbsd-syscalls.c
+++ b/bin/systrace/openbsd-syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: openbsd-syscalls.c,v 1.13 2002/08/28 03:54:35 itojun Exp $ */
+/* $OpenBSD: openbsd-syscalls.c,v 1.14 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -595,6 +595,17 @@ obsd_read(int fd)
err(1, "%s:%d: answer", __func__, __LINE__);
break;
+ case SYSTR_MSG_UGID: {
+ struct str_msg_ugid *msg_ugid;
+
+ msg_ugid = &msg.msg_data.msg_ugid;
+
+ intercept_ugid(icpid, msg_ugid->uid, msg_ugid->uid);
+
+ if (obsd_answer(fd, pid, seqnr, 0, 0, 0) == -1)
+ err(1, "%s:%d: answer", __func__, __LINE__);
+ break;
+ }
case SYSTR_MSG_CHILD:
intercept_child_info(msg.msg_pid,
msg.msg_data.msg_child.new_pid);
diff --git a/bin/systrace/parse.y b/bin/systrace/parse.y
index a9f35888c58..b18c3204293 100644
--- a/bin/systrace/parse.y
+++ b/bin/systrace/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.9 2002/08/04 04:15:50 provos Exp $ */
+/* $OpenBSD: parse.y,v 1.10 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -40,6 +40,9 @@
#include <err.h>
#include <stdarg.h>
#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
#include "intercept.h"
#include "systrace.h"
@@ -62,7 +65,7 @@ extern int myoff;
%}
%token AND OR NOT LBRACE RBRACE LSQBRACE RSQBRACE THEN MATCH PERMIT DENY
-%token EQ NEQ TRUE SUB NSUB INPATH LOG
+%token EQ NEQ TRUE SUB NSUB INPATH LOG COMMA IF USER GROUP EQUAL NEQUAL
%token <string> STRING
%token <string> CMDSTRING
%token <number> NUMBER
@@ -72,15 +75,17 @@ extern int myoff;
%type <number> typeoff
%type <number> logcode
%type <string> errorcode
+%type <predicate> predicate
%union {
int number;
char *string;
short action;
struct logic *logic;
+ struct predicate predicate;
}
%%
-fullexpression : expression THEN action errorcode logcode
+fullexpression : expression THEN action errorcode logcode predicate
{
int flags = 0, errorcode = SYSTRACE_EPERM;
@@ -119,6 +124,7 @@ fullexpression : expression THEN action errorcode logcode
myfilter->match_action = $3;
myfilter->match_error = errorcode;
myfilter->match_flags = flags;
+ myfilter->match_predicate = $6;
}
;
@@ -142,6 +148,59 @@ logcode : /* Empty */
}
;
+predicate : /* Empty */
+{
+ memset(&$$, 0, sizeof($$));
+}
+ | COMMA IF USER EQUAL STRING
+{
+ struct passwd *pw;
+
+ memset(&$$, 0, sizeof($$));
+ if ((pw = getpwnam($5)) == NULL) {
+ yyerror("Unknown user %s", $5);
+ break;
+ }
+ $$.p_uid = pw->pw_uid;
+ $$.p_flags = PREDIC_UID;
+}
+ | COMMA IF USER NEQUAL STRING
+{
+ struct passwd *pw;
+
+ memset(&$$, 0, sizeof($$));
+ if ((pw = getpwnam($5)) == NULL) {
+ yyerror("Unknown user %s", $5);
+ break;
+ }
+ $$.p_uid = pw->pw_uid;
+ $$.p_flags = PREDIC_UID | PREDIC_NEGATIVE;
+}
+ | COMMA IF GROUP EQUAL STRING
+{
+ struct group *gr;
+
+ memset(&$$, 0, sizeof($$));
+ if ((gr = getgrnam($5)) == NULL) {
+ yyerror("Unknown group %s", $5);
+ break;
+ }
+ $$.p_gid = gr->gr_gid;
+ $$.p_flags = PREDIC_GID;
+}
+ | COMMA IF GROUP NEQUAL STRING
+{
+ struct group *gr;
+
+ memset(&$$, 0, sizeof($$));
+ if ((gr = getgrnam($5)) == NULL) {
+ yyerror("Unknown group %s", $5);
+ break;
+ }
+ $$.p_gid = gr->gr_gid;
+ $$.p_flags = PREDIC_GID | PREDIC_NEGATIVE;
+}
+
expression : symbol
{
$$ = $1;
@@ -302,6 +361,8 @@ struct logic *
parse_newsymbol(char *type, int typeoff, char *data)
{
struct logic *node;
+ int iamroot = getuid() == 0;
+
node = calloc(1, sizeof(struct logic));
if (node == NULL) {
@@ -312,8 +373,15 @@ parse_newsymbol(char *type, int typeoff, char *data)
node->type = type;
node->typeoff = typeoff;
if (data) {
- node->filterdata = strdup(filter_expand(data));
- free(data);
+ /* For the root user, variable expansion may change */
+ if (iamroot) {
+ node->filterdata = data;
+ if (filter_needexpand(data))
+ node->flags |= LOGIC_NEEDEXPAND;
+ } else {
+ node->filterdata = strdup(filter_expand(data));
+ free(data);
+ }
if (node->filterdata == NULL) {
yyerror("strdup");
return (NULL);
diff --git a/bin/systrace/policy.c b/bin/systrace/policy.c
index e799d785b52..2488d3c7b82 100644
--- a/bin/systrace/policy.c
+++ b/bin/systrace/policy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: policy.c,v 1.20 2002/09/23 04:41:02 itojun Exp $ */
+/* $OpenBSD: policy.c,v 1.21 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -52,8 +52,8 @@ static int policycompare(struct policy *, struct policy *);
static int polnrcompare(struct policy *, struct policy *);
static char *systrace_policyfilename(char *, const char *);
static char *systrace_policyline(char *line);
-static int systrace_policyprocess(struct policy *, char *);
-static int systrace_predicatematch(char *);
+static int systrace_policyprocess(struct policy *,
+ char *);
static int systrace_writepolicy(struct policy *);
int systrace_templatedir(void);
@@ -408,6 +408,7 @@ systrace_readtemplate(char *filename, struct policy *policy,
if ((fp = fopen(filename, "r")) == NULL)
return (NULL);
+ /* Set up pid with current information */
while (fgets(line, sizeof(line), fp)) {
linenumber++;
@@ -474,59 +475,6 @@ systrace_readtemplate(char *filename, struct policy *policy,
goto out;
}
-int
-systrace_predicatematch(char *p)
-{
- extern char *username;
- int i, res, neg;
-
- res = 0;
- neg = 0;
-
- if (!strncasecmp(p, "user", 4)) {
- /* Match against user name */
- p += 4;
- p += strspn(p, " \t");
- if (!strncmp(p, "=", 1)) {
- p += 1;
- neg = 0;
- } else if (!strncmp(p, "!=", 2)) {
- p += 2;
- neg = 1;
- } else
- return (-1);
- p += strspn(p, " \t");
-
- res = (!strcmp(p, username));
- } else if (!strncasecmp(p, "group", 5)) {
- /* Match against group list */
- p += 5;
- p += strspn(p, " \t");
- if (!strncmp(p, "=", 1)) {
- p += 1;
- neg = 0;
- } else if (!strncmp(p, "!=", 2)) {
- p += 2;
- neg = 1;
- } else
- return (-1);
- p += strspn(p, " \t");
-
- for (i = 0; i < ngroups; i++) {
- if (!strcmp(p, groupnames[i])) {
- res = 1;
- break;
- }
- }
- } else
- return (-1);
-
- if (neg)
- res = !res;
-
- return (res);
-}
-
/* Removes trailing whitespace and comments from the input line */
static char *
@@ -570,9 +518,13 @@ systrace_policyline(char *line)
static int
systrace_policyprocess(struct policy *policy, char *p)
{
+ char line[_POSIX2_LINE_MAX];
char *name, *emulation, *rule;
struct filter *filter, *parsed;
short action, future;
+ int resolved = 0, res;
+
+ /* Delay predicate evaluation if we are root */
emulation = strsep(&p, "-");
if (p == NULL || *p == '\0')
@@ -588,25 +540,22 @@ systrace_policyprocess(struct policy *policy, char *p)
rule = p;
if ((p = strrchr(p, ',')) != NULL && !strncasecmp(p, ", if", 4)) {
- int match;
-
*p = '\0';
+ res = filter_parse_simple(rule, &action, &future);
+ *p = ',';
+ if (res == 0) {
+ /* Need to make a real policy out of it */
+ snprintf(line, sizeof(line), "true then %s", rule);
+ rule = line;
+ }
+ } else if (filter_parse_simple(rule, &action, &future) == 0)
+ resolved = 1;
- /* Process predicates */
- p += 4;
- p += strspn(p, " \t");
-
- match = systrace_predicatematch(p);
- if (match == -1)
- return (-1);
- /* If the predicate does not match skip rule */
- if (!match)
- return (0);
- }
-
- if (filter_parse_simple(rule, &action, &future) == -1) {
+ /* If the simple parser did not match, try real parser */
+ if (!resolved) {
if (parse_filter(rule, &parsed) == -1)
return (-1);
+
filter_free(parsed);
}
diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c
index 7f8002abcca..8913ce7fe79 100644
--- a/bin/systrace/systrace.c
+++ b/bin/systrace/systrace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace.c,v 1.36 2002/10/08 03:13:23 itojun Exp $ */
+/* $OpenBSD: systrace.c,v 1.37 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -44,6 +44,7 @@
#include <string.h>
#include <err.h>
#include <errno.h>
+#include <pwd.h>
#include "intercept.h"
#include "systrace.h"
@@ -57,13 +58,36 @@ int automatic = 0; /* Do not run interactively */
int allow = 0; /* Allow all and generate */
int userpolicy = 1; /* Permit user defined policies */
int noalias = 0; /* Do not do system call aliasing */
-char *username = NULL; /* Username in automatic mode */
-char cwd[MAXPATHLEN]; /* Current working directory of process */
+int iamroot = 0; /* Set if we are running as root */
+char cwd[MAXPATHLEN]; /* Current working directory */
+char home[MAXPATHLEN]; /* Home directory of user */
+char username[MAXLOGNAME]; /* Username: predicate match and expansion */
static void child_handler(int);
static void usage(void);
static int requestor_start(char *);
+void
+systrace_parameters(void)
+{
+ struct passwd *pw;
+ uid_t uid = getuid();
+
+ iamroot = getuid() == 0;
+
+ /* Find out current username. */
+ if ((pw = getpwuid(uid)) == NULL)
+ snprintf(username, sizeof(username), "uid %u", uid);
+ else
+ snprintf(username, sizeof(username), "%s", pw->pw_name);
+
+ strlcpy(home, pw->pw_dir, sizeof(home));
+
+ /* Determine current working directory for filtering */
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ err(1, "getcwd");
+}
+
/*
* Generate human readable output and setup replacements if available.
*/
@@ -150,7 +174,7 @@ trans_cb(int fd, pid_t pid, int policynr,
if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
- action = filter_evaluate(tls, pflq, &ipid->uflags);
+ action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto replace;
@@ -177,7 +201,7 @@ trans_cb(int fd, pid_t pid, int policynr,
alias->aemul, alias->aname)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
- action = filter_evaluate(tls, pflq, &ipid->uflags);
+ action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto replace;
@@ -193,7 +217,7 @@ trans_cb(int fd, pid_t pid, int policynr,
}
action = filter_ask(fd, tls, pflq, policynr, emulation, name,
- output, &future, &ipid->uflags);
+ output, &future, ipid);
if (future != ICPOLICY_ASK)
filter_modifypolicy(fd, policynr, emulation, name, future);
@@ -218,7 +242,7 @@ trans_cb(int fd, pid_t pid, int policynr,
if (log)
syslog(LOG_WARNING, "%s user: %s, prog: %s",
action < ICPOLICY_NEVER ? "permit" : "deny",
- username, output);
+ ipid->username, output);
return (action);
}
@@ -230,6 +254,7 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
char output[_POSIX2_LINE_MAX];
struct policy *policy;
struct intercept_pid *ipid;
+ struct filterq *pflq = NULL;
short action = ICPOLICY_PERMIT;
short future;
int len, off, log = 0;
@@ -255,6 +280,13 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
if (len > 0)
snprintf(output + off, len, ", args: %d", argsize);
+ if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
+ errx(1, "%s:%d: no filter queue", __func__, __LINE__);
+
+ action = filter_evaluate(NULL, pflq, ipid);
+ if (action != ICPOLICY_ASK)
+ goto out;
+
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
log = 1;
@@ -262,7 +294,7 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
}
action = filter_ask(fd, NULL, NULL, policynr, emulation, name,
- output, &future, &ipid->uflags);
+ output, &future, ipid);
if (future != ICPOLICY_ASK)
systrace_modifypolicy(fd, policynr, name, future);
@@ -277,7 +309,7 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
if (log)
syslog(LOG_WARNING, "%s user: %s, prog: %s",
action < ICPOLICY_NEVER ? "permit" : "deny",
- username, output);
+ ipid->username, output);
return (action);
}
@@ -470,12 +502,7 @@ main(int argc, char **argv)
if (argc == 0 || (pidattach && *argv[0] != '/'))
usage();
- /* Username for automatic mode, and policy predicates */
- username = uid_to_name(getuid());
-
- /* Determine current working directory for filtering */
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- err(1, "getcwd");
+ systrace_parameters();
/* Local initalization */
systrace_initalias();
diff --git a/bin/systrace/systrace.h b/bin/systrace/systrace.h
index 556797da4a8..bb18ff51f0d 100644
--- a/bin/systrace/systrace.h
+++ b/bin/systrace/systrace.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace.h,v 1.15 2002/09/23 04:41:02 itojun Exp $ */
+/* $OpenBSD: systrace.h,v 1.16 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -43,11 +43,14 @@ struct logic {
struct logic *right;
char *type;
int typeoff;
+ int flags;
void *filterdata;
size_t filterlen;
int (*filter_match)(struct intercept_translate *, struct logic *);
};
+#define LOGIC_NEEDEXPAND 0x01
+
struct filter {
TAILQ_ENTRY(filter) next;
TAILQ_ENTRY(filter) policy_next;
@@ -60,6 +63,15 @@ struct filter {
int match_error;
int match_flags;
int match_count; /* Number of times this filter matched */
+
+ struct predicate {
+#define PREDIC_UID 0x01
+#define PREDIC_GID 0x02
+#define PREDIC_NEGATIVE 0x10
+ int p_flags;
+ uid_t p_uid;
+ gid_t p_gid;
+ } match_predicate;
};
TAILQ_HEAD(filterq, filter);
@@ -112,6 +124,7 @@ TAILQ_HEAD(tmplqueue, template);
#define PROCESS_DETACH 0x02 /* Process gets detached */
#define SYSCALL_LOG 0x04 /* Log this system call */
+void systrace_parameters(void);
int systrace_initpolicy(char *, char *);
void systrace_setupdir(char *);
struct template *systrace_readtemplate(char *, struct policy *,
@@ -166,16 +179,20 @@ struct systrace_revalias {
struct systrace_revalias *systrace_reverse(const char *, const char *);
struct systrace_revalias *systrace_find_reverse(const char *, const char *);
-short filter_evaluate(struct intercept_tlq *, struct filterq *, int *);
+short filter_evaluate(struct intercept_tlq *, struct filterq *,
+ struct intercept_pid *);
short filter_ask(int, struct intercept_tlq *, struct filterq *, int,
- const char *, const char *, char *, short *, int *);
+ const char *, const char *, char *, short *, struct intercept_pid *);
void filter_free(struct filter *);
void filter_modifypolicy(int, int, const char *, const char *, short);
+int filter_predicate(struct intercept_pid *, struct predicate *);
int filter_parse_simple(char *, short *, short *);
int filter_parse(char *, struct filter **);
int filter_prepolicy(int, struct policy *);
-char *filter_expand(char *data);
+char *filter_expand(char *);
+char *filter_dynamicexpand(struct intercept_pid *, char *);
+int filter_needexpand(char *);
int parse_filter(char *, struct filter **);
diff --git a/bin/systrace/util.c b/bin/systrace/util.c
index ad1d4230f2b..b6bd8b17cd2 100644
--- a/bin/systrace/util.c
+++ b/bin/systrace/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.8 2002/07/19 14:38:58 itojun Exp $ */
+/* $OpenBSD: util.c,v 1.9 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -33,7 +33,6 @@
#include <string.h>
#include <ctype.h>
#include <stdio.h>
-#include <pwd.h>
#include "util.h"
@@ -71,21 +70,6 @@ strrpl(char *str, size_t size, char *match, char *value)
return (p);
}
-char *
-uid_to_name(uid_t uid)
-{
- static char buf[128];
- struct passwd *pw;
-
- if ((pw = getpwuid(uid)) == NULL)
- snprintf(buf, sizeof(buf), "uid %u", uid);
- else
- snprintf(buf, sizeof(buf), "%s", pw->pw_name);
-
- return (buf);
-}
-
-
/* simplify_path is from pdksh and apparently in the public domain */
/* ISABSPATH() means path is fully and completely specified,
diff --git a/bin/systrace/util.h b/bin/systrace/util.h
index a7ce10a6bfe..8e4fdb22d2a 100644
--- a/bin/systrace/util.h
+++ b/bin/systrace/util.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.h,v 1.1 2002/07/19 14:38:58 itojun Exp $ */
+/* $OpenBSD: util.h,v 1.2 2002/10/09 03:52:10 itojun Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -30,6 +30,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
void simplify_path(char *);
-char *uid_to_name(uid_t);
char *strrpl(char *, size_t, char *, char *);
+
+#endif /* !_UTIL_H_ */