diff options
Diffstat (limited to 'bin/systrace')
-rw-r--r-- | bin/systrace/Makefile | 7 | ||||
-rw-r--r-- | bin/systrace/cradle.c | 385 | ||||
-rw-r--r-- | bin/systrace/filter.c | 22 | ||||
-rw-r--r-- | bin/systrace/systrace.1 | 10 | ||||
-rw-r--r-- | bin/systrace/systrace.c | 107 | ||||
-rw-r--r-- | bin/systrace/systrace.h | 6 |
6 files changed, 499 insertions, 38 deletions
diff --git a/bin/systrace/Makefile b/bin/systrace/Makefile index d76b603f49c..115afd556cf 100644 --- a/bin/systrace/Makefile +++ b/bin/systrace/Makefile @@ -1,11 +1,14 @@ -# $OpenBSD: Makefile,v 1.11 2004/01/05 02:55:28 espie Exp $ +# $OpenBSD: Makefile,v 1.12 2004/01/23 20:51:18 sturm Exp $ PROG= systrace CFLAGS+=-I. -I${.CURDIR} CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ -Wno-uninitialized CFLAGS+=-DYY_NO_UNPUT -SRCS= filter.c intercept-translate.c intercept.c \ +DPADD+= ${LIBEVENT} +LDADD+= -levent + +SRCS= cradle.c filter.c intercept-translate.c intercept.c \ openbsd-syscalls.c util.c \ policy.c systrace-errno.h systrace-error.c \ systrace-translate.c systrace.c alias.c register.c \ diff --git a/bin/systrace/cradle.c b/bin/systrace/cradle.c new file mode 100644 index 00000000000..3d38b8d586a --- /dev/null +++ b/bin/systrace/cradle.c @@ -0,0 +1,385 @@ +/* $OpenBSD: cradle.c,v 1.1 2004/01/23 20:51:18 sturm Exp $ */ + +/* + * Copyright (c) 2003 Marius Aamodt Eriksen <marius@monkey.org> + * 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. + * + * 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/time.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/queue.h> +#include <sys/tree.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> + +#include <err.h> +#include <errno.h> +#include <event.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <limits.h> +#ifdef __linux__ +#include <bits/posix1_lim.h> +#ifndef LOGIN_NAME_MAX +#define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX +#endif +#endif /* __linux__ */ + +#include "intercept.h" +#include "systrace.h" + +extern int connected; +extern char dirpath[]; + +static struct event listen_ev; +static struct event uilisten_ev; + +static int cradle_server(char *path, char *uipath, char *guipath); +static void listen_cb(int, short, void *); +static void msg_cb(int, short, void *); +static void ui_cb(int, short, void *); +static void gensig_cb(int, short, void *); + +static FILE *ui_fl = NULL; +static struct event ui_ev, sigterm_ev, sigint_ev; +static char buffer[4096]; +static char title[4096]; +static char *xuipath, *xpath; +static volatile int got_sigusr1 = 0; + +struct client { + struct event ev; + FILE *fl; + int buffered; + TAILQ_ENTRY(client) next; +}; + +TAILQ_HEAD(client_head, client) clientq; + +/* fake signal handler */ +static void +sigusr1_handler(int sig) +{ + got_sigusr1 = 1; +} + +static void +gensig_cb(int sig, short ev, void *data) +{ + unlink(xpath); + unlink(xuipath); + + rmdir(dirpath); + + exit(1); +} + +static int +mkunserv(char *path) +{ + int s; + struct sockaddr_un sun; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + err(1, "socket()"); + + memset(&sun, 0, sizeof (sun)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, path, sizeof (sun.sun_path)) >= + sizeof (sun.sun_path)) + errx(1, "Path too long: %s", path); + + if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(1, "bind()"); + + if (chmod(path, S_IRUSR | S_IWUSR) == -1) + err(1, "chmod()"); + + if (listen(s, 10) == -1) + err(1, "listen()"); + + return (s); +} + +static int +cradle_server(char *path, char *uipath, char *guipath) +{ + int s, uis; + pid_t pid, newpid; + sigset_t none, set, oldset; + sig_t oldhandler; + + sigemptyset(&none); + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + if (sigprocmask(SIG_BLOCK, &set, &oldset) == -1) + err(1, "sigprocmask()"); + oldhandler = signal(SIGUSR1, sigusr1_handler); + if (oldhandler == SIG_ERR) + err(1, "signal()"); + + xpath = path; + xuipath = uipath; + + pid = getpid(); + newpid = fork(); + + switch (newpid) { + case -1: + err(1, "fork()"); + case 0: + break; + default: + /* + * Parent goes to sleep waiting for server to start. + * When it wakes up, we can start the GUI. + */ + sigsuspend(&none); + if (signal(SIGUSR1, oldhandler) == SIG_ERR) + err(1, "signal()"); + if (sigprocmask(SIG_SETMASK, &oldset, NULL) == -1) + err(1, "sigprocmask()"); + if (got_sigusr1) { + requestor_start(guipath, 1); + return (0); + } else + return (-1); + } + + setsid(); + snprintf(title, sizeof(title), "cradle server for UID %d", getuid()); + setproctitle(title); + + TAILQ_INIT(&clientq); + + event_init(); + + s = mkunserv(path); + uis = mkunserv(uipath); + + signal_set(&sigterm_ev, SIGTERM, gensig_cb, NULL); + if (signal_add(&sigterm_ev, NULL) == -1) + err(1, "signal_add()"); + + signal_set(&sigint_ev, SIGINT, gensig_cb, NULL); + if (signal_add(&sigint_ev, NULL) == -1) + err(1, "signal_add()"); + + event_set(&listen_ev, s, EV_READ, listen_cb, NULL); + if (event_add(&listen_ev, NULL) == -1) + err(1, "event_add()"); + + event_set(&uilisten_ev, uis, EV_READ, listen_cb, &listen_cb); + if (event_add(&uilisten_ev, NULL) == -1) + err(1, "event_add()"); + + kill(pid, SIGUSR1); + + event_dispatch(); + errx(1, "event_dispatch()"); + /* NOTREACHED */ + /* gcc fodder */ + return (-1); +} + +void +cradle_start(char *path, char *uipath, char *guipath) +{ + int s; + struct sockaddr_un sun; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) + err(1, "socket()"); + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, path, sizeof (sun.sun_path)) >= + sizeof (sun.sun_path)) + errx(1, "Path too long: %s", path); + + while (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + if (errno != ENOENT) + err(1, "connect()"); + + if (cradle_server(path, uipath, guipath) == -1) + errx(1, "failed contacting or starting cradle server"); + } + + if (dup2(s, fileno(stdin)) == -1) + err(1, "dup2"); + if (dup2(s, fileno(stdout)) == -1) + err(1, "dup2"); + setlinebuf(stdout); + + connected = 1; +} + +static void +listen_cb(int fd, short which, void *arg) +{ + int s, ui = arg != NULL; + struct sockaddr sa; + struct client *cli; + socklen_t salen = sizeof(sa); + struct event *ev; + + s = accept(fd, &sa, &salen); + if (s == -1) { + warn("accept()"); + goto out; + } + + if (ui) { + if (ui_fl != NULL) + goto out; + + if ((ui_fl = fdopen(s, "w+")) == NULL) + err(1, "fdopen()"); + setvbuf(ui_fl, NULL, _IONBF, 0); + event_set(&ui_ev, s, EV_READ | EV_PERSIST, ui_cb, NULL); + + /* Dequeue UI-pending events */ + while ((cli = TAILQ_FIRST(&clientq)) != NULL) { + TAILQ_REMOVE(&clientq, cli, next); + msg_cb(fileno(cli->fl), EV_READ, cli); + if (ui_fl == NULL) + break; + } + + if (event_add(&ui_ev, NULL) == -1) + err(1, "event_add()"); + } else { + if ((cli = calloc(1, sizeof(*cli))) == NULL) + err(1, "calloc()"); + + if ((cli->fl = fdopen(s, "w+")) == NULL) + err(1, "fdopen()"); + + setvbuf(cli->fl, NULL, _IONBF, 0); + event_set(&cli->ev, s, EV_READ, msg_cb, cli); + if (event_add(&cli->ev, NULL) == -1) + err(1, "event_add()"); + } + out: + ev = ui ? &uilisten_ev : &listen_ev; + if (event_add(ev, NULL) == -1) + err(1, "event_add()"); +} + +static void +msg_cb(int fd, short which, void *arg) +{ + struct client *cli = arg; + char line[4096]; + + if (ui_fl == NULL) { + TAILQ_INSERT_TAIL(&clientq, cli, next); + return; + } + + /* Policy question from systrace */ + if (!cli->buffered) + if (fgets(buffer, sizeof(buffer), cli->fl) == NULL) + goto out_eof; + cli->buffered = 0; + + if (fputs(buffer, ui_fl) == EOF) + goto out_uieof0; + again_answer: + /* Policy answer from UI */ + if (fgets(line, sizeof(line), ui_fl) == NULL) + goto out_uieof0; + if (fputs(line, cli->fl) == EOF) + goto out_eof; + /* Status from systrace */ + while (1) { + if (fgets(line, sizeof(line), cli->fl) == NULL) + goto out_eof; + if (fputs(line, ui_fl) == EOF) + goto out_uieof1; + if (strcmp(line, "WRONG\n") == 0) + goto again_answer; + if (strcmp(line, "OKAY\n") == 0) + break; + } + + out_event: + if (event_add(&cli->ev, NULL) == -1) + err(1, "event_add()"); + return; + + out_eof: + fclose(cli->fl); + free(cli); + return; + + out_uieof0: + fclose(ui_fl); + ui_fl = NULL; + cli->buffered = 1; + TAILQ_INSERT_HEAD(&clientq, cli, next); + return; + + out_uieof1: + fclose(ui_fl); + ui_fl = NULL; + while (1) { + /* We have a line coming in... */ + if (strcmp(line, "WRONG\n") == 0) + if (fputs("kill\n", cli->fl) == EOF) + goto out_eof; + if (strcmp(line, "OKAY\n") == 0) + break; + if (fgets(line, sizeof(line), cli->fl) == NULL) + goto out_eof; + } + + goto out_event; +} + +/* + * Hack to catch "idle" EOFs from the UI + */ +static void +ui_cb(int fd, short which, void *arg) +{ + char c; + + fread(&c, sizeof(c), 1, ui_fl); + + if (feof(ui_fl)) { + ui_fl = NULL; + event_del(&ui_ev); + } else + warnx("Junk from UI"); +} diff --git a/bin/systrace/filter.c b/bin/systrace/filter.c index 778522acf8b..48c8f5c92b1 100644 --- a/bin/systrace/filter.c +++ b/bin/systrace/filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filter.c,v 1.29 2003/08/04 18:15:11 sturm Exp $ */ +/* $OpenBSD: filter.c,v 1.30 2004/01/23 20:51:18 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -40,6 +40,7 @@ #include <stdio.h> #include <fcntl.h> #include <regex.h> +#include <errno.h> #include <fnmatch.h> #include <err.h> @@ -51,9 +52,13 @@ extern int allow; extern int noalias; extern int connected; +extern int cradle; extern char cwd[]; extern char home[]; extern char username[]; +extern char *guipath; + +int requestor_restart = 0; static void logic_free(struct logic *); static int filter_match(struct intercept_pid *, struct intercept_tlq *, @@ -561,8 +566,18 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, } } - if (fgets(line, sizeof(line), stdin) == NULL) - errx(1, "EOF on policy input request"); + if (fgets(line, sizeof(line), stdin) == NULL) { + if (connected && !cradle && errno == EPIPE && + !requestor_restart) { + requestor_start(guipath, 0); + clearerr(stdin); + clearerr(stdout); + requestor_restart = 1; + printf("%s\n", output); + continue; + } + err(1, "EOF on policy input request"); + } p = line; strsep(&p, "\n"); } else if (!first) { @@ -570,6 +585,7 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, errx(1, "Filter generation error: %s", line); } first = 0; + requestor_restart = 0; /* Simple keywords */ if (!strcasecmp(line, "detach")) { diff --git a/bin/systrace/systrace.1 b/bin/systrace/systrace.1 index 7336d218851..9d5ff2a369e 100644 --- a/bin/systrace/systrace.1 +++ b/bin/systrace/systrace.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: systrace.1,v 1.38 2004/01/07 21:15:42 sturm Exp $ +.\" $OpenBSD: systrace.1,v 1.39 2004/01/23 20:51:18 sturm Exp $ .\" .\" Copyright 2002 Niels Provos <provos@citi.umich.edu> .\" All rights reserved. @@ -30,7 +30,7 @@ .\" .\" Manual page, using -mandoc macros .\" -.Dd May 21, 2003 +.Dd November 28, 2003 .Dt SYSTRACE 1 .Os .Sh NAME @@ -39,7 +39,7 @@ .Sh SYNOPSIS .Nm systrace .Bk -words -.Op Fl AaeitUu +.Op Fl AaCeitUu .Op Fl c Ar uid:gid .Op Fl d Ar policydir .Op Fl f Ar file @@ -92,6 +92,10 @@ or to if the .Fl e flag is specified. +.It Fl C +Run systrace in cradle mode; if a cradle server is not running, one is +launched. +This decouples UIs from systrace, allowing for re-attaching UIs. .It Fl c Ar uid:gid Specifies the .Va uid diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c index 32e62253a6f..358b2764b4b 100644 --- a/bin/systrace/systrace.c +++ b/bin/systrace/systrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.c,v 1.48 2004/01/07 21:15:43 sturm Exp $ */ +/* $OpenBSD: systrace.c,v 1.49 2004/01/23 20:51:18 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -34,6 +34,7 @@ #include <sys/wait.h> #include <sys/tree.h> #include <sys/socket.h> +#include <sys/stat.h> #include <limits.h> #include <stdlib.h> #include <unistd.h> @@ -52,6 +53,9 @@ #include "systrace.h" #include "util.h" +#define CRADLE_SERVER "cradle_server" +#define CRADLE_UI "cradle_ui" + pid_t trpid; int trfd; int connected = 0; /* Connected to GUI */ @@ -61,15 +65,17 @@ int allow = 0; /* Allow all and generate */ int userpolicy = 1; /* Permit user defined policies */ int noalias = 0; /* Do not do system call aliasing */ int iamroot = 0; /* Set if we are running as root */ +int cradle = 0; /* Set if we are running in cradle mode */ int logstderr = 0; /* Log to STDERR instead of syslog */ char cwd[MAXPATHLEN]; /* Current working directory */ char home[MAXPATHLEN]; /* Home directory of user */ char username[MAXLOGNAME]; /* Username: predicate match and expansion */ +char *guipath = _PATH_XSYSTRACE; /* Path to GUI executable */ +char dirpath[MAXPATHLEN]; static void child_handler(int); static void log_msg(int, const char *, ...); static void usage(void); -static int requestor_start(char *); void systrace_parameters(void) @@ -431,58 +437,94 @@ static void usage(void) { fprintf(stderr, - "Usage: systrace [-AaitUu] [-c uid:gid] [-d policydir] [-f file]\n" + "Usage: systrace [-AaCeitUu] [-c uid:gid] [-d policydir] [-f file]\n" "\t [-g gui] [-p pid] command ...\n"); exit(1); } -static int -requestor_start(char *path) +int +requestor_start(char *path, int docradle) { - char *argv[2]; + char *argv[3]; int pair[2]; pid_t pid; argv[0] = path; - argv[1] = NULL; + argv[1] = docradle ? "-C" : NULL; + argv[2] = NULL; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + if (!docradle && 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]); + if (!docradle) { + 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: %s", path); + } - close(pair[1]); - if (dup2(pair[0], fileno(stdin)) == -1) - err(1, "dup2"); + if (!docradle) { + close(pair[1]); + if (dup2(pair[0], fileno(stdin)) == -1) + err(1, "dup2"); - if (dup2(pair[0], fileno(stdout)) == -1) - err(1, "dup2"); + if (dup2(pair[0], fileno(stdout)) == -1) + err(1, "dup2"); - close(pair[0]); + close(pair[0]); - setlinebuf(stdout); + setlinebuf(stdout); - connected = 1; + connected = 1; + } return (0); } + +static void +cradle_setup(char *pathtogui) +{ + struct stat sb; + char cradlepath[MAXPATHLEN], cradleuipath[MAXPATHLEN]; + + snprintf(dirpath, sizeof(dirpath), "/tmp/systrace-%d", getuid()); + + if (stat(dirpath, &sb) == -1) { + if (errno != ENOENT) + err(1, "stat()"); + if (mkdir(dirpath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + err(1, "mkdir()"); + } else { + if (sb.st_uid != getuid()) + errx(1, "Wrong owner on directory %s", dirpath); + if (sb.st_mode != (S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR)) + errx(1, "Wrong permissions on directory %s", dirpath); + } + + strlcpy(cradlepath, dirpath, sizeof (cradlepath)); + strlcat(cradlepath, "/" CRADLE_SERVER, sizeof (cradlepath)); + + strlcpy(cradleuipath, dirpath, sizeof (cradleuipath)); + strlcat(cradleuipath, "/" CRADLE_UI, sizeof (cradleuipath)); + + cradle_start(cradlepath, cradleuipath, pathtogui); +} + static int get_uid_gid(const char *argument, uid_t *uid, gid_t *gid) { @@ -538,7 +580,6 @@ main(int argc, char **argv) char **args; char *filename = NULL; char *policypath = NULL; - char *guipath = _PATH_XSYSTRACE; struct timeval tv, tv_wait = {60, 0}; pid_t pidattach = 0; int usex11 = 1, count; @@ -547,7 +588,7 @@ main(int argc, char **argv) uid_t cr_uid; gid_t cr_gid; - while ((c = getopt(argc, argv, "c:aAeituUd:g:f:p:")) != -1) { + while ((c = getopt(argc, argv, "c:aAeituUCd:g:f:p:")) != -1) { switch (c) { case 'c': setcredentials = 1; @@ -579,6 +620,9 @@ main(int argc, char **argv) case 'g': guipath = optarg; break; + case 'C': + cradle = 1; + break; case 'f': filename = optarg; break; @@ -662,9 +706,14 @@ main(int argc, char **argv) if (signal(SIGCHLD, child_handler) == SIG_ERR) err(1, "signal"); - /* Start the policy gui if necessary */ - if (usex11 && !automatic && !allow) - requestor_start(guipath); + /* Start the policy gui or cradle if necessary */ + if (usex11 && (!automatic && !allow)) { + if (cradle) + cradle_setup(guipath); + else + requestor_start(guipath, 0); + + } /* Loop on requests */ count = 0; diff --git a/bin/systrace/systrace.h b/bin/systrace/systrace.h index 7ec93afb46d..ceb69613c35 100644 --- a/bin/systrace/systrace.h +++ b/bin/systrace/systrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.h,v 1.24 2003/10/08 16:32:44 sturm Exp $ */ +/* $OpenBSD: systrace.h,v 1.25 2004/01/23 20:51:18 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -202,6 +202,8 @@ char *filter_expand(char *); char *filter_dynamicexpand(struct intercept_pid *, char *); int filter_needexpand(char *); +void cradle_start(char *, char *, char *); + int parse_filter(char *, struct filter **); char *uid_to_name(uid_t); @@ -232,4 +234,6 @@ extern struct intercept_translate ic_signame; extern struct intercept_translate ic_linux_oflags; +int requestor_start(char *, int); + #endif /* _SYSTRACE_H_ */ |