[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