summaryrefslogtreecommitdiff
path: root/bin/systrace/systrace.c
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2002-06-04 17:20:05 +0000
committerNiels Provos <provos@cvs.openbsd.org>2002-06-04 17:20:05 +0000
commit46a8c64495ad8a9d221a6c0fa12e7d77b6e2420b (patch)
tree9c7200a8a35c2bee11d017386d12aab0d8bca720 /bin/systrace/systrace.c
parent72975dabb915c98862a98d34d585bdc781702b4d (diff)
initial import of systrace. don't touch this, more stuff coming in a while
Diffstat (limited to 'bin/systrace/systrace.c')
-rw-r--r--bin/systrace/systrace.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c
new file mode 100644
index 00000000000..e6f929440e6
--- /dev/null
+++ b/bin/systrace/systrace.c
@@ -0,0 +1,450 @@
+/* $OpenBSD: systrace.c,v 1.1 2002/06/04 17:20:04 provos Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+
+#include "intercept.h"
+#include "systrace.h"
+
+pid_t pid;
+int fd;
+int connected = 0; /* Connected to GUI */
+int inherit = 0; /* Inherit policy to childs */
+int automatic = 0; /* Do not run interactively */
+
+short
+trans_cb(int fd, pid_t pid, int policynr,
+ char *name, int code, char *emulation,
+ void *args, int argsize, struct intercept_tlq *tls, void *cbarg)
+{
+ short action, future;
+ struct policy *policy;
+ struct intercept_translate *tl;
+ struct intercept_pid *ipid;
+ struct filterq *pflq = NULL;
+ char output[1024], *p, *line;
+ int size;
+
+ action = ICPOLICY_PERMIT;
+
+ if (policynr == -1)
+ goto out;
+
+ if ((policy = systrace_findpolnr(policynr)) == NULL)
+ errx(1, "%s:%d: find %d\n", __FUNCTION__, __LINE__,
+ policynr);
+
+ if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
+ errx(1, "%s:%d: no filter queue\n", __FUNCTION__, __LINE__);
+
+ ipid = intercept_getpid(pid);
+ ipid->uflags = 0;
+ snprintf(output, sizeof(output),
+ "%s, pid: %d(%d), policy: %s, filters: %d, syscall: %s-%s(%d)",
+ ipid->name != NULL ? ipid->name : policy->name, pid, policynr,
+ policy->name, policy->nfilters, emulation, name, code);
+ p = output + strlen(output);
+ size = sizeof(output) - strlen(output);
+
+ TAILQ_FOREACH(tl, tls, next) {
+ if (!tl->trans_valid)
+ break;
+ line = intercept_translate_print(tl);
+ if (line != NULL) {
+ snprintf(p, size, ", %s: %s", tl->name, line);
+ p = output + strlen(output);
+ size = sizeof(output) - strlen(output);
+ }
+ }
+
+ action = filter_evaluate(tls, pflq, &ipid->uflags);
+ if (action != ICPOLICY_ASK)
+ goto out;
+ if (policy->flags & POLICY_UNSUPERVISED) {
+ action = ICPOLICY_NEVER;
+ goto out;
+ }
+
+ action = filter_ask(tls, pflq, policynr, emulation, name,
+ output, &future, &ipid->uflags);
+ if (future != ICPOLICY_ASK)
+ systrace_modifypolicy(fd, policynr, name, future);
+
+ if (policy->flags & POLICY_DETACHED) {
+ if (intercept_detach(fd, pid) == -1)
+ err(1, "intercept_detach");
+ } else if (action == ICPOLICY_KILL) {
+ kill(pid, SIGKILL);
+ action = ICPOLICY_NEVER;
+ }
+ out:
+ return (action);
+}
+
+short
+gen_cb(int fd, pid_t pid, int policynr, char *name, int code,
+ char *emulation, void *args, int argsize, void *cbarg)
+{
+ char output[1024];
+ struct policy *policy;
+ struct intercept_pid *ipid;
+ short action = ICPOLICY_PERMIT;
+ short future;
+
+ if (policynr == -1)
+ goto out;
+
+ if ((policy = systrace_findpolnr(policynr)) == NULL)
+ errx(1, "%s:%d: find %d\n", __FUNCTION__, __LINE__,
+ policynr);
+
+ if (policy->flags & POLICY_UNSUPERVISED) {
+ action = ICPOLICY_NEVER;
+ goto out;
+ }
+
+ ipid = intercept_getpid(pid);
+ ipid->uflags = 0;
+ snprintf(output, sizeof(output),
+ "%s, pid: %d(%d), policy: %s, filters: %d, syscall: %s-%s(%d), args: %d",
+ ipid->name != NULL ? ipid->name : policy->name, pid, policynr,
+ policy->name, policy->nfilters, emulation, name, code, argsize);
+
+ action = filter_ask(NULL, NULL, policynr, emulation, name,
+ output, &future, &ipid->uflags);
+ if (future != ICPOLICY_ASK)
+ systrace_modifypolicy(fd, policynr, name, future);
+
+ if (policy->flags & POLICY_DETACHED) {
+ if (intercept_detach(fd, pid) == -1)
+ err(1, "intercept_detach");
+ } else if (action == ICPOLICY_KILL) {
+ kill(pid, SIGKILL);
+ action = ICPOLICY_NEVER;
+ }
+ out:
+ return (action);
+}
+
+void
+execres_cb(int fd, pid_t pid, int policynr, char *emulation, char *name, void *arg)
+{
+ struct policy *policy;
+
+ if (policynr != -1) {
+ struct intercept_pid *ipid;
+
+ if (inherit)
+ return;
+
+ ipid = intercept_getpid(pid);
+ if (ipid->uflags & PROCESS_INHERIT_POLICY)
+ return;
+ }
+ if ((policy = systrace_newpolicy(emulation, name)) == NULL)
+ goto error;
+
+ /* See if this policies runs without interactive feedback */
+ if (automatic)
+ policy->flags |= POLICY_UNSUPERVISED;
+
+ policynr = policy->policynr;
+
+ /* Try to find existing policy in file system */
+ if (policynr == -1 && TAILQ_FIRST(&policy->prefilters) == NULL)
+ systrace_addpolicy(name);
+
+ if (policy->flags & POLICY_DETACHED) {
+ if (intercept_detach(fd, pid) == -1)
+ err(1, "intercept_detach");
+ return;
+ }
+
+ if (policynr == -1) {
+ policynr = systrace_newpolicynr(fd, policy);
+ if (policynr == -1)
+ goto error;
+ }
+
+ if (intercept_assignpolicy(fd, pid, policynr) == -1)
+ goto error;
+
+ if (TAILQ_FIRST(&policy->prefilters) != NULL)
+ filter_prepolicy(fd, policy);
+
+ return;
+
+ error:
+ kill(pid, SIGKILL);
+ fprintf(stderr, "Terminating %d: %s\n", pid, name);
+}
+
+void
+child_handler(int sig)
+{
+ int s = errno, status;
+
+ if (signal(SIGCHLD, child_handler) == SIG_ERR) {
+ close(fd);
+ }
+
+ while (wait4(-1, &status, WNOHANG, NULL) > 0)
+ ;
+
+ errno = s;
+}
+
+#define X(x) if ((x) == -1) \
+ err(1, "%s:%d: intercept failed", __FUNCTION__, __LINE__)
+
+void
+systrace_initcb(void)
+{
+ X(intercept_init());
+
+ X(intercept_register_gencb(gen_cb, NULL));
+ X(intercept_register_sccb("native", "open", trans_cb, NULL));
+ X(intercept_register_transfn("native", "open", 0));
+ X(intercept_register_translation("native", "open", 1, &oflags));
+
+ X(intercept_register_sccb("native", "connect", trans_cb, NULL));
+ X(intercept_register_translation("native", "connect", 1,
+ &ic_translate_connect));
+ X(intercept_register_sccb("native", "sendto", trans_cb, NULL));
+ X(intercept_register_translation("native", "sendto", 4,
+ &ic_translate_connect));
+ X(intercept_register_sccb("native", "bind", trans_cb, NULL));
+ X(intercept_register_translation("native", "bind", 1,
+ &ic_translate_connect));
+ X(intercept_register_sccb("native", "execve", trans_cb, NULL));
+ X(intercept_register_transfn("native", "execve", 0));
+ X(intercept_register_sccb("native", "stat", trans_cb, NULL));
+ X(intercept_register_transfn("native", "stat", 0));
+ X(intercept_register_sccb("native", "lstat", trans_cb, NULL));
+ X(intercept_register_translink("native", "lstat", 0));
+ X(intercept_register_sccb("native", "unlink", trans_cb, NULL));
+ X(intercept_register_transfn("native", "unlink", 0));
+ X(intercept_register_sccb("native", "chown", trans_cb, NULL));
+ X(intercept_register_transfn("native", "chown", 0));
+ X(intercept_register_translation("native", "chown", 1, &uidt));
+ X(intercept_register_translation("native", "chown", 2, &gidt));
+ X(intercept_register_sccb("native", "fchown", trans_cb, NULL));
+ X(intercept_register_translation("native", "fchown", 0, &fdt));
+ X(intercept_register_translation("native", "fchown", 1, &uidt));
+ X(intercept_register_translation("native", "fchown", 2, &gidt));
+ X(intercept_register_sccb("native", "chmod", trans_cb, NULL));
+ X(intercept_register_transfn("native", "chmod", 0));
+ X(intercept_register_translation("native", "chmod", 1, &modeflags));
+ X(intercept_register_sccb("native", "readlink", trans_cb, NULL));
+ X(intercept_register_translink("native", "readlink", 0));
+ X(intercept_register_sccb("native", "chdir", trans_cb, NULL));
+ X(intercept_register_transfn("native", "chdir", 0));
+ X(intercept_register_sccb("native", "access", trans_cb, NULL));
+ X(intercept_register_transfn("native", "access", 0));
+ X(intercept_register_sccb("native", "mkdir", trans_cb, NULL));
+ X(intercept_register_transfn("native", "mkdir", 0));
+ X(intercept_register_sccb("native", "rmdir", trans_cb, NULL));
+ X(intercept_register_transfn("native", "rmdir", 0));
+ X(intercept_register_sccb("native", "rename", trans_cb, NULL));
+ X(intercept_register_transfn("native", "rename", 0));
+ X(intercept_register_transfn("native", "rename", 1));
+ X(intercept_register_sccb("native", "symlink", trans_cb, NULL));
+ X(intercept_register_transstring("native", "symlink", 0));
+ X(intercept_register_translink("native", "symlink", 1));
+
+ X(intercept_register_sccb("linux", "open", trans_cb, NULL));
+ X(intercept_register_translink("linux", "open", 0));
+ X(intercept_register_translation("linux", "open", 1, &linux_oflags));
+ X(intercept_register_sccb("linux", "stat", trans_cb, NULL));
+ X(intercept_register_translink("linux", "stat", 0));
+ X(intercept_register_sccb("linux", "lstat", trans_cb, NULL));
+ X(intercept_register_translink("linux", "lstat", 0));
+ X(intercept_register_sccb("linux", "execve", trans_cb, NULL));
+ X(intercept_register_translink("linux", "execve", 0));
+ X(intercept_register_sccb("linux", "access", trans_cb, NULL));
+ X(intercept_register_translink("linux", "access", 0));
+ X(intercept_register_sccb("linux", "symlink", trans_cb, NULL));
+ X(intercept_register_transstring("linux", "symlink", 0));
+ X(intercept_register_translink("linux", "symlink", 1));
+ X(intercept_register_sccb("linux", "readlink", trans_cb, NULL));
+ X(intercept_register_translink("linux", "readlink", 0));
+ X(intercept_register_sccb("linux", "rename", trans_cb, NULL));
+ X(intercept_register_translink("linux", "rename", 0));
+ X(intercept_register_translink("linux", "rename", 1));
+ X(intercept_register_sccb("linux", "mkdir", trans_cb, NULL));
+ X(intercept_register_translink("linux", "mkdir", 0));
+ X(intercept_register_sccb("linux", "rmdir", trans_cb, NULL));
+ X(intercept_register_translink("linux", "rmdir", 0));
+ X(intercept_register_sccb("linux", "unlink", trans_cb, NULL));
+ X(intercept_register_translink("linux", "unlink", 0));
+ X(intercept_register_sccb("linux", "chmod", trans_cb, NULL));
+ X(intercept_register_translink("linux", "chmod", 0));
+ X(intercept_register_translation("linux", "chmod", 1, &modeflags));
+
+ X(intercept_register_execcb(execres_cb, NULL));
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: systrace [-ait] [-f policy] command ...\n");
+ exit(1);
+}
+
+int
+requestor_start(char *path)
+{
+ char *argv[2];
+ int pair[2];
+ pid_t pid;
+
+ argv[0] = path;
+ argv[1] = NULL;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ err(1, "socketpair");
+
+ pid = fork();
+ if (pid == -1)
+ err(1, "fork");
+ if (pid == 0) {
+ close(pair[0]);
+ if (dup2(pair[1], fileno(stdin)) == -1)
+ err(1, "dup2");
+ if (dup2(pair[1], fileno(stdout)) == -1)
+ err(1, "dup2");
+ setlinebuf(stdout);
+
+ close(pair[1]);
+
+ execvp(path, argv);
+
+ err(1, "execvp");
+ }
+
+ close(pair[1]);
+ if (dup2(pair[0], fileno(stdin)) == -1)
+ err(1, "dup2");
+
+ if (dup2(pair[0], fileno(stdout)) == -1)
+ err(1, "dup2");
+
+ close(pair[0]);
+
+ setlinebuf(stdout);
+
+ connected = 1;
+
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i, c;
+ char **args;
+ char *filename = NULL;
+ int usex11 = 1;
+
+ while ((c = getopt(argc, argv, "aitf:")) != -1) {
+ switch (c) {
+ case 'a':
+ automatic = 1;
+ break;
+ case 'i':
+ inherit = 1;
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+ case 't':
+ usex11 = 0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ if ((args = malloc((argc + 1) * sizeof(char *))) == NULL)
+ err(1, "malloc");
+
+ for (i = 0; i < argc; i++)
+ args[i] = argv[i];
+ args[i] = NULL;
+
+ if (signal(SIGCHLD, child_handler) == SIG_ERR)
+ err(1, "signal");
+
+ /* Local initalization */
+ systrace_initpolicy(filename);
+ systrace_initcb();
+
+ X(fd = intercept_open());
+
+ pid = intercept_run(fd, args[0], args);
+ if (pid == -1)
+ err(1, "fork");
+
+ if (intercept_attach(fd, pid) == -1)
+ err(1, "attach");
+
+ if (usex11 && !automatic)
+ requestor_start("./notification/src/notification");
+
+ if (kill(pid, SIGCONT) == -1)
+ err(1, "kill");
+
+ while (intercept_read(fd) != -1)
+ if (!intercept_existpids())
+ break;
+
+ systrace_dumppolicy();
+
+ close(fd);
+
+ exit(0);
+}