diff options
author | Nikolay Sturm <sturm@cvs.openbsd.org> | 2006-07-02 12:34:16 +0000 |
---|---|---|
committer | Nikolay Sturm <sturm@cvs.openbsd.org> | 2006-07-02 12:34:16 +0000 |
commit | 36207a330ccf1cae7cf91b22b4e4b123030ab8be (patch) | |
tree | 89d6f8534a819d485ce5c89a5adbe563f11df94a /bin/systrace/policy.c | |
parent | 7b13dfe1cf22c6103eb7dc6d10eef85c9ddcf53f (diff) |
sync with systrace 1.6d, keeping local changes
tests and feedback by a few
Diffstat (limited to 'bin/systrace/policy.c')
-rw-r--r-- | bin/systrace/policy.c | 205 |
1 files changed, 182 insertions, 23 deletions
diff --git a/bin/systrace/policy.c b/bin/systrace/policy.c index eb8339f0ac4..d00da3550aa 100644 --- a/bin/systrace/policy.c +++ b/bin/systrace/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.30 2006/03/18 19:03:23 robert Exp $ */ +/* $OpenBSD: policy.c,v 1.31 2006/07/02 12:34:15 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -43,6 +43,7 @@ #include <fcntl.h> #include <ctype.h> #include <err.h> +#include <libgen.h> #include "intercept.h" #include "systrace.h" @@ -144,7 +145,7 @@ systrace_initpolicy(char *file, char *path) } if (file != NULL) - return (systrace_readpolicy(file)); + return (systrace_readpolicy(file) != NULL ? 0 : -1); return (0); } @@ -160,6 +161,34 @@ systrace_findpolicy(const char *name) } 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((char *)res->name); + if ((res->name = strdup(name)) == NULL) + err(1, "%s: strdup", __func__); + + SPLAY_INSERT(policytree, &policyroot, res); + return (res); +} + +struct policy * systrace_findpolnr(int nr) { struct policy tmp; @@ -188,11 +217,15 @@ systrace_newpolicynr(int fd, struct policy *tmp) struct policy * systrace_newpolicy(const char *emulation, const char *name) { + int i; struct policy *tmp; 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); @@ -209,20 +242,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); @@ -244,6 +280,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) @@ -282,7 +330,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); @@ -290,6 +338,11 @@ 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); } @@ -323,8 +376,13 @@ systrace_policyfilename(char *dirname, const char *name) return (file); } -int -systrace_addpolicy(const char *name) +/* + * Converts a executeable name into the corresponding filename + * that contains the security policy. + */ + +char * +systrace_getpolicyname(const char *name) { char *file = NULL; @@ -336,13 +394,21 @@ systrace_addpolicy(const char *name) } /* Read global policy */ - if (file == NULL) { + if (file == NULL) file = systrace_policyfilename(POLICY_PATH, name); - if (file == NULL) - return (-1); - } - return (systrace_readpolicy(file)); + return (file); +} + +int +systrace_addpolicy(const char *name) +{ + char *file; + + if ((file = systrace_getpolicyname(name)) == NULL) + return (-1); + + return (systrace_readpolicy(file) != NULL ? 0 : -1); } /* @@ -411,6 +477,8 @@ systrace_templatedir(void) error: errx(1, "%s: template name too long", __func__); + + /* NOTREACHED */ } struct template * @@ -492,7 +560,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) @@ -579,7 +649,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. */ @@ -613,8 +684,14 @@ systrace_policyprocess(struct policy *policy, char *p) return (0); } -int -systrace_readpolicy(char *filename) +/* + * Reads security 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; @@ -624,7 +701,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)) { @@ -640,6 +717,8 @@ systrace_readpolicy(char *filename) continue; if (!strncasecmp(p, "Policy: ", 8)) { + struct timeval now; + p += 8; name = strsep(&p, ","); if (p == NULL) @@ -652,6 +731,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; } @@ -671,13 +754,65 @@ 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) { @@ -687,6 +822,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); @@ -726,11 +862,34 @@ 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; |