[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    systrace testers wanted
From:       Nikolay Sturm <sturm () erisiandiscord ! de>
Date:       2006-06-25 9:37:43
Message-ID: 20060625093743.GB28225 () twilight ! erisiandiscord ! de
[Download RAW message or body]

Hi,

the following diff updates systrace to the latest release. Please test
it and send me any feedback you have.

Features:
- new support for wildcarded policies
- better support for linux binaries
- optimisations

thanks,

Nikolay

Index: Makefile
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/Makefile,v
retrieving revision 1.13
diff -u -r1.13 Makefile
--- Makefile	9 Jul 2004 21:53:55 -0000	1.13
+++ Makefile	30 May 2006 21:21:47 -0000
@@ -9,7 +9,7 @@
 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
Index: cradle.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/cradle.c,v
retrieving revision 1.3
diff -u -r1.3 cradle.c
--- cradle.c	26 Apr 2006 20:19:25 -0000	1.3
+++ cradle.c	1 Jun 2006 16:23:53 -0000
@@ -61,11 +61,11 @@
 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;
Index: filter.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/filter.c,v
retrieving revision 1.32
diff -u -r1.32 filter.c
--- filter.c	2 May 2006 19:49:05 -0000	1.32
+++ filter.c	29 May 2006 19:24:46 -0000
@@ -397,6 +397,10 @@
 {
 	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 @@
 	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 @@
 
 	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) {
Index: intercept.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/intercept.c,v
retrieving revision 1.51
diff -u -r1.51 intercept.c
--- intercept.c	26 Apr 2006 20:19:25 -0000	1.51
+++ intercept.c	1 Jun 2006 18:56:32 -0000
@@ -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>
@@ -549,6 +550,9 @@
 	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 @@
 		havecwd = 1;
 	}
 
-	/* Need concatenated path for simplifypath */
 	if (havecwd && name[0] != '/') {
 		if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd))
 			return (NULL);
@@ -658,8 +661,7 @@
 
 		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 @@
 		    icpid->name, intercept_newimagecbarg);
 }
 
-
 int
 intercept_newpolicy(int fd)
 {
@@ -885,6 +886,12 @@
 }
 
 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 @@
 }
 
 /*
+ * 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;
 
Index: intercept.h
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/intercept.h,v
retrieving revision 1.23
diff -u -r1.23 intercept.h
--- intercept.h	10 Jun 2006 07:19:13 -0000	1.23
+++ intercept.h	18 Jun 2006 10:11:47 -0000
@@ -101,7 +101,7 @@
 	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 elevate *elevate;	/* privilege elevation request */
 };
 
+#define INTERCEPT_MAXSYSCALLNR		512
 #define INTERCEPT_MAXSYSCALLARGS	10
 
 struct intercept_translate {
@@ -125,6 +126,7 @@
 	size_t trans_size;
 	char *trans_print;
 	u_int trans_flags;
+	void *user;
 	TAILQ_ENTRY(intercept_translate) next;
 };
 
@@ -148,6 +150,7 @@
 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 @@
     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_ */
Index: linux-translate.c
===================================================================
RCS file: linux-translate.c
diff -N linux-translate.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-translate.c	1 Jun 2006 21:56:17 -0000
@@ -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,
+};
Index: linux-translate.h
===================================================================
RCS file: linux-translate.h
diff -N linux-translate.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-translate.h	30 May 2006 21:24:07 -0000
@@ -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 */
Index: linux_socketcall.h
===================================================================
RCS file: linux_socketcall.h
diff -N linux_socketcall.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux_socketcall.h	1 Jun 2006 21:55:57 -0000
@@ -0,0 +1,196 @@
+/*	$OpenBSD: linux_socketcall.h,v 1.2 1996/04/17 05:24:03 mickey 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 */
Index: openbsd-syscalls.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/openbsd-syscalls.c,v
retrieving revision 1.30
diff -u -r1.30 openbsd-syscalls.c
--- openbsd-syscalls.c	2 May 2006 19:49:05 -0000	1.30
+++ openbsd-syscalls.c	29 May 2006 20:34:24 -0000
@@ -458,6 +458,8 @@
 	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];
 	}
Index: policy.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/policy.c,v
retrieving revision 1.30
diff -u -r1.30 policy.c
--- policy.c	18 Mar 2006 19:03:23 -0000	1.30
+++ policy.c	1 Jun 2006 17:55:06 -0000
@@ -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 @@
 	}
 
 	if (file != NULL)
-		return (systrace_readpolicy(file));
+		return (systrace_readpolicy(file) != NULL ? 0 : -1);
 
 	return (0);
 }
@@ -160,6 +161,34 @@
 }
 
 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 @@
 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 @@
 	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 @@
 
 		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 @@
 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 @@
 	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 @@
 	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 @@
 	}
 
 	/* 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 @@
 
  error:
 	errx(1, "%s: template name too long", __func__);
+
+	/* NOTREACHED */
 }
 
 struct template *
@@ -492,7 +560,9 @@
 	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 @@
 	} 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 @@
 	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 @@
 	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 @@
 			continue;
 
 		if (!strncasecmp(p, "Policy: ", 8)) {
+			struct timeval now;
+
 			p += 8;
 			name = strsep(&p, ",");
 			if (p == NULL)
@@ -652,6 +731,10 @@
 			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 @@
 
  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 @@
 	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 @@
 		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;
 
Index: register.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/register.c,v
retrieving revision 1.20
diff -u -r1.20 register.c
--- register.c	10 Jun 2006 07:19:13 -0000	1.20
+++ register.c	18 Jun 2006 10:11:47 -0000
@@ -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__)
@@ -235,6 +236,23 @@
 	X(intercept_register_sccb("linux", "chmod", trans_cb, NULL));
 	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));
Index: systrace-translate.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/systrace-translate.c,v
retrieving revision 1.20
diff -u -r1.20 systrace-translate.c
--- systrace-translate.c	2 May 2006 19:49:05 -0000	1.20
+++ systrace-translate.c	30 May 2006 18:35:11 -0000
@@ -193,15 +193,15 @@
 	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 @@
 	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 @@
 	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)
 {
@@ -651,6 +683,11 @@
 struct intercept_translate ic_memprot = {
 	"prot",
 	NULL, print_memprot,
+};
+
+struct intercept_translate ic_linux_memprot = {
+	"prot",
+	get_linux_memprot, print_memprot,
 };
 
 struct intercept_translate ic_fileflags = {
Index: systrace.1
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/systrace.1,v
retrieving revision 1.42
diff -u -r1.42 systrace.1
--- systrace.1	3 May 2006 05:16:26 -0000	1.42
+++ systrace.1	30 May 2006 19:26:33 -0000
@@ -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 @@
 .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 @@
 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 @@
 .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:
Index: systrace.c
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/systrace.c,v
retrieving revision 1.53
diff -u -r1.53 systrace.c
--- systrace.c	2 May 2006 19:49:05 -0000	1.53
+++ systrace.c	1 Jun 2006 20:32:50 -0000
@@ -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 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 
 	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);
 
@@ -575,6 +611,36 @@
 	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 @@
 	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 @@
 			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 @@
 		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 @@
 	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 @@
 
 	}
 
-	/* 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);
 
Index: systrace.h
===================================================================
RCS file: /a/devel/cvs/src/bin/systrace/systrace.h,v
retrieving revision 1.26
diff -u -r1.26 systrace.h
--- systrace.h	12 Mar 2006 20:56:10 -0000	1.26
+++ systrace.h	30 May 2006 22:04:10 -0000
@@ -98,14 +98,17 @@
 	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 @@
 #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 *);
 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_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;

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic