diff options
author | Niels Provos <provos@cvs.openbsd.org> | 2002-06-04 17:20:05 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 2002-06-04 17:20:05 +0000 |
commit | 46a8c64495ad8a9d221a6c0fa12e7d77b6e2420b (patch) | |
tree | 9c7200a8a35c2bee11d017386d12aab0d8bca720 /bin/systrace/systrace.c | |
parent | 72975dabb915c98862a98d34d585bdc781702b4d (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.c | 450 |
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); +} |