diff options
-rw-r--r-- | bin/systrace/filter.c | 152 | ||||
-rw-r--r-- | bin/systrace/intercept.c | 72 | ||||
-rw-r--r-- | bin/systrace/intercept.h | 13 | ||||
-rw-r--r-- | bin/systrace/lex.l | 8 | ||||
-rw-r--r-- | bin/systrace/openbsd-syscalls.c | 13 | ||||
-rw-r--r-- | bin/systrace/parse.y | 78 | ||||
-rw-r--r-- | bin/systrace/policy.c | 91 | ||||
-rw-r--r-- | bin/systrace/systrace.c | 57 | ||||
-rw-r--r-- | bin/systrace/systrace.h | 25 | ||||
-rw-r--r-- | bin/systrace/util.c | 18 | ||||
-rw-r--r-- | bin/systrace/util.h | 8 |
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 **)®); - icpid->uid = reg; - icpid->flags |= ICFLAGS_UIDKNOWN; - } else if (!strcmp("setgid", name)) { - register_t reg; - - intercept.getarg(0, args, argsize, (void **)®); - 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_ */ |