summaryrefslogtreecommitdiffstats
path: root/bin/systrace/filter.c
diff options
context:
space:
mode:
authoritojun <itojun@openbsd.org>2002-10-09 03:52:10 +0000
committeritojun <itojun@openbsd.org>2002-10-09 03:52:10 +0000
commit7498c5fc93ac82bff5bc14461ed17d575129a31c (patch)
treec59c8af486f8a2270dcb095809ff40572f0b243a /bin/systrace/filter.c
parentnew message to track uid/gid changes (diff)
downloadwireguard-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.c152
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)
{