diff options
author | 2002-10-09 03:52:10 +0000 | |
---|---|---|
committer | 2002-10-09 03:52:10 +0000 | |
commit | 7498c5fc93ac82bff5bc14461ed17d575129a31c (patch) | |
tree | c59c8af486f8a2270dcb095809ff40572f0b243a /bin/systrace/filter.c | |
parent | new message to track uid/gid changes (diff) | |
download | wireguard-openbsd-7498c5fc93ac82bff5bc14461ed17d575129a31c.tar.xz wireguard-openbsd-7498c5fc93ac82bff5bc14461ed17d575129a31c.zip |
predicates are part of the grammar now; in non-root case, predicates are
evaluated only once; in root case, predicates and variable expansion are
dynamic.
from provos
Diffstat (limited to 'bin/systrace/filter.c')
-rw-r--r-- | bin/systrace/filter.c | 152 |
1 files changed, 122 insertions, 30 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) { |