summaryrefslogtreecommitdiff
path: root/bin/systrace/policy.c
diff options
context:
space:
mode:
authorNikolay Sturm <sturm@cvs.openbsd.org>2006-07-02 12:34:16 +0000
committerNikolay Sturm <sturm@cvs.openbsd.org>2006-07-02 12:34:16 +0000
commit36207a330ccf1cae7cf91b22b4e4b123030ab8be (patch)
tree89d6f8534a819d485ce5c89a5adbe563f11df94a /bin/systrace/policy.c
parent7b13dfe1cf22c6103eb7dc6d10eef85c9ddcf53f (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.c205
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;