summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsturm <sturm@openbsd.org>2006-07-02 12:34:15 +0000
committersturm <sturm@openbsd.org>2006-07-02 12:34:15 +0000
commit21398955d81c21e7b53a18dfd69b7ebb0417f336 (patch)
tree04e3927a7ebad0d42d7b56908dc16ccdc0b7a8d5
parentdocument the vfs_busy class of functions (diff)
downloadwireguard-openbsd-21398955d81c21e7b53a18dfd69b7ebb0417f336.tar.xz
wireguard-openbsd-21398955d81c21e7b53a18dfd69b7ebb0417f336.zip
sync with systrace 1.6d, keeping local changes
tests and feedback by a few
-rw-r--r--bin/systrace/Makefile4
-rw-r--r--bin/systrace/cradle.c12
-rw-r--r--bin/systrace/filter.c16
-rw-r--r--bin/systrace/intercept.c36
-rw-r--r--bin/systrace/intercept.h14
-rw-r--r--bin/systrace/lex.l6
-rw-r--r--bin/systrace/linux-translate.c384
-rw-r--r--bin/systrace/linux-translate.h43
-rw-r--r--bin/systrace/linux_socketcall.h196
-rw-r--r--bin/systrace/openbsd-syscalls.c4
-rw-r--r--bin/systrace/policy.c205
-rw-r--r--bin/systrace/register.c20
-rw-r--r--bin/systrace/systrace-translate.c59
-rw-r--r--bin/systrace/systrace.114
-rw-r--r--bin/systrace/systrace.c234
-rw-r--r--bin/systrace/systrace.h25
16 files changed, 1119 insertions, 153 deletions
diff --git a/bin/systrace/Makefile b/bin/systrace/Makefile
index 1450f01d385..fe8c1dc0a21 100644
--- a/bin/systrace/Makefile
+++ b/bin/systrace/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.14 2006/06/30 19:03:43 otto Exp $
+# $OpenBSD: Makefile,v 1.15 2006/07/02 12:34:15 sturm Exp $
PROG= systrace
CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys
@@ -9,7 +9,7 @@ DPADD+= ${LIBEVENT}
LDADD+= -levent
SRCS= cradle.c filter.c intercept-translate.c intercept.c \
- openbsd-syscalls.c util.c \
+ linux-translate.c openbsd-syscalls.c util.c \
policy.c systrace-errno.h systrace-error.c \
systrace-translate.c systrace.c alias.c register.c \
parse.y lex.l
diff --git a/bin/systrace/cradle.c b/bin/systrace/cradle.c
index 821c6ade20a..336f77994cc 100644
--- a/bin/systrace/cradle.c
+++ b/bin/systrace/cradle.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cradle.c,v 1.3 2006/04/26 20:19:25 sturm Exp $ */
+/* $OpenBSD: cradle.c,v 1.4 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright (c) 2003 Marius Aamodt Eriksen <marius@monkey.org>
@@ -61,11 +61,11 @@ 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 int cradle_server(char *, char *, char *);
+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;
diff --git a/bin/systrace/filter.c b/bin/systrace/filter.c
index 6d9fcc1c277..576b848af2d 100644
--- a/bin/systrace/filter.c
+++ b/bin/systrace/filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: filter.c,v 1.32 2006/05/02 19:49:05 sturm Exp $ */
+/* $OpenBSD: filter.c,v 1.33 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -397,6 +397,10 @@ filter_modifypolicy(int fd, int policynr, const char *emulation,
{
struct systrace_revalias *reverse = NULL;
+ /*
+ * Check if we are dealing with a system call that really
+ * is an alias for something else.
+ */
if (!noalias)
reverse = systrace_find_reverse(emulation, name);
if (reverse == NULL) {
@@ -441,6 +445,12 @@ filter_quickpredicate(struct filter *filter)
return (1);
}
+/*
+ * Processes the filters for a policy that have not been applied yet.
+ * Pre-filters get installed when reading a policy. This function
+ * installs a fast-path in the kernel.
+ */
+
int
filter_prepolicy(int fd, struct policy *policy)
{
@@ -549,10 +559,8 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls,
while (1) {
/* Special policy active that allows only yes or no */
- if (icpid->uflags & PROCESS_PROMPT) {
- fprintf(stderr, "isprompt\n");
+ if (icpid->uflags & PROCESS_PROMPT)
isprompt = 1;
- }
filter = NULL;
if (!allow) {
diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c
index c17d6850320..0e8815942fd 100644
--- a/bin/systrace/intercept.c
+++ b/bin/systrace/intercept.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.c,v 1.51 2006/04/26 20:19:25 sturm Exp $ */
+/* $OpenBSD: intercept.c,v 1.52 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -29,6 +29,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/tree.h>
@@ -241,7 +242,7 @@ intercept_register_pfreecb(void (*cb)(int, void *), void *arg)
/* ARGSUSED */
static void
sigusr1_handler(int signum)
-{
+{
/* all we need to do is pretend to handle it */
got_sigusr1 = 1;
}
@@ -549,6 +550,9 @@ intercept_get_string(int fd, pid_t pid, void *addr)
static char name[8192];
int off = 0, done = 0, stride;
+ if (addr == NULL)
+ return (NULL);
+
stride = 32;
do {
if (intercept.io(fd, pid, INTERCEPT_READ, (char *)addr + off,
@@ -636,7 +640,6 @@ normalize_filename(int fd, pid_t pid, char *name, int userp)
havecwd = 1;
}
- /* Need concatenated path for simplifypath */
if (havecwd && name[0] != '/') {
if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd))
return (NULL);
@@ -658,8 +661,7 @@ normalize_filename(int fd, pid_t pid, char *name, int userp)
if (userp == ICLINK_NOLAST) {
/* Check if the last component has special meaning */
- if (strcmp(base, "..") == 0 ||
- strcmp(base, "/") == 0)
+ if (strcmp(base, "..") == 0 || strcmp(base, "/") == 0)
userp = ICLINK_ALL;
else
goto nolast;
@@ -867,7 +869,6 @@ intercept_newimage(int fd, pid_t pid, int policynr,
icpid->name, intercept_newimagecbarg);
}
-
int
intercept_newpolicy(int fd)
{
@@ -885,6 +886,12 @@ intercept_assignpolicy(int fd, pid_t pid, int policynr)
}
int
+intercept_modifypolicy_nr(int fd, int policynr, int code, short policy)
+{
+ return (intercept.policy(fd, policynr, code, policy));
+}
+
+int
intercept_modifypolicy(int fd, int policynr, const char *emulation,
const char *name, short policy)
{
@@ -958,12 +965,27 @@ intercept_ugid(struct intercept_pid *icpid, uid_t uid, gid_t gid)
}
/*
+ * Returns the number of a system call
+ */
+
+int
+intercept_getsyscallnumber(const char *emulation, const char *name)
+{
+ int nr = intercept.getsyscallnumber(emulation, name);
+
+ if (nr >= INTERCEPT_MAXSYSCALLNR)
+ err(1, "%s: system call number too high: %d", __func__, nr);
+
+ return (nr);
+}
+
+/*
* Checks if the given emulation has a certain system call.
* This is a very slow function.
*/
int
-intercept_isvalidsystemcall(char *emulation, char *name)
+intercept_isvalidsystemcall(const char *emulation, const char *name)
{
int res;
diff --git a/bin/systrace/intercept.h b/bin/systrace/intercept.h
index bf8f595eb48..d371dfb9e31 100644
--- a/bin/systrace/intercept.h
+++ b/bin/systrace/intercept.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.h,v 1.23 2006/06/10 07:19:13 sturm Exp $ */
+/* $OpenBSD: intercept.h,v 1.24 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -101,7 +101,7 @@ struct intercept_pid {
uid_t uid; /* current uid */
gid_t gid; /* current gid */
- char username[MAXLOGNAME];
+ char username[LOGIN_NAME_MAX];
char home[MAXPATHLEN]; /* current home dir for uid */
void *data;
@@ -110,6 +110,7 @@ struct intercept_pid {
struct elevate *elevate; /* privilege elevation request */
};
+#define INTERCEPT_MAXSYSCALLNR 512
#define INTERCEPT_MAXSYSCALLARGS 10
struct intercept_translate {
@@ -125,6 +126,7 @@ struct intercept_translate {
size_t trans_size;
char *trans_print;
u_int trans_flags;
+ void *user;
TAILQ_ENTRY(intercept_translate) next;
};
@@ -148,6 +150,7 @@ int intercept_read(int);
int intercept_newpolicy(int);
int intercept_assignpolicy(int, pid_t, int);
int intercept_modifypolicy(int, int, const char *, const char *, short);
+int intercept_modifypolicy_nr(int, int, int, short);
void intercept_child_info(pid_t, pid_t);
void intercept_policy_free(int);
@@ -196,11 +199,12 @@ void intercept_syscall(int, pid_t, u_int16_t, int, const char *, int,
const char *, void *, int);
void intercept_syscall_result(int, pid_t, u_int16_t, int, const char *, int,
const char *, void *, int, int, void *);
-void intercept_ugid(struct intercept_pid *, uid_t, gid_t);
-void intercept_setpid(struct intercept_pid *, uid_t, gid_t);
void intercept_newimage(int, pid_t, int,
const char *, char *, struct intercept_pid *);
+void intercept_ugid(struct intercept_pid *, uid_t, gid_t);
+void intercept_setpid(struct intercept_pid *, uid_t, gid_t);
-int intercept_isvalidsystemcall(char *, char *);
+int intercept_getsyscallnumber(const char *, const char *);
+int intercept_isvalidsystemcall(const char *, const char *);
#endif /* _INTERCEPT_H_ */
diff --git a/bin/systrace/lex.l b/bin/systrace/lex.l
index 247dfd187a1..3d5511d2dcf 100644
--- a/bin/systrace/lex.l
+++ b/bin/systrace/lex.l
@@ -1,4 +1,4 @@
-/* $OpenBSD: lex.l,v 1.17 2003/11/27 17:39:08 sturm Exp $ */
+/* $OpenBSD: lex.l,v 1.18 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -137,8 +137,8 @@ as { return AS; }
yylval.string = strdup(quotestr);
return CMDSTRING;
} else {
- strlcat(quotestr, "\"", sizeof(quotestr));
- quoteescape = 0;
+ strlcat(quotestr, "\"", sizeof(quotestr));
+ quoteescape = 0;
}
}
\[ { return LSQBRACE; }
diff --git a/bin/systrace/linux-translate.c b/bin/systrace/linux-translate.c
new file mode 100644
index 00000000000..c3d0af75cc9
--- /dev/null
+++ b/bin/systrace/linux-translate.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2002 Marius Aamodt Eriksen <marius@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 <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <err.h>
+#include <netdb.h>
+
+#include <compat/linux/linux_socket.h>
+#include <compat/linux/linux_types.h>
+#include <compat/linux/linux_fcntl.h>
+#include "linux_socketcall.h"
+
+#include "intercept.h"
+#include "systrace.h"
+
+extern struct intercept_system intercept;
+
+/* XXX register_t */
+#define ARGSIZE(n) ((n) * sizeof(unsigned long))
+static unsigned char socketcall_argsize[18] = {
+ ARGSIZE(0), /* none */
+ ARGSIZE(3), /* LINUX_SYS_socket */
+ ARGSIZE(3), /* LINUX_SYS_bind */
+ ARGSIZE(3), /* LINUX_SYS_connect */
+ ARGSIZE(2), /* LINUX_SYS_listen */
+ ARGSIZE(3), /* LINUX_SYS_accept */
+ ARGSIZE(3), /* LINUX_SYS_getsockname */
+ ARGSIZE(3), /* LINUX_SYS_getpeername */
+ ARGSIZE(4), /* LINUX_SYS_socketpair */
+ ARGSIZE(4), /* LINUX_SYS_send */
+ ARGSIZE(4), /* LINUX_SYS_recv */
+ ARGSIZE(6), /* LINUX_SYS_sendto */
+ ARGSIZE(6), /* LINUX_SYS_recvfrom */
+ ARGSIZE(2), /* LINUX_SYS_shutdown */
+ ARGSIZE(5), /* LINUX_SYS_setsockopt */
+ ARGSIZE(5), /* LINUX_SYS_getsockopt */
+ ARGSIZE(3), /* LINUX_SYS_sendmsg */
+ ARGSIZE(3) /* LINUX_SYS_recvmsg */
+};
+
+/* ARGSUSED */
+static int
+get_socketcall(struct intercept_translate *trans, int fd, pid_t pid, void *addr)
+{
+ int call = (intptr_t)addr;
+
+ systrace_switch_alias("linux", "socketcall", "linux",
+ linux_socketcall_names[call]);
+
+ /* We don't want to print the argument .. */
+ trans->trans_valid = 0;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+print_socketcall(char *buf, size_t buflen, struct intercept_translate *tl)
+{
+ return (0);
+}
+
+static int
+get_socketcall_args(struct intercept_translate *trans, int fd, pid_t pid,
+ void *addr)
+{
+ int call = (intptr_t)trans->trans_addr2;
+ unsigned long argsize;
+
+ if (call != (intptr_t)trans->user) {
+ trans->trans_valid = 0;
+ return (0);
+ }
+
+ argsize = socketcall_argsize[call];
+
+ if ((trans->trans_data = malloc(argsize)) == NULL)
+ return (-1);
+
+ if (intercept.io(fd, pid, INTERCEPT_READ, addr,
+ trans->trans_data, argsize) == -1) {
+ free(trans->trans_data);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+print_socktype(char *buf, size_t buflen, struct intercept_translate *tl)
+{
+ char *what = NULL;
+ unsigned long *args = tl->trans_data;
+ int type = args[1];
+
+ switch (type) {
+ case SOCK_STREAM:
+ what = "SOCK_STREAM";
+ break;
+ case SOCK_DGRAM:
+ what = "SOCK_DGRAM";
+ break;
+ case SOCK_RAW:
+ what = "SOCK_RAW";
+ break;
+ case SOCK_SEQPACKET:
+ what = "SOCK_SEQPACKET";
+ break;
+ case SOCK_RDM:
+ what = "SOCK_RDM";
+ break;
+ default:
+ snprintf(buf, buflen, "SOCK_UNKNOWN(%d)", type);
+ break;
+ }
+
+ if (what != NULL)
+ strlcpy(buf, what, buflen);
+
+ return (0);
+}
+
+static int
+print_sockdom(char *buf, size_t buflen, struct intercept_translate *tl)
+{
+ char *what = NULL;
+ unsigned long *args = tl->trans_data;
+ int domain = args[0];
+
+ switch (domain) {
+ case LINUX_AF_UNIX:
+ what = "AF_UNIX";
+ break;
+ case LINUX_AF_INET:
+ what = "AF_INET";
+ break;
+ case LINUX_AF_INET6:
+ what = "AF_INET6";
+ break;
+ case LINUX_AF_IPX:
+ what = "AF_IPX";
+ break;
+ default:
+ snprintf(buf, buflen, "AF_UNKNOWN(%d)", domain);
+ break;
+ }
+
+ if (what != NULL)
+ strlcpy(buf, what, buflen);
+
+ return (0);
+}
+
+static int
+get_sockaddr(struct intercept_translate *trans, int fd, pid_t pid,
+ void *addr)
+{
+ struct sockaddr_storage sa;
+ socklen_t len;
+ void *sockaddr_addr;
+ unsigned long *args;
+ int call = (intptr_t)trans->trans_addr2;
+
+ if (get_socketcall_args(trans, fd, pid, addr) == -1)
+ return (-1);
+
+ if (trans->trans_valid == 0)
+ return (0);
+
+ args = trans->trans_data;
+
+ len = call == LINUX_SYS_sendto ? args[5] : args[2];
+ sockaddr_addr = (void *)(call == LINUX_SYS_sendto ? args[4] : args[1]);
+
+ if (len == 0 || len > sizeof(struct sockaddr_storage))
+ return (-1);
+
+ if (intercept.io(fd, pid, INTERCEPT_READ, sockaddr_addr,
+ (void *)&sa, len) == -1)
+ return (-1);
+
+ free(trans->trans_data);
+ trans->trans_data = malloc(len);
+ if (trans->trans_data == NULL)
+ return (-1);
+ trans->trans_size = len;
+ memcpy(trans->trans_data, &sa, len);
+
+ return (0);
+}
+
+#ifndef offsetof
+#define offsetof(s, e) ((size_t)&((s *)0)->e)
+#endif
+
+static int
+print_sockaddr(char *buf, size_t buflen, struct intercept_translate *tl)
+{
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
+ struct linux_sockaddr *linux_sa = tl->trans_data;
+ struct sockaddr sa;
+ socklen_t len = (socklen_t)tl->trans_size;
+
+ /* XXX - Niels */
+ tl->trans_size = 0;
+
+ buf[0] = '\0';
+
+ switch (linux_sa->sa_family) {
+ case LINUX_AF_UNIX:
+ if (len <= offsetof(struct linux_sockaddr, sa_data))
+ return (-1);
+ len -= offsetof(struct linux_sockaddr, sa_data);
+ if (buflen < len + 1)
+ len = buflen - 1;
+ memcpy(buf, linux_sa->sa_data, len);
+ buf[len] = '\0';
+ return (0);
+ case LINUX_AF_INET:
+ case LINUX_AF_INET6:
+ break;
+ default:
+ snprintf(buf, buflen, "family(%d)", linux_sa->sa_family);
+ return (0);
+ }
+
+ memcpy(&sa.sa_family, &linux_sa->sa_family, sizeof(sa.sa_family));
+ memcpy(&sa.sa_data, &linux_sa->sa_data, sizeof(sa.sa_data));
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sa.sa_len = len;
+#endif /* HAVE_SOCKADDR_SA_LEN */
+ if (getnameinfo(&sa, len,
+ host, sizeof(host), serv, sizeof(serv),
+ NI_NUMERICHOST | NI_NUMERICSERV)) {
+ warn("getnameinfo");
+ return (-1);
+ }
+
+ snprintf(buf, buflen, "inet-[%s]:%s", host, serv);
+
+ return (0);
+}
+
+static int
+get_msghdr(struct intercept_translate *trans, int fd, pid_t pid,
+ void *addr)
+{
+ struct msghdr msg;
+ int len = sizeof(struct msghdr);
+ unsigned long *args;
+
+ if (get_socketcall_args(trans, fd, pid, addr) == -1)
+ return (-1);
+
+ if (trans->trans_valid == 0)
+ return (0);
+
+ args = trans->trans_data;
+ if (intercept.io(fd, pid, INTERCEPT_READ, (void *)args[1],
+ (void *)&msg, len) == -1)
+ return (-1);
+
+ if (msg.msg_name == NULL) {
+ trans->trans_data = NULL;
+ trans->trans_size = 0;
+ return (0);
+ }
+
+ trans->trans_size = msg.msg_namelen;
+ trans->trans_data = malloc(len);
+ if (trans->trans_data == NULL)
+ return (-1);
+ if (intercept.io(fd, pid, INTERCEPT_READ, msg.msg_name,
+ (void *)trans->trans_data, trans->trans_size) == -1)
+ return (-1);
+
+ return (0);
+}
+
+static int
+print_msghdr(char *buf, size_t buflen, struct intercept_translate *tl)
+{
+ int res = 0;
+ if (tl->trans_size == 0) {
+ snprintf(buf, buflen, "<unknown>");
+ } else {
+ res = print_sockaddr(buf, buflen, tl);
+ /*
+ * disable replacement of this argument because it's two levels
+ * deep and we cant replace that far.
+ */
+ tl->trans_size = 0;
+
+ /* TODO: make this less of a hack */
+ }
+
+ return (res);
+}
+
+struct intercept_translate ic_linux_socket_sockdom = {
+ "sockdom",
+ get_socketcall_args, print_sockdom,
+ -1,
+ .user = (void *)LINUX_SYS_socket
+};
+
+struct intercept_translate ic_linux_socket_socktype = {
+ "socktype",
+ get_socketcall_args, print_socktype,
+ -1,
+ .user = (void *)LINUX_SYS_socket
+};
+
+struct intercept_translate ic_linux_connect_sockaddr = {
+ "sockaddr",
+ get_sockaddr, print_sockaddr,
+ -1,
+ .user = (void *)LINUX_SYS_connect
+};
+
+struct intercept_translate ic_linux_bind_sockaddr = {
+ "sockaddr",
+ get_sockaddr, print_sockaddr,
+ -1,
+ .user = (void *)LINUX_SYS_bind
+};
+
+struct intercept_translate ic_linux_sendto_sockaddr = {
+ "sockaddr",
+ get_sockaddr, print_sockaddr,
+ -1,
+ .user = (void *)LINUX_SYS_sendto
+};
+
+struct intercept_translate ic_linux_sendmsg_sockaddr = {
+ "sockaddr",
+ get_msghdr, print_msghdr,
+ -1,
+ .user = (void *)LINUX_SYS_sendmsg
+};
+
+struct intercept_translate ic_linux_socketcall_catchall = {
+ "call",
+ get_socketcall, print_socketcall,
+};
diff --git a/bin/systrace/linux-translate.h b/bin/systrace/linux-translate.h
new file mode 100644
index 00000000000..a65664b850e
--- /dev/null
+++ b/bin/systrace/linux-translate.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002 Marius Aamodt Eriksen <marius@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.
+ */
+
+
+#ifndef LINUX_TRANSLATE_H
+#define LINUX_TRANSLATE_H
+
+extern struct intercept_translate ic_linux_socket_sockdom;
+extern struct intercept_translate ic_linux_socket_socktype;
+extern struct intercept_translate ic_linux_connect_sockaddr;
+extern struct intercept_translate ic_linux_sendto_sockaddr;
+extern struct intercept_translate ic_linux_sendmsg_sockaddr;
+extern struct intercept_translate ic_linux_socketcall_catchall;
+extern struct intercept_translate ic_linux_bind_sockaddr;
+
+#endif /* LINUX_TRANSLATE_H */
diff --git a/bin/systrace/linux_socketcall.h b/bin/systrace/linux_socketcall.h
new file mode 100644
index 00000000000..be5337ee084
--- /dev/null
+++ b/bin/systrace/linux_socketcall.h
@@ -0,0 +1,196 @@
+/* $OpenBSD: linux_socketcall.h,v 1.1 2006/07/02 12:34:15 sturm Exp $ */
+/* $NetBSD: linux_socketcall.h,v 1.1 1995/02/28 23:26:05 fvdl Exp $ */
+
+/*
+ * Copyright (c) 1995 Frank van der Linden
+ * 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 for the NetBSD Project
+ * by Frank van der Linden
+ * 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.
+ */
+
+#ifndef _LINUX_SOCKETCALL_H
+#define _LINUX_SOCKETCALL_H
+
+/*
+ * Values passed to the Linux socketcall() syscall, determining the actual
+ * action to take.
+ */
+char *linux_socketcall_names[] = {
+ NULL,
+#define LINUX_SYS_socket 1
+ "socket",
+#define LINUX_SYS_bind 2
+ "bind",
+#define LINUX_SYS_connect 3
+ "connect",
+#define LINUX_SYS_listen 4
+ "listen",
+#define LINUX_SYS_accept 5
+ "accept",
+#define LINUX_SYS_getsockname 6
+ "getsockname",
+#define LINUX_SYS_getpeername 7
+ "getpeername",
+#define LINUX_SYS_socketpair 8
+ "socketpair",
+#define LINUX_SYS_send 9
+ "send",
+#define LINUX_SYS_recv 10
+ "recv",
+#define LINUX_SYS_sendto 11
+ "sendto",
+#define LINUX_SYS_recvfrom 12
+ "recvfrom",
+#define LINUX_SYS_shutdown 13
+ "shutdown",
+#define LINUX_SYS_setsockopt 14
+ "setsockopt",
+#define LINUX_SYS_getsockopt 15
+ "getsockopt",
+#define LINUX_SYS_sendmsg 16
+ "sendmsg",
+#define LINUX_SYS_recvmsg 17
+ "recvmsg" };
+
+/*
+ * Structures for the arguments of the different system calls. This looks
+ * a little better than copyin() of all values one by one.
+ */
+struct linux_socket_args {
+ int domain;
+ int type;
+ int protocol;
+};
+
+struct linux_bind_args {
+ int s;
+ struct sockaddr *name;
+ int namelen;
+};
+
+struct linux_connect_args {
+ int s;
+ struct sockaddr *name;
+ int namelen;
+};
+
+struct linux_listen_args {
+ int s;
+ int backlog;
+};
+
+struct linux_accept_args {
+ int s;
+ struct sockaddr *addr;
+ int *namelen;
+};
+
+struct linux_getsockname_args {
+ int s;
+ struct sockaddr *addr;
+ int *namelen;
+};
+
+struct linux_getpeername_args {
+ int s;
+ struct sockaddr *addr;
+ int *namelen;
+};
+
+struct linux_socketpair_args {
+ int domain;
+ int type;
+ int protocol;
+ int *rsv;
+};
+
+struct linux_send_args {
+ int s;
+ void *msg;
+ int len;
+ int flags;
+};
+
+struct linux_recv_args {
+ int s;
+ void *msg;
+ int len;
+ int flags;
+};
+
+struct linux_sendto_args {
+ int s;
+ void *msg;
+ int len;
+ int flags;
+ struct sockaddr *to;
+ int tolen;
+};
+
+struct linux_recvfrom_args {
+ int s;
+ void *buf;
+ int len;
+ int flags;
+ struct sockaddr *from;
+ int *fromlen;
+};
+
+struct linux_shutdown_args {
+ int s;
+ int how;
+};
+
+struct linux_getsockopt_args {
+ int s;
+ int level;
+ int optname;
+ void *optval;
+ int *optlen;
+};
+
+struct linux_setsockopt_args {
+ int s;
+ int level;
+ int optname;
+ void *optval;
+ int optlen;
+};
+
+struct linux_sendmsg_args {
+ int s;
+ struct msghdr *msg;
+ int flags;
+};
+
+struct linux_recvmsg_args {
+ int s;
+ struct msghdr *msg;
+ int flags;
+};
+
+#endif /* _LINUX_SOCKETCALL_H */
diff --git a/bin/systrace/openbsd-syscalls.c b/bin/systrace/openbsd-syscalls.c
index d2ed8bbede7..53eabec7e22 100644
--- a/bin/systrace/openbsd-syscalls.c
+++ b/bin/systrace/openbsd-syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: openbsd-syscalls.c,v 1.30 2006/05/02 19:49:05 sturm Exp $ */
+/* $OpenBSD: openbsd-syscalls.c,v 1.31 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -458,6 +458,8 @@ obsd_replace(int fd, pid_t pid, u_int16_t seqnr,
size_t len, off;
int i, ret;
+ memset(&replace, 0, sizeof(replace));
+
for (i = 0, len = 0; i < repl->num; i++) {
len += repl->len[i];
}
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;
diff --git a/bin/systrace/register.c b/bin/systrace/register.c
index 9e4c14c11ab..11b3838e9f0 100644
--- a/bin/systrace/register.c
+++ b/bin/systrace/register.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: register.c,v 1.20 2006/06/10 07:19:13 sturm Exp $ */
+/* $OpenBSD: register.c,v 1.21 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -39,6 +39,7 @@
#include "intercept.h"
#include "systrace.h"
+#include "linux-translate.h"
#define X(x) if ((x) == -1) \
err(1, "%s:%d: intercept failed", __func__, __LINE__)
@@ -236,6 +237,23 @@ systrace_initcb(void)
intercept_register_translink("linux", "chmod", 0);
intercept_register_translation("linux", "chmod", 1, &ic_modeflags);
+ X(intercept_register_sccb("linux", "socketcall", trans_cb, NULL));
+ alias = systrace_new_alias("linux", "socketcall", "linux", "_socketcall");
+ tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_socket_sockdom);
+ systrace_alias_add_trans(alias, tl);
+ tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_socket_socktype);
+ systrace_alias_add_trans(alias, tl);
+ tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_connect_sockaddr);
+ systrace_alias_add_trans(alias, tl);
+ tl = intercept_register_translation("linux", "socketcall", 1, &ic_linux_bind_sockaddr);
+ systrace_alias_add_trans(alias, tl);
+ tl = intercept_register_translation("linux", "socketcall", 0, &ic_linux_socketcall_catchall);
+ systrace_alias_add_trans(alias, tl);
+
+ X(intercept_register_sccb("linux", "kill", trans_cb, NULL));
+ intercept_register_translation("linux", "kill", 0, &ic_pidname);
+ intercept_register_translation("linux", "kill", 1, &ic_signame);
+
X(intercept_register_execcb(execres_cb, NULL));
X(intercept_register_pfreecb(policyfree_cb, NULL));
}
diff --git a/bin/systrace/systrace-translate.c b/bin/systrace/systrace-translate.c
index 22d2d7a26d8..e965ec49adf 100644
--- a/bin/systrace/systrace-translate.c
+++ b/bin/systrace/systrace-translate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace-translate.c,v 1.20 2006/05/02 19:49:05 sturm Exp $ */
+/* $OpenBSD: systrace-translate.c,v 1.21 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -193,15 +193,15 @@ print_sockdom(char *buf, size_t buflen, struct intercept_translate *tl)
case AF_INET6:
what = "AF_INET6";
break;
+ case AF_IPX:
+ what = "AF_IPX";
+ break;
case AF_ISO:
what = "AF_ISO";
break;
case AF_NS:
what = "AF_NS";
break;
- case AF_IPX:
- what = "AF_IPX";
- break;
case AF_IMPLINK:
what = "AF_IMPLINK";
break;
@@ -267,14 +267,20 @@ print_pidname(char *buf, size_t buflen, struct intercept_translate *tl)
struct intercept_pid *icpid;
pid_t pid = (intptr_t)tl->trans_addr;
- if (pid != 0) {
- icpid = intercept_getpid(pid);
- strlcpy(buf, icpid->name != NULL ? icpid->name : "<unknown>",
- buflen);
- if (icpid->name == NULL)
- intercept_freepid(pid);
- } else
+ if (pid > 0) {
+ icpid = intercept_findpid(pid);
+ strlcpy(buf, icpid != NULL ? icpid->name : "<unknown>", buflen);
+ } else if (pid == 0) {
strlcpy(buf, "<own process group>", buflen);
+ } else if (pid == -1) {
+ strlcpy(buf, "<every process: -1>", buflen);
+ } else {
+ /* pid is negative but not -1 - trying to signal pgroup */
+ pid = -pid;
+ icpid = intercept_findpid(pid);
+ strlcpy(buf, "pg:", buflen);
+ strlcat(buf, icpid != NULL ? icpid->name : "unknown", buflen);
+ }
return (0);
}
@@ -421,6 +427,32 @@ print_fcntlcmd(char *buf, size_t buflen, struct intercept_translate *tl)
return (0);
}
+struct linux_i386_mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+static int
+get_linux_memprot(struct intercept_translate *trans, int fd, pid_t pid,
+ void *addr)
+{
+ struct linux_i386_mmap_arg_struct arg;
+ size_t len = sizeof(arg);
+ extern struct intercept_system intercept;
+
+ if (intercept.io(fd, pid, INTERCEPT_READ, addr,
+ (void *)&arg, len) == -1)
+ return (-1);
+
+ trans->trans_addr = (void *)arg.prot;
+
+ return (0);
+}
+
static int
print_memprot(char *buf, size_t buflen, struct intercept_translate *tl)
{
@@ -653,6 +685,11 @@ struct intercept_translate ic_memprot = {
NULL, print_memprot,
};
+struct intercept_translate ic_linux_memprot = {
+ "prot",
+ get_linux_memprot, print_memprot,
+};
+
struct intercept_translate ic_fileflags = {
"flags",
NULL, print_fileflags,
diff --git a/bin/systrace/systrace.1 b/bin/systrace/systrace.1
index 20830691e74..c2b7fe530c8 100644
--- a/bin/systrace/systrace.1
+++ b/bin/systrace/systrace.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: systrace.1,v 1.42 2006/05/03 05:16:26 sturm Exp $
+.\" $OpenBSD: systrace.1,v 1.43 2006/07/02 12:34:15 sturm Exp $
.\"
.\" Copyright 2002 Niels Provos <provos@citi.umich.edu>
.\" All rights reserved.
@@ -39,9 +39,10 @@
.Sh SYNOPSIS
.Nm systrace
.Bk -words
-.Op Fl AaCeitUu
+.Op Fl AaCeitUuV
.Op Fl c Ar user:group
.Op Fl d Ar policydir
+.Op Fl E Ar logfile
.Op Fl f Ar file
.Op Fl g Ar gui
.Op Fl p Ar pid
@@ -120,6 +121,9 @@ root privilege.
.It Fl d Ar policydir
Specifies an alternative location for the user's directory from
which policies are loaded and to which changed policies are stored.
+.It Fl E Ar logfile
+Logs all policy violations or specifically logged system calls to
+.Ar logfile .
.It Fl e
Specifies to log to
.Em stderr
@@ -131,6 +135,9 @@ The policies specified in
are added to the policies that
.Nm
knows about.
+The dirname in the policy may contain an "*" to match any possible pathname.
+The wildcard is removed from the policy database the first time that
+a filename matches.
.It Fl g Ar gui
Specifies an alternative location for the notification user interface.
.It Fl i
@@ -158,6 +165,9 @@ and
.Fn access
are translated to
.Fn fsread .
+.It Fl V
+Prints the version number of
+.Nm .
.El
.Ss POLICY
The policy is specified via the following grammar:
diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c
index 442cb900eb2..37a52712f5c 100644
--- a/bin/systrace/systrace.c
+++ b/bin/systrace/systrace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace.c,v 1.53 2006/05/02 19:49:05 sturm Exp $ */
+/* $OpenBSD: systrace.c,v 1.54 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -48,6 +48,7 @@
#include <errno.h>
#include <grp.h>
#include <pwd.h>
+#include <event.h>
#include "intercept.h"
#include "systrace.h"
@@ -56,6 +57,8 @@
#define CRADLE_SERVER "cradle_server"
#define CRADLE_UI "cradle_ui"
+#define VERSION "1.6d (OpenBSD)"
+
pid_t trpid;
int trfd;
int connected = 0; /* Connected to GUI */
@@ -66,15 +69,21 @@ 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 */
+int logtofile = 0; /* Log to file instead of syslog */
+FILE *logfile; /* default logfile to send to if enabled */
char cwd[MAXPATHLEN]; /* Current working directory */
char home[MAXPATHLEN]; /* Home directory of user */
-char username[MAXLOGNAME]; /* Username: predicate match and expansion */
+char username[LOGIN_NAME_MAX]; /* Username: predicate match and expansion */
char *guipath = _PATH_XSYSTRACE; /* Path to GUI executable */
char dirpath[MAXPATHLEN];
+static struct event ev_read;
+static struct event ev_timeout;
+
static void child_handler(int);
static void log_msg(int, const char *, ...);
+static void systrace_read(int, short, void *);
+static void systrace_timeout(int, short, void *);
static void usage(void);
void
@@ -164,7 +173,7 @@ trans_cb(int fd, pid_t pid, int policynr,
const char *binname = NULL;
char output[_POSIX2_LINE_MAX];
pid_t ppid;
- int dolog = 0;
+ int done = 0, dolog = 0;
action = ICPOLICY_PERMIT;
@@ -181,48 +190,63 @@ trans_cb(int fd, pid_t pid, int policynr,
ppid = ipid->ppid;
/* Required to set up replacements */
- make_output(output, sizeof(output), binname, pid, ppid, policynr,
- policy->name, policy->nfilters, emulation, name, code,
- tls, repl);
-
- if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
- errx(1, "%s:%d: no filter queue", __func__, __LINE__);
+ do {
+ make_output(output, sizeof(output), binname, pid, ppid,
+ policynr, policy->name, policy->nfilters,
+ emulation, name, code, tls, repl);
- action = filter_evaluate(tls, pflq, ipid);
- if (action != ICPOLICY_ASK)
- goto done;
-
- /* Do aliasing here */
- if (!noalias)
- alias = systrace_find_alias(emulation, name);
- if (alias != NULL) {
- int i;
-
- /* Set up variables for further filter actions */
- tls = &alitls;
- emulation = alias->aemul;
- name = alias->aname;
-
- /* Create an aliased list for filter_evaluate */
- TAILQ_INIT(tls);
- for (i = 0; i < alias->nargs; i++) {
- memcpy(&alitl[i], alias->arguments[i],
- sizeof(struct intercept_translate));
- TAILQ_INSERT_TAIL(tls, &alitl[i], next);
- }
+ /* Fast-path checking */
+ if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
+ goto out;
- if ((pflq = systrace_policyflq(policy,
- alias->aemul, alias->aname)) == NULL)
+ pflq = systrace_policyflq(policy, emulation, name);
+ if (pflq == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
action = filter_evaluate(tls, pflq, ipid);
if (action != ICPOLICY_ASK)
goto done;
- make_output(output, sizeof(output), binname, pid, ppid,
- policynr, policy->name, policy->nfilters,
- alias->aemul, alias->aname, code, tls, NULL);
- }
+ /* Do aliasing here */
+ if (!noalias)
+ alias = systrace_find_alias(emulation, name);
+ if (alias != NULL) {
+ int i;
+
+ /* Set up variables for further filter actions */
+ tls = &alitls;
+ emulation = alias->aemul;
+ name = alias->aname;
+
+ /* Create an aliased list for filter_evaluate */
+ TAILQ_INIT(tls);
+ for (i = 0; i < alias->nargs; i++) {
+ memcpy(&alitl[i], alias->arguments[i],
+ sizeof(struct intercept_translate));
+ TAILQ_INSERT_TAIL(tls, &alitl[i], next);
+ }
+
+ if ((pflq = systrace_policyflq(policy,
+ alias->aemul, alias->aname)) == NULL)
+ errx(1, "%s:%d: no filter queue",
+ __func__, __LINE__);
+
+ action = filter_evaluate(tls, pflq, ipid);
+ if (action != ICPOLICY_ASK)
+ goto done;
+
+ make_output(output, sizeof(output), binname, pid, ppid,
+ policynr, policy->name, policy->nfilters,
+ alias->aemul, alias->aname, code, tls, NULL);
+ }
+
+ /*
+ * At this point, we have to ask the user, but we may check
+ * if the policy has been updated in the meanwhile.
+ */
+ if (systrace_updatepolicy(fd, policy) == -1)
+ done = 1;
+ } while (!done);
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
@@ -268,7 +292,7 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
struct filterq *pflq = NULL;
short action = ICPOLICY_PERMIT;
short future;
- int off, dolog = 0;
+ int off, done = 0, dolog = 0;
size_t len;
if (policynr == -1)
@@ -295,18 +319,27 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
- action = filter_evaluate(NULL, pflq, ipid);
+ do {
+ /* Fast-path checking */
+ if ((action = policy->kerneltable[code]) != ICPOLICY_ASK)
+ goto out;
- if (ipid->uflags & SYSCALL_LOG)
- dolog = 1;
+ action = filter_evaluate(NULL, pflq, ipid);
- if (action != ICPOLICY_ASK)
- goto out;
+ if (action != ICPOLICY_ASK)
+ goto haveresult;
+ /*
+ * At this point, we have to ask the user, but we may check
+ * if the policy has been updated in the meanwhile.
+ */
+ if (systrace_updatepolicy(fd, policy) == -1)
+ done = 1;
+ } while (!done);
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
dolog = 1;
- goto out;
+ goto haveresult;
}
action = filter_ask(fd, NULL, pflq, policynr, emulation, name,
@@ -321,12 +354,15 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
kill(pid, SIGKILL);
return (ICPOLICY_NEVER);
}
- out:
+
+ haveresult:
+ if (ipid->uflags & SYSCALL_LOG)
+ dolog = 1;
if (dolog)
log_msg(LOG_WARNING, "%s user: %s, prog: %s",
action < ICPOLICY_NEVER ? "permit" : "deny",
ipid->username, output);
-
+ out:
return (action);
}
@@ -426,9 +462,9 @@ log_msg(int priority, const char *fmt, ...)
va_start(ap, fmt);
- if (logstderr) {
+ if (logtofile) {
vsnprintf(buf, sizeof(buf), fmt, ap);
- fprintf(stderr, "%s: %s\n", __progname, buf);
+ fprintf(logfile, "%s: %s\n", __progname, buf);
} else
vsyslog(priority, fmt, ap);
@@ -439,8 +475,8 @@ static void
usage(void)
{
fprintf(stderr,
- "Usage: systrace [-AaCeitUu] [-c uid:gid] [-d policydir] [-f file]\n"
- "\t [-g gui] [-p pid] command ...\n");
+ "Usage: systrace [-AaCeitUuV] [-c user:group] [-d policydir] [-E logfile]\n"
+ "\t [-f file] [-g gui] [-p pid] command ...\n");
exit(1);
}
@@ -575,6 +611,36 @@ get_uid_gid(const char *argument, uid_t *uid, gid_t *gid)
return (0);
}
+static void
+systrace_timeout(int fd, short what, void *arg)
+{
+ struct timeval tv;
+
+ /* Reschedule timeout */
+ timerclear(&tv);
+ tv.tv_sec = SYSTRACE_UPDATETIME;
+ evtimer_add(&ev_timeout, &tv);
+
+ systrace_updatepolicies(trfd);
+ if (userpolicy)
+ systrace_dumppolicies(trfd);
+}
+
+/*
+ * Read from the kernel if something happened.
+ */
+
+static void
+systrace_read(int fd, short what, void *arg)
+{
+ intercept_read(fd);
+
+ if (!intercept_existpids()) {
+ event_del(&ev_read);
+ event_del(&ev_timeout);
+ }
+}
+
int
main(int argc, char **argv)
{
@@ -582,16 +648,19 @@ main(int argc, char **argv)
char **args;
char *filename = NULL;
char *policypath = NULL;
- struct timeval tv, tv_wait = {60, 0};
+ struct timeval tv;
pid_t pidattach = 0;
- int usex11 = 1, count;
+ int usex11 = 1;
int background;
int setcredentials = 0;
uid_t cr_uid;
gid_t cr_gid;
- while ((c = getopt(argc, argv, "c:aAeituUCd:g:f:p:")) != -1) {
+ while ((c = getopt(argc, argv, "Vc:aAeE:ituUCd:g:f:p:")) != -1) {
switch (c) {
+ case 'V':
+ fprintf(stderr, "%s V%s\n", argv[0], VERSION);
+ exit(0);
case 'c':
setcredentials = 1;
if (get_uid_gid(optarg, &cr_uid, &cr_gid) == -1)
@@ -606,7 +675,15 @@ main(int argc, char **argv)
policypath = optarg;
break;
case 'e':
- logstderr = 1;
+ logtofile = 1;
+ logfile = stderr;
+ break;
+ case 'E':
+ logtofile = 1;
+ logfile = fopen(optarg, "a");
+ if (logfile == NULL)
+ err(1, "Cannot open \"%s\" for writing",
+ optarg);
break;
case 'A':
if (automatic)
@@ -660,6 +737,10 @@ main(int argc, char **argv)
usage();
}
+ /* Initalize libevent but without kqueue because of systrace fd */
+ setenv("EVENT_NOKQUEUE", "yes", 0);
+ event_init();
+
/* Local initialization */
systrace_initalias();
systrace_initpolicy(filename, policypath);
@@ -708,7 +789,10 @@ main(int argc, char **argv)
if (signal(SIGCHLD, child_handler) == SIG_ERR)
err(1, "signal");
- /* Start the policy gui or cradle if necessary */
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ err(1, "signal");
+
+ /* Start the policy GUI or cradle if necessary */
if (usex11 && (!automatic && !allow)) {
if (cradle)
cradle_setup(guipath);
@@ -717,34 +801,22 @@ main(int argc, char **argv)
}
- /* Loop on requests */
- count = 0;
- while (intercept_read(trfd) != -1) {
- if (!intercept_existpids())
- break;
- if (userpolicy) {
- /* Periodically save modified policies */
- if (count == 0) {
- /* Set new wait time */
- gettimeofday(&tv, NULL);
- timeradd(&tv, &tv_wait, &tv);
- } else if (count > 10) {
- struct timeval now;
- gettimeofday(&now, NULL);
-
- count = 0;
- if (timercmp(&now, &tv, >)) {
- /* Dump policy and cause new time */
- systrace_dumppolicy();
- continue;
- }
- }
- count++;
- }
+ /* Register read events */
+ event_set(&ev_read, trfd, EV_READ|EV_PERSIST, systrace_read, NULL);
+ event_add(&ev_read, NULL);
+
+ if (userpolicy || automatic) {
+ evtimer_set(&ev_timeout, systrace_timeout, &ev_timeout);
+ timerclear(&tv);
+ tv.tv_sec = SYSTRACE_UPDATETIME;
+ evtimer_add(&ev_timeout, &tv);
}
+ /* Wait for events */
+ event_dispatch();
+
if (userpolicy)
- systrace_dumppolicy();
+ systrace_dumppolicies(trfd);
close(trfd);
diff --git a/bin/systrace/systrace.h b/bin/systrace/systrace.h
index ef148e91e85..2f9b9d75da0 100644
--- a/bin/systrace/systrace.h
+++ b/bin/systrace/systrace.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace.h,v 1.26 2006/03/12 20:56:10 sturm Exp $ */
+/* $OpenBSD: systrace.h,v 1.27 2006/07/02 12:34:15 sturm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -98,14 +98,17 @@ struct policy {
const char *name;
char emulation[16];
+ struct timespec ts_last; /* last time we read the file */
+
SPLAY_HEAD(syscalltree, policy_syscall) pflqs;
- int policynr;
+ int policynr; /* in-kernel policy number */
+ short kerneltable[INTERCEPT_MAXSYSCALLNR];
int flags;
struct filterq filters;
- int nfilters;
- struct filterq prefilters;
+ int nfilters; /* nr of installed policy statements */
+ struct filterq prefilters; /* filters we need to install*/
};
struct template {
@@ -131,6 +134,8 @@ TAILQ_HEAD(tmplqueue, template);
#define SYSCALL_LOG 0x04 /* Log this system call */
#define PROCESS_PROMPT 0x08 /* Prompt but nothing else */
+#define SYSTRACE_UPDATETIME 30 /* update policies every 30 seconds */
+
void systrace_parameters(void);
int systrace_initpolicy(char *, char *);
void systrace_setupdir(char *);
@@ -138,19 +143,24 @@ struct template *systrace_readtemplate(char *, struct policy *,
struct template *);
void systrace_initcb(void);
struct policy *systrace_newpolicy(const char *, const char *);
+void systrace_cleanpolicy(struct policy *);
void systrace_freepolicy(struct policy *);
int systrace_newpolicynr(int, struct policy *);
int systrace_modifypolicy(int, int, const char *, short);
struct policy *systrace_findpolicy(const char *);
+struct policy *systrace_findpolicy_wildcard(const char *);
struct policy *systrace_findpolnr(int);
-int systrace_dumppolicy(void);
-int systrace_readpolicy(char *);
+int systrace_dumppolicies(int);
+int systrace_updatepolicies(int);
+struct policy *systrace_readpolicy(const char *);
int systrace_addpolicy(const char *);
+int systrace_updatepolicy(int fd, struct policy *policy);
struct filterq *systrace_policyflq(struct policy *, const char *, const char *);
+char *systrace_getpolicyname(const char *);
int systrace_error_translate(char *);
-#define SYSTRACE_MAXALIAS 5
+#define SYSTRACE_MAXALIAS 10
struct systrace_alias {
SPLAY_ENTRY(systrace_alias) node;
@@ -233,6 +243,7 @@ extern struct intercept_translate ic_pidname;
extern struct intercept_translate ic_signame;
extern struct intercept_translate ic_fcntlcmd;
extern struct intercept_translate ic_memprot;
+extern struct intercept_translate ic_linux_memprot;
extern struct intercept_translate ic_fileflags;
extern struct intercept_translate ic_linux_oflags;