Add userland portion of systrace.

This commit is contained in:
christos 2002-06-17 16:29:07 +00:00
parent 581a55332b
commit 5039a9e5ee
21 changed files with 6074 additions and 2 deletions

View File

@ -1,8 +1,8 @@
# $NetBSD: Makefile,v 1.18 1999/11/23 05:28:15 mrg Exp $
# $NetBSD: Makefile,v 1.19 2002/06/17 16:29:07 christos Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= cat chio chmod cp csh date dd df domainname echo ed expr hostname \
kill ksh ln ls mkdir mt mv pax ps pwd rcp rcmd rm rmdir sh \
sleep stty sync test
sleep stty sync systrace test
.include <bsd.subdir.mk>

18
bin/systrace/Makefile Normal file
View File

@ -0,0 +1,18 @@
# $NetBSD: Makefile,v 1.1 2002/06/17 16:29:08 christos Exp $
# $OpenBSD: Makefile,v 1.4 2002/06/05 17:34:56 mickey Exp $
PROG= systrace
CFLAGS+= -I. -I/sys
SRCS= filter.c intercept-translate.c intercept.c \
netbsd-syscalls.c util.c \
policy.c systrace-errno.h systrace-error.c \
systrace-translate.c systrace.c \
parse.y lex.l
CLEANFILES+= parse.c lex.c y.tab.h
YHEADER=yes
LDADD+= -ll -ly
DPADD+= ${LIBL} ${LIBY}
.include <bsd.prog.mk>
.depend: parse.c lex.c

577
bin/systrace/filter.c Normal file
View File

@ -0,0 +1,577 @@
/* $NetBSD: filter.c,v 1.1 2002/06/17 16:29:08 christos Exp $ */
/* $OpenBSD: filter.c,v 1.11 2002/06/11 05:30:28 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: filter.c,v 1.1 2002/06/17 16:29:08 christos Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/tree.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <err.h>
#include "intercept.h"
#include "systrace.h"
#include "filter.h"
#include "util.h"
extern int allow;
extern int connected;
extern char cwd[];
static void logic_free(struct logic *);
static int filter_match(struct intercept_tlq *, struct logic *);
static void filter_review(struct filterq *);
static void filter_policyrecord(struct policy *, struct filter *, const char *,
const char *, char *);
static void filter_replace(char *, size_t, char *, char *);
static int
filter_match(struct intercept_tlq *tls, struct logic *logic)
{
struct intercept_translate *tl;
int off = 0;
switch (logic->op) {
case LOGIC_NOT:
return (!filter_match(tls, logic->left));
case LOGIC_OR:
if (filter_match(tls, logic->left))
return (1);
return (filter_match(tls, logic->right));
case LOGIC_AND:
if (!filter_match(tls, logic->left))
return (0);
return (filter_match(tls, logic->right));
default:
break;
}
/* Now we just have a logic single */
if (logic->type == NULL)
goto match;
TAILQ_FOREACH(tl, tls, next) {
if (!tl->trans_valid)
return (0);
if (strcasecmp(tl->name, logic->type))
continue;
if (logic->typeoff == -1 || logic->typeoff == off)
break;
off++;
}
if (tl == NULL)
return (0);
match:
return (logic->filter_match(tl, logic));
}
short
filter_evaluate(struct intercept_tlq *tls, struct filterq *fls, int *pflags)
{
struct filter *filter, *last = NULL;
short action, laction = 0;
TAILQ_FOREACH(filter, fls, next) {
action = filter->match_action;
if (filter_match(tls, filter->logicroot)) {
/* Profile feedback optimization */
filter->match_count++;
if (last != NULL && last->match_action == action &&
filter->match_count > last->match_count) {
TAILQ_REMOVE(fls, last, next);
TAILQ_INSERT_AFTER(fls, filter, last, next);
}
if (action == ICPOLICY_NEVER)
action = filter->match_error;
*pflags = filter->match_flags;
return (action);
}
/* Keep track of last processed filtered in a group */
last = filter;
laction = action;
}
return (ICPOLICY_ASK);
}
static void
logic_free(struct logic *logic)
{
if (logic->left)
logic_free(logic->left);
if (logic->right)
logic_free(logic->right);
if (logic->type)
free(logic->type);
if (logic->filterdata)
free(logic->filterdata);
free(logic);
}
void
filter_free(struct filter *filter)
{
if (filter->logicroot)
logic_free(filter->logicroot);
if (filter->rule)
free(filter->rule);
free(filter);
}
static void
filter_review(struct filterq *fls)
{
struct filter *filter;
int i = 0;
printf("Filter review:\n");
TAILQ_FOREACH(filter, fls, next) {
i++;
printf("%d. %s\n", i, filter->rule);
}
}
static void
filter_policyrecord(struct policy *policy, struct filter *filter,
const char *emulation, const char *name, char *rule)
{
/* Record the filter in the policy */
if (filter == NULL) {
filter = calloc(1, sizeof(struct filter));
if (filter == NULL)
err(1, "%s:%d: calloc", __func__, __LINE__);
if ((filter->rule = strdup(rule)) == NULL)
err(1, "%s:%d: strdup", __func__, __LINE__);
}
strlcpy(filter->name, name, sizeof(filter->name));
strlcpy(filter->emulation, emulation, sizeof(filter->emulation));
TAILQ_INSERT_TAIL(&policy->filters, filter, policy_next);
policy->nfilters++;
policy->flags |= POLICY_CHANGED;
}
int
filter_parse(char *line, struct filter **pfilter)
{
char *rule;
if (parse_filter(line, pfilter) == -1)
return (-1);
if ((rule = strdup(line)) == NULL)
err(1, "%s:%d: strdup", __func__, __LINE__);
(*pfilter)->rule = rule;
return (0);
}
/* Translate a simple action like "permit" or "deny[einval]" to numbers */
int
filter_parse_simple(char *rule, short *paction, short *pfuture)
{
char buf[1024];
int isfuture = 1;
char *line, *p;
strlcpy(buf, rule, sizeof(buf));
line = buf;
if (!strcmp("permit", line)) {
*paction = *pfuture = ICPOLICY_PERMIT;
return (0);
} else if (!strcmp("permit-now", line)) {
*paction = ICPOLICY_PERMIT;
return (0);
} else if (strncmp("deny", line, 4))
return (-1);
line +=4 ;
if (!strncmp("-now", line, 4)) {
line += 4;
isfuture = 0;
}
*paction = ICPOLICY_NEVER;
switch (line[0]) {
case '\0':
break;
case '[':
line++;
p = strsep(&line, "]");
if (line == NULL || *line != '\0')
return (-1);
*paction = systrace_error_translate(p);
if (*paction == -1)
return (-1);
break;
default:
return (-1);
}
if (isfuture)
*pfuture = *paction;
return (NULL);
}
int
filter_prepolicy(int fd, struct policy *policy)
{
int res;
struct filter *filter, *parsed;
struct filterq *fls;
short action, future;
/* Commit all matching pre-filters */
for (filter = TAILQ_FIRST(&policy->prefilters);
filter; filter = TAILQ_FIRST(&policy->prefilters)) {
future = ICPOLICY_ASK;
TAILQ_REMOVE(&policy->prefilters, filter, policy_next);
res = 0;
parsed = NULL;
/* Special rules that are not real filters */
if (filter_parse_simple(filter->rule, &action, &future) == -1)
res = filter_parse(filter->rule, &parsed);
if (res == -1)
errx(1, "%s:%d: can not parse \"%s\"",
__func__, __LINE__, filter->rule);
if (future == ICPOLICY_ASK) {
fls = systrace_policyflq(policy, policy->emulation,
filter->name);
TAILQ_INSERT_TAIL(fls, parsed, next);
} else {
res = systrace_modifypolicy(fd, policy->policynr,
filter->name, future);
if (res == -1)
errx(1, "%s:%d: modify policy for \"%s\"",
__func__, __LINE__, filter->rule);
}
filter_policyrecord(policy, parsed, policy->emulation,
filter->name, filter->rule);
filter_free(filter);
}
/* Existing policy applied undo changed flag */
policy->flags &= ~POLICY_CHANGED;
return (0);
}
short
filter_ask(struct intercept_tlq *tls, struct filterq *fls,
int policynr, const char *emulation, const char *name,
char *output, short *pfuture, int *pflags)
{
char line[2*MAXPATHLEN], *p;
struct filter *filter;
struct policy *policy;
short action;
int first = 1;
*pfuture = ICPOLICY_ASK;
*pflags = 0;
if ((policy = systrace_findpolnr(policynr)) == NULL)
errx(1, "%s:%d: no policy %d\n", __func__, __LINE__,
policynr);
if (!allow)
printf("%s\n", output);
else {
/* Automatically allow */
if (tls != NULL) {
struct intercept_translate *tl;
char compose[2*MAXPATHLEN], *l;
char *lst = NULL;
int set = 0;
/* Explicitly match every component */
line[0] = '\0';
TAILQ_FOREACH(tl, tls, next) {
if (!tl->trans_valid)
break;
l = intercept_translate_print(tl);
if (l == NULL)
continue;
snprintf(compose, sizeof(compose),
"%s%s eq \"%s\"",
tl->name,
lst && !strcmp(tl->name, lst) ? "[1]" : "",
l);
lst = tl->name;
if (set)
strlcat(line, " and ",
sizeof(line));
else
set = 1;
strlcat(line, compose, sizeof(line));
}
if (!set)
strlcpy(line, "true", sizeof(line));
strlcat(line, " then permit", sizeof(line));
} else
strlcpy(line, "permit", sizeof(line));
}
while (1) {
filter = NULL;
if (!allow) {
/* Ask for a policy */
if (!connected)
printf("Answer: ");
else {
/* Do not prompt the first time */
if (!first) {
printf("WRONG\n");
}
}
fgets(line, sizeof(line), stdin);
p = line;
strsep(&p, "\n");
} else if (!first) {
/* Error with filter */
errx(1, "Filter generation error: %s", line);
}
first = 0;
/* Simple keywords */
if (!strcasecmp(line, "detach")) {
if (policy->nfilters) {
policy->flags |= POLICY_UNSUPERVISED;
action = ICPOLICY_NEVER;
} else {
policy->flags |= POLICY_DETACHED;
policy->flags |= POLICY_CHANGED;
action = ICPOLICY_PERMIT;
}
goto out;
} else if (!strcasecmp(line, "kill")) {
action = ICPOLICY_KILL;
goto out;
} else if (!strcasecmp(line, "review") && fls != NULL) {
filter_review(fls);
continue;
}
if (filter_parse_simple(line, &action, pfuture) != -1) {
if (*pfuture == ICPOLICY_ASK)
goto out;
break;
}
if (fls == NULL) {
printf("Syntax error.\n");
continue;
}
if (filter_parse(line, &filter) == -1)
continue;
TAILQ_INSERT_TAIL(fls, filter, next);
action = filter_evaluate(tls, fls, pflags);
if (action == ICPOLICY_ASK) {
TAILQ_REMOVE(fls, filter, next);
printf("Filter unmatched. Freeing it\n");
filter_free(filter);
continue;
}
break;
}
filter_policyrecord(policy, filter, emulation, name, line);
out:
if (connected)
printf("OKAY\n");
return (action);
}
static void
filter_replace(char *buf, size_t buflen, char *match, char *repl)
{
while (strrpl(buf, buflen, match, repl) != NULL)
;
}
char *
filter_expand(char *data)
{
static char expand[2*MAXPATHLEN];
char *what;
if (data != NULL)
strlcpy(expand, data, sizeof(expand));
what = getenv("HOME");
if (what != NULL)
filter_replace(expand, sizeof(expand), "$HOME", what);
what = getenv("USER");
if (what != NULL)
filter_replace(expand, sizeof(expand), "$USER", what);
filter_replace(expand, sizeof(expand), "$CWD", cwd);
return (expand);
}
int
filter_fnmatch(struct intercept_translate *tl, struct logic *logic)
{
int res;
char *line;
if (tl->trans_size == 0)
return (0);
if ((line = intercept_translate_print(tl)) == NULL)
return (0);
#ifdef __NetBSD__
res = fnmatch(logic->filterdata, line, FNM_PATHNAME);
#else
res = fnmatch(logic->filterdata, line, FNM_PATHNAME | FNM_LEADING_DIR);
#endif
return (res == 0);
}
int
filter_substrmatch(struct intercept_translate *tl, struct logic *logic)
{
char *line;
if ((line = intercept_translate_print(tl)) == NULL)
return (0);
return (strstr(line, logic->filterdata) != NULL);
}
int
filter_negsubstrmatch(struct intercept_translate *tl, struct logic *logic)
{
char *line;
if ((line = intercept_translate_print(tl)) == NULL)
return (0);
return (strstr(line, logic->filterdata) == NULL);
}
int
filter_stringmatch(struct intercept_translate *tl, struct logic *logic)
{
char *line;
if ((line = intercept_translate_print(tl)) == NULL)
return (0);
return (!strcasecmp(line, logic->filterdata));
}
int
filter_negstringmatch(struct intercept_translate *tl, struct logic *logic)
{
char *line;
if ((line = intercept_translate_print(tl)) == NULL)
return (1);
return (strcasecmp(line, logic->filterdata) != 0);
}
int
filter_inpath(struct intercept_translate *tl, struct logic *logic)
{
char *line, c;
int len;
if ((line = intercept_translate_print(tl)) == NULL)
return (0);
len = strlen(line);
if (len == 0 || len > strlen(logic->filterdata))
return (0);
/* Root is always in path */
if (len == 1)
return (line[0] == '/');
/* Complete filename needs to fit */
if (strncmp(line, logic->filterdata, len))
return (0);
/* Termination has to be \0 or / */
c = ((char *)logic->filterdata)[len];
if (c != '/' && c != '\0')
return (0);
return (1);
}
int
filter_true(struct intercept_translate *tl, struct logic *logic)
{
return (1);
}

40
bin/systrace/filter.h Normal file
View File

@ -0,0 +1,40 @@
/* $NetBSD: filter.h,v 1.1 2002/06/17 16:29:08 christos Exp $ */
/* $OpenBSD: parse.y,v 1.4 2002/06/05 17:22:38 mickey Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
int filter_fnmatch(struct intercept_translate *, struct logic *);
int filter_stringmatch(struct intercept_translate *, struct logic *);
int filter_negstringmatch(struct intercept_translate *, struct logic *);
int filter_substrmatch(struct intercept_translate *, struct logic *);
int filter_negsubstrmatch(struct intercept_translate *, struct logic *);
int filter_inpath(struct intercept_translate *, struct logic *);
int filter_true(struct intercept_translate *, struct logic *);

View File

@ -0,0 +1,285 @@
/* $NetBSD: intercept-translate.c,v 1.1 2002/06/17 16:29:08 christos Exp $ */
/* $OpenBSD: intercept-translate.c,v 1.2 2002/06/04 19:15:54 deraadt Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: intercept-translate.c,v 1.1 2002/06/17 16:29:08 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/tree.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <err.h>
#include "intercept.h"
char *error_msg = "error";
static void ic_trans_free(struct intercept_translate *);
static int ic_print_filename(char *, size_t, struct intercept_translate *);
static int ic_get_filename(struct intercept_translate *, int, pid_t, void *);
static int ic_get_string(struct intercept_translate *, int, pid_t, void *);
static int ic_get_linkname(struct intercept_translate *, int, pid_t, void *);
static int ic_get_sockaddr(struct intercept_translate *, int, pid_t, void *);
static int ic_print_sockaddr(char *, size_t, struct intercept_translate *);
static void
ic_trans_free(struct intercept_translate *trans)
{
if (trans->trans_data)
free(trans->trans_data);
if (trans->trans_print)
free(trans->trans_print);
trans->trans_valid = 0;
trans->trans_data = NULL;
trans->trans_print = NULL;
trans->trans_size = 0;
trans->trans_addr = NULL;
}
extern struct intercept_system intercept;
/* Takes a translation structure and retrieves the right data */
int
intercept_translate(struct intercept_translate *trans,
int fd, pid_t pid, int off, void *args, int argsize)
{
void *addr, *addr2;
ic_trans_free(trans);
if (intercept.getarg(off, args, argsize, &addr) == -1)
return (-1);
if (trans->off2) {
if (intercept.getarg(trans->off + trans->off2,
args, argsize, &addr2) == -1)
return (-1);
trans->trans_addr2 = addr2;
}
trans->trans_valid = 1;
trans->trans_addr = addr;
if (trans->translate == NULL)
return (0);
if ((*trans->translate)(trans, fd, pid, addr) == -1) {
trans->trans_valid = 0;
return (-1);
}
return (0);
}
char *
intercept_translate_print(struct intercept_translate *trans)
{
char line[1024];
if (trans->trans_print == NULL) {
if (trans->print(line, sizeof(line), trans) == -1)
return (error_msg);
if ((trans->trans_print = strdup(line)) == NULL)
return (error_msg);
}
return (trans->trans_print);
}
static int
ic_print_filename(char *buf, size_t buflen, struct intercept_translate *tl)
{
strlcpy(buf, tl->trans_data, buflen);
return (0);
}
static int
ic_get_filename(struct intercept_translate *trans, int fd, pid_t pid,
void *addr)
{
char buf[MAXPATHLEN];
char *path, *name;
int len;
name = intercept_filename(fd, pid, addr);
if (name == NULL)
return (-1);
/* If realpath fails then the filename does not exist */
path = buf;
if (realpath(name, path) == NULL)
path = "<non-existant filename>";
len = strlen(path) + 1;
trans->trans_data = malloc(len);
if (trans->trans_data == NULL)
return (-1);
trans->trans_size = len;
memcpy(trans->trans_data, path, len);
return (0);
}
static int
ic_get_string(struct intercept_translate *trans, int fd, pid_t pid, void *addr)
{
char *name;
int len;
name = intercept_get_string(fd, pid, addr);
if (name == NULL)
return (-1);
len = strlen(name) + 1;
trans->trans_data = malloc(len);
if (trans->trans_data == NULL)
return (-1);
trans->trans_size = len;
memcpy(trans->trans_data, name, len);
return (0);
}
static int
ic_get_linkname(struct intercept_translate *trans, int fd, pid_t pid,
void *addr)
{
char *name;
int len;
name = intercept_filename(fd, pid, addr);
if (name == NULL)
return (-1);
len = strlen(name) + 1;
trans->trans_data = malloc(len);
if (trans->trans_data == NULL)
return (-1);
trans->trans_size = len;
memcpy(trans->trans_data, name, len);
return (0);
}
static int
ic_get_sockaddr(struct intercept_translate *trans, int fd, pid_t pid,
void *addr)
{
struct sockaddr_storage sa;
socklen_t len;
len = (socklen_t )trans->trans_addr2;
if (len == 0 || len > sizeof(struct sockaddr_storage))
return (-1);
if (intercept.io(fd, pid, INTERCEPT_READ, addr,
(void *)&sa, len) == -1)
return (-1);
trans->trans_data = malloc(len);
if (trans->trans_data == NULL)
return (-1);
trans->trans_size = len;
memcpy(trans->trans_data, &sa, len);
return (0);
}
static int
ic_print_sockaddr(char *buf, size_t buflen, struct intercept_translate *tl)
{
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
struct sockaddr *sa = tl->trans_data;
socklen_t len = (socklen_t)tl->trans_size;
buf[0] = '\0';
switch (sa->sa_family) {
case PF_LOCAL:
if (sa->sa_len < len)
len = sa->sa_len;
if (buflen < len + 1)
len = buflen - 1;
memcpy(buf, sa->sa_data, len);
buf[len] = '\0';
return (0);
case PF_INET:
case PF_INET6:
break;
default:
snprintf(buf, buflen, "family(%d)", sa->sa_family);
return (0);
}
sa->sa_len = 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);
}
struct intercept_translate ic_translate_string = {
"string",
ic_get_string, ic_print_filename,
};
struct intercept_translate ic_translate_filename = {
"filename",
ic_get_filename, ic_print_filename,
};
struct intercept_translate ic_translate_linkname = {
"filename",
ic_get_linkname, ic_print_filename,
};
struct intercept_translate ic_translate_connect = {
"sockaddr",
ic_get_sockaddr, ic_print_sockaddr,
/* XXX - Special handling */ 1,
};

566
bin/systrace/intercept.c Normal file
View File

@ -0,0 +1,566 @@
/* $NetBSD: intercept.c,v 1.1 2002/06/17 16:29:08 christos Exp $ */
/* $OpenBSD: intercept.c,v 1.5 2002/06/10 19:16:26 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: intercept.c,v 1.1 2002/06/17 16:29:08 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/tree.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#define _KERNEL
#include <errno.h>
#undef _KERNEL
#include <err.h>
#include "util.h"
#include "intercept.h"
struct intercept_syscall {
SPLAY_ENTRY(intercept_syscall) node;
char name[64];
char emulation[16];
short (*cb)(int, pid_t, int, const char *, int, const char *, void *,
int, struct intercept_tlq *, void *);
void *cb_arg;
struct intercept_tlq tls;
};
static int sccompare(struct intercept_syscall *, struct intercept_syscall *);
static int pidcompare(struct intercept_pid *, struct intercept_pid *);
static struct intercept_syscall *intercept_sccb_find(const char *,
const char *);
static SPLAY_HEAD(pidtree, intercept_pid) pids;
static SPLAY_HEAD(sctree, intercept_syscall) scroot;
/* Generic callback functions */
void (*intercept_newimagecb)(int, pid_t, int, const char *, const char *, void *) = NULL;
void *intercept_newimagecbarg = NULL;
short (*intercept_gencb)(int, pid_t, int, const char *, int, const char *, void *, int, void *) = NULL;
void *intercept_gencbarg = NULL;
static int
sccompare(struct intercept_syscall *a, struct intercept_syscall *b)
{
int diff;
diff = strcmp(a->emulation, b->emulation);
if (diff)
return (diff);
return (strcmp(a->name, b->name));
}
static int
pidcompare(struct intercept_pid *a, struct intercept_pid *b)
{
int diff = a->pid - b->pid;
if (diff == 0)
return (0);
if (diff > 0)
return (1);
return (-1);
}
SPLAY_PROTOTYPE(sctree, intercept_syscall, node, sccompare);
SPLAY_GENERATE(sctree, intercept_syscall, node, sccompare);
SPLAY_PROTOTYPE(pidtree, intercept_pid, next, pidcompare);
SPLAY_GENERATE(pidtree, intercept_pid, next, pidcompare);
extern struct intercept_system intercept;
int
intercept_init(void)
{
SPLAY_INIT(&pids);
SPLAY_INIT(&scroot);
intercept_newimagecb = NULL;
intercept_gencb = NULL;
return (intercept.init());
}
static struct intercept_syscall *
intercept_sccb_find(const char *emulation, const char *name)
{
struct intercept_syscall tmp;
strlcpy(tmp.name, name, sizeof(tmp.name));
strlcpy(tmp.emulation, emulation, sizeof(tmp.emulation));
return (SPLAY_FIND(sctree, &scroot, &tmp));
}
int
intercept_register_translation(char *emulation, char *name, int offset,
struct intercept_translate *tl)
{
struct intercept_syscall *tmp;
struct intercept_translate *tlnew;
if (offset >= INTERCEPT_MAXSYSCALLARGS)
return (-1);
tmp = intercept_sccb_find(emulation, name);
if (tmp == NULL)
return (-1);
tlnew = malloc(sizeof(struct intercept_translate));
if (tlnew == NULL)
return (-1);
memcpy(tlnew, tl, sizeof(struct intercept_translate));
tlnew->off = offset;
TAILQ_INSERT_TAIL(&tmp->tls, tlnew, next);
return (0);
}
void *
intercept_sccb_cbarg(char *emulation, char *name)
{
struct intercept_syscall *tmp;
if ((tmp = intercept_sccb_find(emulation, name)) == NULL)
return (NULL);
return (tmp->cb_arg);
}
int
intercept_register_sccb(const char *emulation, const char *name,
short (*cb)(int, pid_t, int, const char *, int, const char *, void *, int,
struct intercept_tlq *, void *),
void *cbarg)
{
struct intercept_syscall *tmp;
if (intercept_sccb_find(emulation, name))
return (-1);
if (intercept.getsyscallnumber(emulation, name) == -1) {
warnx("%s: %d: unknown syscall: %s-%s", __func__, __LINE__,
emulation, name);
return (-1);
}
if ((tmp = calloc(1, sizeof(struct intercept_syscall))) == NULL) {
warn("%s:%d: malloc", __func__, __LINE__);
return (-1);
}
TAILQ_INIT(&tmp->tls);
strlcpy(tmp->name, name, sizeof(tmp->name));
strlcpy(tmp->emulation, emulation, sizeof(tmp->emulation));
tmp->cb = cb;
tmp->cb_arg = cbarg;
SPLAY_INSERT(sctree, &scroot, tmp);
return (0);
}
int
intercept_register_gencb(short (*cb)(int, pid_t, int, const char *, int, const char *, void *, int, void *), void *arg)
{
intercept_gencb = cb;
intercept_gencbarg = arg;
return (0);
}
int
intercept_register_execcb(void (*cb)(int, pid_t, int, const char *, const char *, void *), void *arg)
{
intercept_newimagecb = cb;
intercept_newimagecbarg = arg;
return (0);
}
pid_t
intercept_run(int fd, char *path, char *const argv[])
{
pid_t pid;
pid = fork();
if (pid == -1)
return (-1);
if (pid == 0) {
/* Needs to be closed */
close(fd);
/* Stop myself */
raise(SIGSTOP);
execvp(path, argv);
/* Error */
err(1, "execvp");
}
sleep(1); /* XXX */
return (pid);
}
int
intercept_existpids(void)
{
return (SPLAY_ROOT(&pids) != NULL);
}
void
intercept_freepid(pid_t pidnr)
{
struct intercept_pid *pid, tmp2;
tmp2.pid = pidnr;
pid = SPLAY_FIND(pidtree, &pids, &tmp2);
if (pid == NULL)
return;
intercept.freepid(pid);
SPLAY_REMOVE(pidtree, &pids, pid);
if (pid->name)
free(pid->name);
if (pid->newname)
free(pid->newname);
free(pid);
}
struct intercept_pid *
intercept_getpid(pid_t pid)
{
struct intercept_pid *tmp, tmp2;
tmp2.pid = pid;
tmp = SPLAY_FIND(pidtree, &pids, &tmp2);
if (tmp)
return (tmp);
if ((tmp = malloc(sizeof(struct intercept_pid))) == NULL)
err(1, "%s: malloc", __func__);
memset(tmp, 0, sizeof(struct intercept_pid));
tmp->pid = pid;
SPLAY_INSERT(pidtree, &pids, tmp);
return (tmp);
}
int
intercept_open(void)
{
int fd;
if ((fd = intercept.open()) == -1)
return (-1);
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(O_NONBLOCK)");
return (fd);
}
int
intercept_attach(int fd, pid_t pid)
{
return (intercept.attach(fd, pid));
}
int
intercept_attachpid(int fd, pid_t pid, char *name)
{
struct intercept_pid *icpid;
int res;
res = intercept.attach(fd, pid);
if (res == -1)
return (-1);
if ((icpid = intercept_getpid(pid)) == NULL)
return (-1);
if ((icpid->newname = strdup(name)) == NULL)
err(1, "strdup");
if (intercept.report(fd, pid) == -1)
return (-1);
/* Indicates a running attach */
icpid->execve_code = -1;
return (0);
}
int
intercept_detach(int fd, pid_t pid)
{
int res;
res = intercept.detach(fd, pid);
if (res != -1)
intercept_freepid(pid);
return (res);
}
int
intercept_read(int fd)
{
struct pollfd pollfd;
int n;
pollfd.fd = fd;
pollfd.events = POLLIN;
do {
n = poll(&pollfd, 1, -1);
if (n == -1) {
if (errno != EINTR && errno != EAGAIN)
return (-1);
}
} while (n <= 0);
if (!(pollfd.revents & (POLLIN|POLLRDNORM)))
return (-1);
return (intercept.read(fd));
}
char *
intercept_get_string(int fd, pid_t pid, void *addr)
{
static char name[1024];
int off = 0;
do {
if (intercept.io(fd, pid, INTERCEPT_READ, (char *)addr + off,
&name[off], 4) == -1) {
warn("ioctl");
return (NULL);
}
off += 4;
name[off] = '\0';
if (strlen(name) < off)
break;
} while (off < sizeof(name));
return (name);
}
char *
intercept_filename(int fd, pid_t pid, void *addr)
{
static char cwd[1024];
char *name;
name = intercept_get_string(fd, pid, addr);
if (name == NULL)
err(1, "%s:%d: getstring", __func__, __LINE__);
if (name[0] != '/') {
if (intercept.getcwd(fd, pid, cwd, sizeof(cwd)) == NULL)
err(1, "%s:%d: getcwd", __func__, __LINE__);
strlcat(cwd, "/", sizeof(cwd));
strlcat(cwd, name, sizeof(cwd));
} else
strlcpy(cwd, name, sizeof(cwd));
simplify_path(cwd);
return (cwd);
}
void
intercept_syscall(int fd, pid_t pid, int policynr, const char *name, int code,
const char *emulation, void *args, int argsize)
{
short action, flags = 0;
struct intercept_syscall *sc;
int error = 0;
action = ICPOLICY_PERMIT;
flags = 0;
/* Special handling for the exec call */
if (!strcmp(name, "execve")) {
struct intercept_pid *icpid;
void *addr;
if ((icpid = intercept_getpid(pid)) == NULL)
err(1, "intercept_getpid");
icpid->execve_code = code;
icpid->policynr = policynr;
if (icpid->newname)
free(icpid->newname);
intercept.getarg(0, args, argsize, &addr);
icpid->newname = strdup(intercept_filename(fd, pid, addr));
if (icpid->newname == NULL)
err(1, "%s:%d: strdup", __func__, __LINE__);
/* We need to know the result from this system call */
flags = ICFLAGS_RESULT;
}
sc = intercept_sccb_find(emulation, name);
if (sc != NULL) {
struct intercept_translate *tl;
TAILQ_FOREACH(tl, &sc->tls, next) {
if (intercept_translate(tl, fd, pid, tl->off,
args, argsize) == -1)
break;
}
action = (*sc->cb)(fd, pid, policynr, name, code, emulation,
args, argsize, &sc->tls, sc->cb_arg);
} else if (intercept_gencb != NULL)
action = (*intercept_gencb)(fd, pid, policynr, name, code,
emulation, args, argsize, intercept_gencbarg);
if (action > 0) {
error = action;
action = ICPOLICY_NEVER;
}
/* Resume execution of the process */
intercept.answer(fd, pid, action, error, flags);
}
void
intercept_syscall_result(int fd, pid_t pid, int policynr,
const char *name, int code, char *emulation, void *args, int argsize,
int result, void *rval)
{
struct intercept_pid *icpid;
if (!strcmp("execve", name)) {
#ifdef __NetBSD__
if (result && result != EJUSTRETURN)
#else
if (result)
#endif
goto out;
/* Commit the name of the new image */
icpid = intercept_getpid(pid);
if (icpid->name)
free(icpid->name);
icpid->name = icpid->newname;
icpid->newname = NULL;
if (intercept_newimagecb != NULL)
(*intercept_newimagecb)(fd, pid, policynr, emulation,
icpid->name, intercept_newimagecbarg);
}
out:
/* Resume execution of the process */
intercept.answer(fd, pid, 0, 0, 0);
}
int
intercept_newpolicy(int fd)
{
int policynr;
policynr = intercept.newpolicy(fd);
return (policynr);
}
int
intercept_assignpolicy(int fd, pid_t pid, int policynr)
{
return (intercept.assignpolicy(fd, pid, policynr));
}
int
intercept_modifypolicy(int fd, int policynr, const char *emulation,
const char *name, short policy)
{
int code;
code = intercept.getsyscallnumber(emulation, name);
if (code == -1)
return (-1);
return (intercept.policy(fd, policynr, code, policy));
}
void
intercept_child_info(pid_t opid, pid_t npid)
{
struct intercept_pid *ipid, *inpid, tmp;
/* A child just died on us */
if (npid == -1) {
intercept_freepid(opid);
return;
}
tmp.pid = opid;
ipid = SPLAY_FIND(pidtree, &pids, &tmp);
if (ipid == NULL)
return;
inpid = intercept_getpid(npid);
inpid->policynr = ipid->policynr;
if (ipid->name != NULL)
inpid->name = strdup(ipid->name);
/* XXX - keeps track of emulation */
intercept.clonepid(ipid, inpid);
}

155
bin/systrace/intercept.h Normal file
View File

@ -0,0 +1,155 @@
/* $NetBSD: intercept.h,v 1.1 2002/06/17 16:29:09 christos Exp $ */
/* $OpenBSD: intercept.h,v 1.2 2002/06/10 19:16:26 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _INTERCEPT_H_
#define _INTERCEPT_H_
#include <sys/queue.h>
struct intercept_pid;
struct intercept_system {
char *name;
int (*init)(void);
int (*open)(void);
int (*attach)(int, pid_t);
int (*detach)(int, pid_t);
int (*report)(int, pid_t);
int (*read)(int);
int (*getsyscallnumber)(const char *, const char *);
char *(*getcwd)(int, pid_t, char *, size_t);
int (*io)(int, pid_t, int, void *, u_char *, size_t);
int (*getarg)(int, void *, int, void **);
int (*answer)(int, pid_t, short, int, short);
int (*newpolicy)(int);
int (*assignpolicy)(int, pid_t, int);
int (*policy)(int, int, int, short);
void (*clonepid)(struct intercept_pid *, struct intercept_pid *);
void (*freepid)(struct intercept_pid *);
};
#define INTERCEPT_READ 1
#define INTERCEPT_WRITE 2
#define ICPOLICY_ASK 0
#define ICPOLICY_PERMIT -1
#define ICPOLICY_KILL -2
#define ICPOLICY_NEVER 1
#define ICFLAGS_RESULT 1
struct intercept_pid {
SPLAY_ENTRY(intercept_pid) next;
pid_t pid;
short policynr;
int execve_code;
short execve_policy;
char *name;
char *newname;
void *data;
int uflags; /* Flags that can be used by external application */
};
#define INTERCEPT_MAXSYSCALLARGS 10
struct intercept_translate {
char *name;
int (*translate)(struct intercept_translate *, int, pid_t, void *);
int (*print)(char *, size_t, struct intercept_translate *);
int off2;
int off;
u_char trans_valid;
void *trans_addr;
void *trans_addr2;
void *trans_data;
size_t trans_size;
char *trans_print;
TAILQ_ENTRY(intercept_translate) next;
};
TAILQ_HEAD(intercept_tlq, intercept_translate);
int intercept_init(void);
pid_t intercept_run(int, char *, char * const *);
int intercept_open(void);
int intercept_attach(int, pid_t);
int intercept_attachpid(int, pid_t, char *);
int intercept_detach(int, pid_t);
int intercept_read(int);
int intercept_newpolicy(int);
int intercept_assignpolicy(int, pid_t, int);
int intercept_modifypolicy(int, int, const char *, const char *, short);
int intercept_register_sccb(const char *, const char *,
short (*)(int, pid_t, int, const char *, int, const char *, void *, int,
struct intercept_tlq *, void *),
void *);
void *intercept_sccb_cbarg(char *, char *);
int intercept_register_gencb(short (*)(int, pid_t, int, const char *, int, const char *, void *, int, void *), void *);
int intercept_register_execcb(void (*)(int, pid_t, int, const char *, const char *, void *), void *);
int intercept_register_translation(char *, char *, int,
struct intercept_translate *);
int intercept_translate(struct intercept_translate *, int, pid_t, int, void *, int);
char *intercept_translate_print(struct intercept_translate *);
#define intercept_register_transstring(x,y,z) \
intercept_register_translation(x, y, z, &ic_translate_string)
#define intercept_register_transfn(x,y,z) \
intercept_register_translation(x, y, z, &ic_translate_filename)
#define intercept_register_translink(x,y,z) \
intercept_register_translation(x, y, z, &ic_translate_linkname)
extern struct intercept_translate ic_translate_string;
extern struct intercept_translate ic_translate_filename;
extern struct intercept_translate ic_translate_linkname;
extern struct intercept_translate ic_translate_connect;
void intercept_freepid(pid_t);
struct intercept_pid *intercept_getpid(pid_t);
int intercept_existpids(void);
char *intercept_get_string(int, pid_t, void *);
char *intercept_filename(int, pid_t, void *);
void intercept_syscall(int, pid_t, int, const char *, int, const char *, void *,
int);
void intercept_child_info(pid_t, pid_t);
void intercept_syscall_result(int, pid_t, int, const char *, int, char *,
void *, int, int, void *);
#endif /* _INTERCEPT_H_ */

113
bin/systrace/lex.l Normal file
View File

@ -0,0 +1,113 @@
/* $NetBSD: lex.l,v 1.1 2002/06/17 16:29:09 christos Exp $ */
/* $OpenBSD: lex.l,v 1.6 2002/06/05 17:34:56 mickey Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
%x incl
%{
#include <sys/cdefs.h>
__RCSID("$NetBSD: lex.l,v 1.1 2002/06/17 16:29:09 christos Exp $");
#include <sys/types.h>
#include <sys/tree.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <stdarg.h>
#include <string.h>
#include "intercept.h"
#include "systrace.h"
#ifdef __NetBSD__
#include "parse.h"
#else
#include "y.tab.h"
#endif
int yyerror(const char *fmt, ...);
int yylex(void);
char *mystring;
int myoff;
#define YY_INPUT(buf,result,max_size) \
{ \
int len = strlen(mystring + myoff); \
if (max_size < len) \
len = max_size; \
if (len == 0) \
result = YY_NULL; \
else { \
memcpy(buf, mystring + myoff, len); \
myoff += len; \
result = len; \
} \
}
%}
%%
deny { return DENY; }
permit { return PERMIT; }
and { return AND; }
or { return OR; }
not { return NOT; }
match { return MATCH; }
then { return THEN; }
eq { return EQ; }
neq { return NEQ; }
sub { return SUB; }
nsub { return NSUB; }
inpath { return INPATH; }
true { return TRUE; }
"->" { return THEN; }
\( { return LBRACE; }
\) { return RBRACE; }
[\$A-Za-z][\.\(\)\/A-Za-z_\-0-9]* { yylval.string = strdup(yytext); return STRING; }
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
\"[^\"]+\" { char line[1024];
strlcpy(line, yytext + 1, sizeof(line));
line[strlen(line)-1] = '\0';
yylval.string = strdup(line);
return CMDSTRING; }
\[ { return LSQBRACE; }
\] { return RSQBRACE; }
\ { ; }
\n { ; }
\t { ; }
"#".*\n { ; }
. { yyerror("illegal token"); }
%%
#ifndef yywrap
int yywrap() { return 1; }
#endif

View File

@ -0,0 +1,585 @@
/* $NetBSD: netbsd-syscalls.c,v 1.1 2002/06/17 16:29:09 christos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: netbsd-syscalls.c,v 1.1 2002/06/17 16:29:09 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <compat/aout/aout_syscall.h>
#include <compat/aoutm68k/aoutm68k_syscall.h>
#include <compat/freebsd/freebsd_syscall.h>
#include <compat/hpux/hpux_syscall.h>
#include <compat/ibcs2/ibcs2_syscall.h>
#include <compat/irix/irix_syscall.h>
#include <compat/linux/linux_syscall.h>
#include <compat/mach/mach_syscall.h>
#include <compat/netbsd32/netbsd32_syscall.h>
#include <compat/osf1/osf1_syscall.h>
#include <compat/pecoff/pecoff_syscall.h>
#include <compat/sunos/sunos_syscall.h>
#include <compat/sunos32/sunos32_syscall.h>
#include <compat/svr4/svr4_syscall.h>
#include <compat/svr4_32/svr4_32_syscall.h>
#include <compat/ultrix/ultrix_syscall.h>
#define KTRACE
#define NFSCLIENT
#define NFSSERVER
#define SYSVSEM
#define SYSVMSG
#define SYSVSHM
#define LFS
#define NTP
#include <kern/syscalls.c>
#include <compat/aout/aout_syscalls.c>
#include <compat/aoutm68k/aoutm68k_syscalls.c>
#include <compat/freebsd/freebsd_syscalls.c>
#include <compat/hpux/hpux_syscalls.c>
#include <compat/ibcs2/ibcs2_syscalls.c>
#include <compat/irix/irix_syscalls.c>
#include <compat/linux/linux_syscalls.c>
#include <compat/mach/mach_syscalls.c>
#include <compat/netbsd32/netbsd32_syscalls.c>
#include <compat/osf1/osf1_syscalls.c>
#include <compat/pecoff/pecoff_syscalls.c>
#include <compat/sunos/sunos_syscalls.c>
#include <compat/sunos32/sunos32_syscalls.c>
#include <compat/svr4/svr4_syscalls.c>
#include <compat/svr4_32/svr4_32_syscalls.c>
#include <compat/ultrix/ultrix_syscalls.c>
#undef KTRACE
#undef NFSCLIENT
#undef NFSSERVER
#undef SYSVSEM
#undef SYSVMSG
#undef SYSVSHM
#undef LFS
#undef NTP
#include <sys/ioctl.h>
#include <sys/tree.h>
#include <sys/systrace.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include "intercept.h"
struct emulation {
char *name; /* Emulation name */
const char * const *sysnames; /* Array of system call names */
int nsysnames; /* Number of */
};
static struct emulation emulations[] = {
{ "netbsd", syscallnames, SYS_MAXSYSCALL },
{ "aout", aout_syscallnames, AOUT_SYS_MAXSYSCALL },
{ "aoutm68k", aoutm68k_syscallnames, AOUTM68K_SYS_MAXSYSCALL },
{ "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL },
{ "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL },
{ "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL },
{ "irix", irix_syscallnames, IRIX_SYS_MAXSYSCALL },
{ "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL },
{ "mach", mach_syscallnames, MACH_SYS_MAXSYSCALL },
{ "netbsd32", netbsd32_syscallnames, netbsd32_SYS_MAXSYSCALL },
{ "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL },
{ "pecoff", pecoff_syscallnames, PECOFF_SYS_MAXSYSCALL },
{ "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL },
{ "sunos32", sunos32_syscallnames, SUNOS32_SYS_MAXSYSCALL },
{ "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL },
{ "svr4_32", svr4_32_syscallnames, SVR4_32_SYS_MAXSYSCALL },
{ "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL },
{ NULL, NULL, NULL }
};
struct nbsd_data {
struct emulation *current;
struct emulation *commit;
};
static int nbsd_init(void);
static int nbsd_attach(int, pid_t);
static int nbsd_report(int, pid_t);
static int nbsd_detach(int, pid_t);
static int nbsd_open(void);
static struct intercept_pid *nbsd_getpid(pid_t);
static void nbsd_freepid(struct intercept_pid *);
static void nbsd_clonepid(struct intercept_pid *, struct intercept_pid *);
static struct emulation *nbsd_find_emulation(const char *);
static int nbsd_set_emulation(pid_t, char *);
static struct emulation *nbsd_switch_emulation(struct nbsd_data *);
static const char *nbsd_syscall_name(pid_t, int);
static int nbsd_syscall_number(const char *, const char *);
static short nbsd_translate_policy(short);
static short nbsd_translate_flags(short);
static int nbsd_translate_errno(int);
static int nbsd_answer(int, pid_t, short, int, short);
static int nbsd_newpolicy(int);
static int nbsd_assignpolicy(int, pid_t, int);
static int nbsd_modifypolicy(int, int, int, short);
static int nbsd_io(int, pid_t, int, void *, u_char *, size_t);
static char *nbsd_getcwd(int, pid_t, char *, size_t);
static int nbsd_argument(int, void *, int, void **);
static int nbsd_read(int);
static int
nbsd_init(void)
{
return (0);
}
static int
nbsd_attach(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCATTACH, &pid) == -1)
return (-1);
return (0);
}
static int
nbsd_report(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCREPORT, &pid) == -1)
return (-1);
return (0);
}
static int
nbsd_detach(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCDETACH, &pid) == -1)
return (-1);
return (0);
}
static int
nbsd_open(void)
{
char *path = "/dev/systrace";
int fd, cfd = -1;
fd = open(path, O_RDONLY, 0);
if (fd == -1) {
warn("open: %s", path);
return (-1);
}
if (ioctl(fd, SYSTR_CLONE, &cfd) == -1) {
warn("ioctl(SYSTR_CLONE)");
goto out;
}
if (fcntl(cfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
out:
close (fd);
return (cfd);
}
static struct intercept_pid *
nbsd_getpid(pid_t pid)
{
struct intercept_pid *icpid;
struct nbsd_data *data;
icpid = intercept_getpid(pid);
if (icpid == NULL)
return (NULL);
if (icpid->data != NULL)
return (icpid);
if ((icpid->data = malloc(sizeof(struct nbsd_data))) == NULL)
err(1, "%s:%d: malloc", __func__, __LINE__);
data = icpid->data;
data->current = &emulations[0];
data->commit = NULL;
return (icpid);
}
static void
nbsd_freepid(struct intercept_pid *ipid)
{
if (ipid->data != NULL)
free(ipid->data);
}
static void
nbsd_clonepid(struct intercept_pid *opid, struct intercept_pid *npid)
{
if (opid->data == NULL) {
npid->data = NULL;
return;
}
if ((npid->data = malloc(sizeof(struct nbsd_data))) == NULL)
err(1, "%s:%d: malloc", __func__, __LINE__);
memcpy(npid->data, opid->data, sizeof(struct nbsd_data));
}
static struct emulation *
nbsd_find_emulation(const char *name)
{
struct emulation *tmp;
tmp = emulations;
while (tmp->name) {
if (!strcmp(tmp->name, name))
break;
tmp++;
}
if (!tmp->name)
return (NULL);
return (tmp);
}
static int
nbsd_set_emulation(pid_t pidnr, char *name)
{
struct emulation *tmp;
struct intercept_pid *pid;
struct nbsd_data *data;
if ((tmp = nbsd_find_emulation(name)) == NULL)
return (-1);
pid = intercept_getpid(pidnr);
if (pid == NULL)
return (-1);
data = pid->data;
data->commit = tmp;
return (0);
}
static struct emulation *
nbsd_switch_emulation(struct nbsd_data *data)
{
data->current = data->commit;
data->commit = NULL;
return data->current;
}
static const char *
nbsd_syscall_name(pid_t pidnr, int number)
{
struct intercept_pid *pid;
struct emulation *current;
pid = nbsd_getpid(pidnr);
if (pid == NULL)
return (NULL);
current = ((struct nbsd_data *)pid->data)->current;
if (number < 0 || number >= current->nsysnames)
return (NULL);
return (current->sysnames[number]);
}
static int
nbsd_syscall_number(const char *emulation, const char *name)
{
struct emulation *current;
int i;
current = nbsd_find_emulation(emulation);
if (current == NULL)
return (-1);
for (i = 0; i < current->nsysnames; i++)
if (!strcmp(name, current->sysnames[i]))
return (i);
return (-1);
}
static short
nbsd_translate_policy(short policy)
{
switch (policy) {
case ICPOLICY_ASK:
return (SYSTR_POLICY_ASK);
case ICPOLICY_PERMIT:
return (SYSTR_POLICY_PERMIT);
case ICPOLICY_NEVER:
default:
return (SYSTR_POLICY_NEVER);
}
}
static short
nbsd_translate_flags(short flags)
{
switch (flags) {
case ICFLAGS_RESULT:
return (SYSTR_FLAGS_RESULT);
default:
return (0);
}
}
static int
nbsd_translate_errno(int errno)
{
return (errno);
}
static int
nbsd_answer(int fd, pid_t pid, short policy, int errno, short flags)
{
struct systrace_answer ans;
ans.stra_pid = pid;
ans.stra_policy = nbsd_translate_policy(policy);
ans.stra_flags = nbsd_translate_flags(flags);
ans.stra_error = nbsd_translate_errno(errno);
if (ioctl(fd, STRIOCANSWER, &ans) == -1)
return (-1);
return (0);
}
static int
nbsd_newpolicy(int fd)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_NEW;
pol.strp_num = -1;
pol.strp_maxents = 512;
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (pol.strp_num);
}
static int
nbsd_assignpolicy(int fd, pid_t pid, int num)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_ASSIGN;
pol.strp_num = num;
pol.strp_pid = pid;
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (0);
}
static int
nbsd_modifypolicy(int fd, int num, int code, short policy)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_MODIFY;
pol.strp_num = num;
pol.strp_code = code;
pol.strp_policy = nbsd_translate_policy(policy);
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (0);
}
static int
nbsd_io(int fd, pid_t pid, int op, void *addr, u_char *buf, size_t size)
{
struct systrace_io io;
memset(&io, 0, sizeof(io));
io.strio_pid = pid;
io.strio_addr = buf;
io.strio_len = size;
io.strio_offs = addr;
io.strio_op = (op == INTERCEPT_READ ? SYSTR_READ : SYSTR_WRITE);
if (ioctl(fd, STRIOCIO, &io) == -1)
return (-1);
return (0);
}
static char *
nbsd_getcwd(int fd, pid_t pid, char *buf, size_t size)
{
char *path;
if (ioctl(fd, STRIOCGETCWD, &pid) == -1)
return (NULL);
path = getcwd(buf, size);
if (ioctl(fd, STRIOCRESCWD, 0) == -1)
warn("%s: ioctl", __func__); /* XXX */
return (path);
}
static int
nbsd_argument(int off, void *pargs, int argsize, void **pres)
{
register_t *args = (register_t *)pargs;
if (off >= argsize / sizeof(register_t))
return (-1);
*pres = (void *)args[off];
return (0);
}
static int
nbsd_read(int fd)
{
struct str_message msg;
struct intercept_pid *icpid;
struct nbsd_data *data;
struct emulation *current;
char name[SYSTR_EMULEN+1];
const char *sysname;
int code;
if (read(fd, &msg, sizeof(msg)) != sizeof(msg))
return (-1);
icpid = nbsd_getpid(msg.msg_pid);
if (icpid == NULL)
return (-1);
data = icpid->data;
current = data->current;
switch(msg.msg_type) {
case SYSTR_MSG_ASK:
code = msg.msg_data.msg_ask.code;
sysname = nbsd_syscall_name(msg.msg_pid, code);
intercept_syscall(fd, msg.msg_pid, msg.msg_policy,
sysname, code, current->name,
(void *)msg.msg_data.msg_ask.args,
msg.msg_data.msg_ask.argsize);
break;
case SYSTR_MSG_RES:
code = msg.msg_data.msg_ask.code;
sysname = nbsd_syscall_name(msg.msg_pid, code);
/* Switch emulation around at the right time */
if (data->commit != NULL) {
current = nbsd_switch_emulation(data);
}
intercept_syscall_result(fd, msg.msg_pid, msg.msg_policy,
sysname, code, current->name,
(void *)msg.msg_data.msg_ask.args,
msg.msg_data.msg_ask.argsize,
msg.msg_data.msg_ask.result,
msg.msg_data.msg_ask.rval);
break;
case SYSTR_MSG_EMUL:
memcpy(name, msg.msg_data.msg_emul.emul, SYSTR_EMULEN);
name[SYSTR_EMULEN] = '\0';
if (nbsd_set_emulation(msg.msg_pid, name) == -1)
errx(1, "%s:%d: set_emulation(%s)",
__func__, __LINE__, name);
if (icpid->execve_code == -1) {
icpid->execve_code = 0;
/* A running attach fake a exec cb */
current = nbsd_switch_emulation(data);
intercept_syscall_result(fd,
msg.msg_pid, msg.msg_policy,
"execve", 0, current->name,
NULL, 0, 0, NULL);
break;
}
if (nbsd_answer(fd, msg.msg_pid, 0, 0, 0) == -1)
err(1, "%s:%d: answer", __func__, __LINE__);
break;
case SYSTR_MSG_CHILD:
intercept_child_info(msg.msg_pid,
msg.msg_data.msg_child.new_pid);
break;
}
return (0);
}
struct intercept_system intercept = {
"netbsd",
nbsd_init,
nbsd_open,
nbsd_attach,
nbsd_detach,
nbsd_report,
nbsd_read,
nbsd_syscall_number,
nbsd_getcwd,
nbsd_io,
nbsd_argument,
nbsd_answer,
nbsd_newpolicy,
nbsd_assignpolicy,
nbsd_modifypolicy,
nbsd_clonepid,
nbsd_freepid,
};

View File

@ -0,0 +1,543 @@
/* $NetBSD: openbsd-syscalls.c,v 1.1 2002/06/17 16:29:09 christos Exp $ */
/* $OpenBSD: openbsd-syscalls.c,v 1.5 2002/06/10 19:16:26 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include "../../sys/compat/bsdos/bsdos_syscall.h"
#include "../../sys/compat/freebsd/freebsd_syscall.h"
#include "../../sys/compat/netbsd/netbsd_syscall.h"
#include "../../sys/compat/hpux/hpux_syscall.h"
#include "../../sys/compat/ibcs2/ibcs2_syscall.h"
#include "../../sys/compat/linux/linux_syscall.h"
#include "../../sys/compat/osf1/osf1_syscall.h"
#include "../../sys/compat/sunos/sunos_syscall.h"
#include "../../sys/compat/svr4/svr4_syscall.h"
#include "../../sys/compat/ultrix/ultrix_syscall.h"
#define KTRACE
#define NFSCLIENT
#define NFSSERVER
#define SYSVSEM
#define SYSVMSG
#define SYSVSHM
#define LFS
#define NTP
#include "../../sys/kern/syscalls.c"
#include "../../sys/compat/bsdos/bsdos_syscalls.c"
#include "../../sys/compat/freebsd/freebsd_syscalls.c"
#include "../../sys/compat/netbsd/netbsd_syscalls.c"
#include "../../sys/compat/hpux/hpux_syscalls.c"
#include "../../sys/compat/ibcs2/ibcs2_syscalls.c"
#include "../../sys/compat/linux/linux_syscalls.c"
#include "../../sys/compat/osf1/osf1_syscalls.c"
#include "../../sys/compat/sunos/sunos_syscalls.c"
#include "../../sys/compat/svr4/svr4_syscalls.c"
#include "../../sys/compat/ultrix/ultrix_syscalls.c"
#undef KTRACE
#undef NFSCLIENT
#undef NFSSERVER
#undef SYSVSEM
#undef SYSVMSG
#undef SYSVSHM
#undef LFS
#undef NTP
#include <sys/ioctl.h>
#include <sys/tree.h>
#include <dev/systrace.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include "intercept.h"
/* Callback into main library */
void intercept_child_info(pid_t, pid_t);
void intercept_syscall(int, pid_t, int, char *, int, char *, void *, int);
void intercept_syscall_result(int, pid_t, int, char *, int, char *, void *,
int, int, void *);
struct emulation {
char *name; /* Emulation name */
char **sysnames; /* Array of system call names */
int nsysnames; /* Number of */
};
static struct emulation emulations[] = {
{ "native", syscallnames, SYS_MAXSYSCALL },
{ "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL },
{ "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL },
{ "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL },
{ "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL },
{ "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL },
{ "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL },
{ "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL },
{ "bsdos", bsdos_syscallnames, BSDOS_SYS_MAXSYSCALL },
{ "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL },
{ "netbsd", netbsd_syscallnames, NETBSD_SYS_MAXSYSCALL },
{ NULL, NULL, NULL }
};
struct obsd_data {
struct emulation *current;
struct emulation *commit;
};
int
obsd_init(void)
{
return (0);
}
int
obsd_attach(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCATTACH, &pid) == -1)
return (-1);
return (0);
}
int
obsd_report(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCREPORT, &pid) == -1)
return (-1);
return (0);
}
int
obsd_detach(int fd, pid_t pid)
{
if (ioctl(fd, STRIOCDETACH, &pid) == -1)
return (-1);
return (0);
}
int
obsd_open(void)
{
char *path = "/dev/systrace";
int fd, cfd = -1;
fd = open(path, O_RDONLY, 0);
if (fd == -1) {
warn("open: %s", path);
return (-1);
}
if (ioctl(fd, SYSTR_CLONE, &cfd) == -1) {
warn("ioctl(SYSTR_CLONE)");
goto out;
}
if (fcntl(cfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
out:
close (fd);
return (cfd);
}
struct intercept_pid *
obsd_getpid(pid_t pid)
{
struct intercept_pid *icpid;
struct obsd_data *data;
icpid = intercept_getpid(pid);
if (icpid == NULL)
return (NULL);
if (icpid->data != NULL)
return (icpid);
if ((icpid->data = malloc(sizeof(struct obsd_data))) == NULL)
err(1, "%s:%d: malloc", __func__, __LINE__);
data = icpid->data;
data->current = &emulations[0];
data->commit = NULL;
return (icpid);
}
void
obsd_freepid(struct intercept_pid *ipid)
{
if (ipid->data != NULL)
free(ipid->data);
}
void
obsd_clonepid(struct intercept_pid *opid, struct intercept_pid *npid)
{
if (opid->data == NULL) {
npid->data = NULL;
return;
}
if ((npid->data = malloc(sizeof(struct obsd_data))) == NULL)
err(1, "%s:%d: malloc", __func__, __LINE__);
memcpy(npid->data, opid->data, sizeof(struct obsd_data));
}
struct emulation *
obsd_find_emulation(char *name)
{
struct emulation *tmp;
tmp = emulations;
while (tmp->name) {
if (!strcmp(tmp->name, name))
break;
tmp++;
}
if (!tmp->name)
return (NULL);
return (tmp);
}
int
obsd_set_emulation(pid_t pidnr, char *name)
{
struct emulation *tmp;
struct intercept_pid *pid;
struct obsd_data *data;
if ((tmp = obsd_find_emulation(name)) == NULL)
return (-1);
pid = intercept_getpid(pidnr);
if (pid == NULL)
return (-1);
data = pid->data;
data->commit = tmp;
return (0);
}
struct emulation *
obsd_switch_emulation(struct obsd_data *data)
{
data->current = data->commit;
data->commit = NULL;
return (data->current);
}
char *
obsd_syscall_name(pid_t pidnr, int number)
{
struct intercept_pid *pid;
struct emulation *current;
pid = obsd_getpid(pidnr);
if (pid == NULL)
return (NULL);
current = ((struct obsd_data *)pid->data)->current;
if (number < 0 || number >= current->nsysnames)
return (NULL);
return (current->sysnames[number]);
}
int
obsd_syscall_number(char *emulation, char *name)
{
struct emulation *current;
int i;
current = obsd_find_emulation(emulation);
if (current == NULL)
return (-1);
for (i = 0; i < current->nsysnames; i++)
if (!strcmp(name, current->sysnames[i]))
return (i);
return (-1);
}
short
obsd_translate_policy(short policy)
{
switch (policy) {
case ICPOLICY_ASK:
return (SYSTR_POLICY_ASK);
case ICPOLICY_PERMIT:
return (SYSTR_POLICY_PERMIT);
case ICPOLICY_NEVER:
default:
return (SYSTR_POLICY_NEVER);
}
}
short
obsd_translate_flags(short flags)
{
switch (flags) {
case ICFLAGS_RESULT:
return (SYSTR_FLAGS_RESULT);
default:
return (0);
}
}
int
obsd_translate_errno(int errno)
{
return (errno);
}
int
obsd_answer(int fd, pid_t pid, short policy, int errno, short flags)
{
struct systrace_answer ans;
ans.stra_pid = pid;
ans.stra_policy = obsd_translate_policy(policy);
ans.stra_flags = obsd_translate_flags(flags);
ans.stra_error = obsd_translate_errno(errno);
if (ioctl(fd, STRIOCANSWER, &ans) == -1)
return (-1);
return (0);
}
int
obsd_newpolicy(int fd)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_NEW;
pol.strp_num = -1;
pol.strp_maxents = 512;
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (pol.strp_num);
}
int
obsd_assignpolicy(int fd, pid_t pid, int num)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_ASSIGN;
pol.strp_num = num;
pol.strp_pid = pid;
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (0);
}
int
obsd_modifypolicy(int fd, int num, int code, short policy)
{
struct systrace_policy pol;
pol.strp_op = SYSTR_POLICY_MODIFY;
pol.strp_num = num;
pol.strp_code = code;
pol.strp_policy = obsd_translate_policy(policy);
if (ioctl(fd, STRIOCPOLICY, &pol) == -1)
return (-1);
return (0);
}
int
obsd_io(int fd, pid_t pid, int op, void *addr, u_char *buf, size_t size)
{
struct systrace_io io;
memset(&io, 0, sizeof(io));
io.strio_pid = pid;
io.strio_addr = buf;
io.strio_len = size;
io.strio_offs = addr;
io.strio_op = (op == INTERCEPT_READ ? SYSTR_READ : SYSTR_WRITE);
if (ioctl(fd, STRIOCIO, &io) == -1)
return (-1);
return (0);
}
char *
obsd_getcwd(int fd, pid_t pid, char *buf, size_t size)
{
char *path;
if (ioctl(fd, STRIOCGETCWD, &pid) == -1)
return (NULL);
path = getcwd(buf, size);
if (ioctl(fd, STRIOCRESCWD, 0) == -1)
warn("%s: ioctl", __func__); /* XXX */
return (path);
}
int
obsd_argument(int off, void *pargs, int argsize, void **pres)
{
register_t *args = (register_t *)pargs;
if (off >= argsize / sizeof(register_t))
return (-1);
*pres = (void *)args[off];
return (0);
}
int
obsd_read(int fd)
{
struct str_message msg;
struct intercept_pid *icpid;
struct obsd_data *data;
struct emulation *current;
char name[SYSTR_EMULEN+1], *sysname;
int code;
if (read(fd, &msg, sizeof(msg)) != sizeof(msg))
return (-1);
icpid = obsd_getpid(msg.msg_pid);
if (icpid == NULL)
return (-1);
data = icpid->data;
current = data->current;
switch (msg.msg_type) {
case SYSTR_MSG_ASK:
code = msg.msg_data.msg_ask.code;
sysname = obsd_syscall_name(msg.msg_pid, code);
intercept_syscall(fd, msg.msg_pid, msg.msg_policy,
sysname, code, current->name,
(void *)msg.msg_data.msg_ask.args,
msg.msg_data.msg_ask.argsize);
break;
case SYSTR_MSG_RES:
code = msg.msg_data.msg_ask.code;
sysname = obsd_syscall_name(msg.msg_pid, code);
/* Switch emulation around at the right time */
if (data->commit != NULL) {
current = obsd_switch_emulation(data);
}
intercept_syscall_result(fd, msg.msg_pid, msg.msg_policy,
sysname, code, current->name,
(void *)msg.msg_data.msg_ask.args,
msg.msg_data.msg_ask.argsize,
msg.msg_data.msg_ask.result,
msg.msg_data.msg_ask.rval);
break;
case SYSTR_MSG_EMUL:
memcpy(name, msg.msg_data.msg_emul.emul, SYSTR_EMULEN);
name[SYSTR_EMULEN] = '\0';
if (obsd_set_emulation(msg.msg_pid, name) == -1)
errx(1, "%s:%d: set_emulation(%s)",
__func__, __LINE__, name);
if (icpid->execve_code == -1) {
icpid->execve_code = 0;
/* A running attach fake a exec cb */
current = obsd_switch_emulation(data);
intercept_syscall_result(fd,
msg.msg_pid, msg.msg_policy,
"execve", 0, current->name,
NULL, 0, 0, NULL);
break;
}
if (obsd_answer(fd, msg.msg_pid, 0, 0, 0) == -1)
err(1, "%s:%d: answer", __func__, __LINE__);
break;
case SYSTR_MSG_CHILD:
intercept_child_info(msg.msg_pid,
msg.msg_data.msg_child.new_pid);
break;
}
return (0);
}
struct intercept_system intercept = {
"openbsd",
obsd_init,
obsd_open,
obsd_attach,
obsd_detach,
obsd_report,
obsd_read,
obsd_syscall_number,
obsd_getcwd,
obsd_io,
obsd_argument,
obsd_answer,
obsd_newpolicy,
obsd_assignpolicy,
obsd_modifypolicy,
obsd_clonepid,
obsd_freepid,
};

329
bin/systrace/parse.y Normal file
View File

@ -0,0 +1,329 @@
/* $NetBSD: parse.y,v 1.1 2002/06/17 16:29:10 christos Exp $ */
/* $OpenBSD: parse.y,v 1.4 2002/06/05 17:22:38 mickey Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
%{
#include <sys/cdefs.h>
__RCSID("$NetBSD: parse.y,v 1.1 2002/06/17 16:29:10 christos Exp $");
#include <sys/types.h>
#include <sys/time.h>
#include <sys/tree.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <stdarg.h>
#include <string.h>
#include "intercept.h"
#include "systrace.h"
#include "systrace-errno.h"
#include "filter.h"
void yyrestart(FILE *);
struct logic *parse_newsymbol(char *, int, char *);
int yylex(void);
int yyparse(void);
int yyerror(const char *, ...);
int errors = 0;
struct filter *myfilter;
extern char *mystring;
extern int myoff;
%}
%token AND OR NOT LBRACE RBRACE LSQBRACE RSQBRACE THEN MATCH PERMIT DENY
%token EQ NEQ TRUE SUB NSUB INPATH
%token <string> STRING
%token <string> CMDSTRING
%token <number> NUMBER
%type <logic> expression
%type <logic> symbol
%type <action> action
%type <number> typeoff
%type <string> errorcode
%union {
int number;
char *string;
short action;
struct logic *logic;
}
%%
filter : fullexpression
;
fullexpression : expression THEN action errorcode
{
int flags = 0, errorcode = SYSTRACE_EPERM;
switch ($3) {
case ICPOLICY_NEVER:
if ($4 == NULL)
break;
errorcode = systrace_error_translate($4);
if (errorcode == -1)
yyerror("Unknown error code: %s", $4);
break;
case ICPOLICY_PERMIT:
if ($4 == NULL)
break;
if (!strcasecmp($4, "inherit"))
flags = PROCESS_INHERIT_POLICY;
break;
}
if ($4 != NULL)
free($4);
myfilter = calloc(1, sizeof(struct filter));
if (myfilter == NULL) {
yyerror("calloc");
break;
}
myfilter->logicroot = $1;
myfilter->match_action = $3;
myfilter->match_error = errorcode;
myfilter->match_flags = flags;
}
;
errorcode : /* Empty */
{
$$ = NULL;
}
| LSQBRACE STRING RSQBRACE
{
$$ = $2;
}
;
expression : symbol
{
$$ = $1;
}
| NOT expression
{
struct logic *node;
node = calloc(1, sizeof(struct logic));
if (node == NULL) {
yyerror("calloc");
break;
}
node->op = LOGIC_NOT;
node->left = $2;
$$ = node;
}
| LBRACE expression RBRACE
{
$$ = $2;
}
| expression AND expression
{
struct logic *node;
node = calloc(1, sizeof(struct logic));
if (node == NULL) {
yyerror("calloc");
break;
}
node->op = LOGIC_AND;
node->left = $1;
node->right = $3;
$$ = node;
}
| expression OR expression
{
struct logic *node;
node = calloc(1, sizeof(struct logic));
if (node == NULL) {
yyerror("calloc");
break;
}
node->op = LOGIC_OR;
node->left = $1;
node->right = $3;
$$ = node;
}
;
symbol : STRING typeoff MATCH CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_fnmatch;
$$ = node;
}
| STRING typeoff EQ CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_stringmatch;
$$ = node;
}
| STRING typeoff NEQ CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_negstringmatch;
$$ = node;
}
| STRING typeoff SUB CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_substrmatch;
$$ = node;
}
| STRING typeoff NSUB CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_negsubstrmatch;
$$ = node;
}
| STRING typeoff INPATH CMDSTRING
{
struct logic *node;
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
break;
node->filter_match = filter_inpath;
$$ = node;
}
| TRUE
{
struct logic *node;
if ((node = parse_newsymbol(NULL, -1, NULL)) == NULL)
break;
node->filter_match = filter_true;
$$ = node;
}
;
typeoff : /* empty */
{
$$ = -1;
}
| LSQBRACE NUMBER RSQBRACE
{
if ($2 < 0 || $2 >= INTERCEPT_MAXSYSCALLARGS) {
yyerror("Bad offset: %d", $2);
break;
}
$$ = $2;
}
;
action : PERMIT
{
$$ = ICPOLICY_PERMIT;
}
| DENY
{
$$ = ICPOLICY_NEVER;
}
%%
int
yyerror(const char *fmt, ...)
{
va_list ap;
errors = 1;
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
fprintf(stdout, "\n");
va_end(ap);
return (0);
}
struct logic *
parse_newsymbol(char *type, int typeoff, char *data)
{
struct logic *node;
node = calloc(1, sizeof(struct logic));
if (node == NULL) {
yyerror("calloc");
return (NULL);
}
node->op = LOGIC_SINGLE;
node->type = type;
node->typeoff = typeoff;
if (data) {
node->filterdata = strdup(filter_expand(data));
free(data);
if (node->filterdata == NULL) {
yyerror("strdup");
return (NULL);
}
node->filterlen = strlen(node->filterdata) + 1;
}
return (node);
}
int
parse_filter(char *name, struct filter **pfilter)
{
errors = 0;
myfilter = NULL;
mystring = name;
myoff = 0;
yyparse();
yyrestart(NULL);
*pfilter = myfilter;
return (errors ? -1 : 0);
}

560
bin/systrace/policy.c Normal file
View File

@ -0,0 +1,560 @@
/* $NetBSD: policy.c,v 1.1 2002/06/17 16:29:10 christos Exp $ */
/* $OpenBSD: policy.c,v 1.9 2002/06/11 05:30:28 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: policy.c,v 1.1 2002/06/17 16:29:10 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/tree.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <grp.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <err.h>
#include "intercept.h"
#include "systrace.h"
static int psccompare(struct policy_syscall *, struct policy_syscall *);
static int policycompare(struct policy *, struct policy *);
static int polnrcompare(struct policy *, struct policy *);
static void systrace_setupdir(void);
static char *systrace_policyfilename(char *, const char *);
static int systrace_predicatematch(char *);
static int systrace_writepolicy(struct policy *);
static int
psccompare(struct policy_syscall *a, struct policy_syscall *b)
{
int diff;
diff = strcmp(a->emulation, b->emulation);
if (diff)
return (diff);
return (strcmp(a->name, b->name));
}
SPLAY_PROTOTYPE(syscalltree, policy_syscall, node, psccompare);
SPLAY_GENERATE(syscalltree, policy_syscall, node, psccompare);
static SPLAY_HEAD(policytree, policy) policyroot;
static SPLAY_HEAD(polnrtree, policy) polnrroot;
static int
policycompare(struct policy *a, struct policy *b)
{
return (strcmp(a->name, b->name));
}
static int
polnrcompare(struct policy *a, struct policy *b)
{
int diff = a->policynr - b->policynr;
if (diff == 0)
return (0);
if (diff > 0 )
return (1);
return (-1);
}
SPLAY_PROTOTYPE(policytree, policy, node, policycompare);
SPLAY_GENERATE(policytree, policy, node, policycompare);
SPLAY_PROTOTYPE(polnrtree, policy, nrnode, polnrcompare);
SPLAY_GENERATE(polnrtree, policy, nrnode, polnrcompare);
extern int userpolicy;
static char policydir[MAXPATHLEN];
static char *groupnames[NGROUPS_MAX];
static int ngroups;
static void
systrace_setupdir(void)
{
char *home;
struct stat sb;
home = getenv("HOME");
if (home == NULL)
errx(1, "No HOME environment set");
if (strlcpy(policydir, home, sizeof(policydir)) >= sizeof(policydir))
errx(1, "HOME too long");
if (strlcat(policydir, "/.systrace", sizeof(policydir)) >= sizeof(policydir))
errx(1, "HOME too long");
if (stat(policydir, &sb) != -1) {
if (!(sb.st_mode & S_IFDIR))
errx(1, "Not a directory: \"%s\"", policydir);
} else if (mkdir(policydir, 0700) == -1)
err(1, "mdkdir(%s)", policydir);
}
int
systrace_initpolicy(char *file)
{
gid_t groups[NGROUPS_MAX];
char gidbuf[10];
int i;
SPLAY_INIT(&policyroot);
SPLAY_INIT(&polnrroot);
/* Find out group names for current user */
if ((ngroups = getgroups(NGROUPS_MAX, groups)) == -1)
err(1, "getgroups");
for (i = 0; i < ngroups; i++) {
struct group *gr;
if ((gr = getgrgid(groups[i])) != NULL) {
if ((groupnames[i] = strdup(gr->gr_name)) == NULL)
err(1, "strdup(%s)", gr->gr_name);
} else {
snprintf(gidbuf, sizeof(gidbuf), "%lu",
(u_long)groups[i]);
if ((groupnames[i] = strdup(gidbuf)) == NULL)
err(1, "strdup(%s)", gidbuf);
}
}
if (userpolicy)
systrace_setupdir();
if (file != NULL)
return (systrace_readpolicy(file));
return (0);
}
struct policy *
systrace_findpolicy(const char *name)
{
struct policy tmp;
tmp.name = name;
return (SPLAY_FIND(policytree, &policyroot, &tmp));
}
struct policy *
systrace_findpolnr(int nr)
{
struct policy tmp;
tmp.policynr = nr;
return (SPLAY_FIND(polnrtree, &polnrroot, &tmp));
}
int
systrace_newpolicynr(int fd, struct policy *tmp)
{
if (tmp->policynr != -1)
return (-1);
if ((tmp->policynr = intercept_newpolicy(fd)) == -1) {
free(tmp);
return (-1);
}
SPLAY_INSERT(polnrtree, &polnrroot, tmp);
return (tmp->policynr);
}
struct policy *
systrace_newpolicy(const char *emulation, const char *name)
{
struct policy *tmp;
if ((tmp = systrace_findpolicy(name)) != NULL)
return (tmp);
tmp = calloc(1, sizeof(struct policy));
if (tmp == NULL)
return (NULL);
tmp->policynr = -1;
/* New policies requires intialization */
if ((tmp->name = strdup(name)) == NULL)
err(1, "%s:%d: strdup", __func__, __LINE__);
strlcpy(tmp->emulation, emulation, sizeof(tmp->emulation));
SPLAY_INSERT(policytree, &policyroot, tmp);
SPLAY_INIT(&tmp->pflqs);
TAILQ_INIT(&tmp->filters);
TAILQ_INIT(&tmp->prefilters);
return (tmp);
}
struct filterq *
systrace_policyflq(struct policy *policy, const char *emulation,
const char *name)
{
struct policy_syscall tmp2, *tmp;
strlcpy(tmp2.emulation, emulation, sizeof(tmp2.emulation));
strlcpy(tmp2.name, name, sizeof(tmp2.name));
tmp = SPLAY_FIND(syscalltree, &policy->pflqs, &tmp2);
if (tmp != NULL)
return (&tmp->flq);
if ((tmp = calloc(1, sizeof(struct policy_syscall))) == NULL)
err(1, "%s:%d: out of memory", __func__, __LINE__);
strlcpy(tmp->emulation, emulation, sizeof(tmp->emulation));
strlcpy(tmp->name, name, sizeof(tmp->name));
TAILQ_INIT(&tmp->flq);
SPLAY_INSERT(syscalltree, &policy->pflqs, tmp);
return (&tmp->flq);
}
int
systrace_modifypolicy(int fd, int policynr, const char *name, short action)
{
struct policy *policy;
int res;
if ((policy = systrace_findpolnr(policynr)) == NULL)
return (-1);
res = intercept_modifypolicy(fd, policynr, policy->emulation,
name, action);
return (res);
}
static char *
systrace_policyfilename(char *dirname, const char *name)
{
static char file[2*MAXPATHLEN];
const char *p;
int i, plen;
if (strlen(name) + strlen(dirname) + 1 >= sizeof(file))
return (NULL);
strlcpy(file, dirname, sizeof(file));
i = strlen(file);
file[i++] = '/';
plen = i;
p = name;
while (*p) {
if (!isalnum(*p)) {
if (i != plen)
file[i++] = '_';
} else
file[i++] = *p;
p++;
}
file[i] = '\0';
return (file);
}
int
systrace_addpolicy(const char *name)
{
char *file = NULL;
if (userpolicy) {
file = systrace_policyfilename(policydir, name);
/* Check if the user policy file exists */
if (file != NULL && access(file, R_OK) == -1)
file = NULL;
}
/* Read global policy */
if (file == NULL) {
file = systrace_policyfilename(POLICY_PATH, name);
if (file == NULL)
return (-1);
}
return (systrace_readpolicy(file));
}
static int
systrace_predicatematch(char *p)
{
extern char *username;
int i, res, neg;
res = 0;
neg = 0;
if (!strncasecmp(p, "user", 4)) {
/* Match against user name */
p += 4;
p += strspn(p, " \t");
if (!strncmp(p, "=", 1)) {
p += 1;
neg = 0;
} else if (!strncmp(p, "!=", 2)) {
p += 2;
neg = 1;
} else
return (-1);
p += strspn(p, " \t");
res = (!strcmp(p, username));
} else if (!strncasecmp(p, "group", 5)) {
/* Match against group list */
p += 5;
p += strspn(p, " \t");
if (!strncmp(p, "=", 1)) {
p += 1;
neg = 0;
} else if (!strncmp(p, "!=", 2)) {
p += 2;
neg = 1;
} else
return (-1);
p += strspn(p, " \t");
for (i = 0; i < ngroups; i++) {
if (!strcmp(p, groupnames[i])) {
res = 1;
break;
}
}
} else
return (-1);
if (neg)
res = !res;
return (res);
}
int
systrace_readpolicy(char *filename)
{
FILE *fp;
struct policy *policy;
char line[1024], *p;
int linenumber = 0;
char *name, *emulation, *rule;
struct filter *filter, *parsed;
short action, future;
int res = -1;
if ((fp = fopen(filename, "r")) == NULL)
return (-1);
policy = NULL;
while (fgets(line, sizeof(line), fp)) {
linenumber++;
if ((p = strchr(line, '\n')) == NULL) {
fprintf(stderr, "%s:%d: input line too long.\n",
filename, linenumber);
goto out;
}
*p = '\0';
p = line;
strsep(&p, "#");
p = line;
p += strspn(p, " \t");
if (strlen(p) == 0)
continue;
if (!strncasecmp(p, "Policy: ", 8)) {
p += 8;
name = strsep(&p, ",");
if (p == NULL)
goto error;
if (strncasecmp(p, " Emulation: ", 12))
goto error;
p += 12;
emulation = p;
policy = systrace_newpolicy(emulation, name);
if (policy == NULL)
goto error;
continue;
}
if (policy == NULL)
goto error;
if (!strncasecmp(p, "detached", 8)) {
policy->flags |= POLICY_DETACHED;
policy = NULL;
continue;
}
emulation = strsep(&p, "-");
if (p == NULL || *p == '\0')
goto error;
if (strcmp(emulation, policy->emulation))
goto error;
name = strsep(&p, ":");
if (p == NULL || *p != ' ')
goto error;
p++;
rule = p;
if ((p = strrchr(p, ',')) != NULL &&
!strncasecmp(p, ", if", 4)) {
int match;
*p = '\0';
/* Process predicates */
p += 4;
p += strspn(p, " \t");
match = systrace_predicatematch(p);
if (match == -1)
goto error;
/* If the predicate does not match skip rule */
if (!match)
continue;
}
if (filter_parse_simple(rule, &action, &future) == -1) {
if (parse_filter(rule, &parsed) == -1)
goto error;
filter_free(parsed);
}
filter = calloc(1, sizeof(struct filter));
if (filter == NULL)
err(1, "%s:%d: calloc", __func__, __LINE__);
filter->rule = strdup(rule);
strlcpy(filter->name, name, sizeof(filter->name));
strlcpy(filter->emulation,emulation,sizeof(filter->emulation));
TAILQ_INSERT_TAIL(&policy->prefilters, filter, policy_next);
}
res = 0;
out:
fclose(fp);
return (res);
error:
fprintf(stderr, "%s:%d: systax error.\n",
filename, linenumber);
goto out;
}
static int
systrace_writepolicy(struct policy *policy)
{
FILE *fp;
int fd;
char *p;
char tmpname[2*MAXPATHLEN];
char finalname[2*MAXPATHLEN];
struct filter *filter;
if ((p = systrace_policyfilename(policydir, policy->name)) == NULL)
return (-1);
strlcpy(finalname, p, sizeof(finalname));
if ((p = systrace_policyfilename(policydir, "tmpXXXXXXXX")) == NULL)
return (-1);
strlcpy(tmpname, p, sizeof(tmpname));
if ((fd = mkstemp(tmpname)) == -1 ||
(fp = fdopen(fd, "w+")) == NULL) {
if (fd != -1) {
unlink(tmpname);
close(fd);
}
return (-1);
}
fprintf(fp, "Policy: %s, Emulation: %s\n",
policy->name, policy->emulation);
if (policy->flags & POLICY_DETACHED) {
fprintf(fp, "detached\n");
} else {
TAILQ_FOREACH(filter, &policy->prefilters, policy_next) {
fprintf(fp, "\t%s-%s: %s\n",
filter->emulation, filter->name, filter->rule);
}
TAILQ_FOREACH(filter, &policy->filters, policy_next) {
fprintf(fp, "\t%s-%s: %s\n",
filter->emulation, filter->name, filter->rule);
}
}
fprintf(fp, "\n");
fclose(fp);
if (rename(tmpname, finalname) == -1) {
warn("rename(%s, %s)", tmpname, finalname);
return (-1);
}
return (0);
}
int
systrace_dumppolicy(void)
{
struct policy *policy;
SPLAY_FOREACH(policy, policytree, &policyroot) {
if (!(policy->flags & POLICY_CHANGED))
continue;
if (systrace_writepolicy(policy) == -1)
fprintf(stderr, "Failed to write policy for %s\n",
policy->name);
}
return (0);
}

View File

@ -0,0 +1,122 @@
/* $NetBSD: systrace-errno.h,v 1.1 2002/06/17 16:29:10 christos Exp $ */
/* $OpenBSD: systrace-errno.h,v 1.1 2002/06/04 17:20:04 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYSTRACE_ERRNO_H_
#define _SYSTRACE_ERRNO_H_
#define SYSTRACE_EPERM 1
#define SYSTRACE_ENOENT 2
#define SYSTRACE_ESRCH 3
#define SYSTRACE_EINTR 4
#define SYSTRACE_EIO 5
#define SYSTRACE_ENXIO 6
#define SYSTRACE_E2BIG 7
#define SYSTRACE_ENOEXEC 8
#define SYSTRACE_EBADF 9
#define SYSTRACE_ECHILD 10
#define SYSTRACE_EDEADLK 11
#define SYSTRACE_ENOMEM 12
#define SYSTRACE_EACCES 13
#define SYSTRACE_EFAULT 14
#define SYSTRACE_ENOTBLK 15
#define SYSTRACE_EBUSY 16
#define SYSTRACE_EEXIST 17
#define SYSTRACE_EXDEV 18
#define SYSTRACE_ENODEV 19
#define SYSTRACE_ENOTDIR 20
#define SYSTRACE_EISDIR 21
#define SYSTRACE_EINVAL 22
#define SYSTRACE_ENFILE 23
#define SYSTRACE_EMFILE 24
#define SYSTRACE_ENOTTY 25
#define SYSTRACE_ETXTBSY 26
#define SYSTRACE_EFBIG 27
#define SYSTRACE_ENOSPC 28
#define SYSTRACE_ESPIPE 29
#define SYSTRACE_EROFS 30
#define SYSTRACE_EMLINK 31
#define SYSTRACE_EPIPE 32
#define SYSTRACE_EDOM 33
#define SYSTRACE_ERANGE 34
#define SYSTRACE_EAGAIN 35
#define SYSTRACE_EWOULDBLOCK 35
#define SYSTRACE_EINPROGRESS 36
#define SYSTRACE_EALREADY 37
#define SYSTRACE_ENOTSOCK 38
#define SYSTRACE_EDESTADDRREQ 39
#define SYSTRACE_EMSGSIZE 40
#define SYSTRACE_EPROTOTYPE 41
#define SYSTRACE_ENOPROTOOPT 42
#define SYSTRACE_EPROTONOSUPPORT 43
#define SYSTRACE_ESOCKTNOSUPPORT 44
#define SYSTRACE_EOPNOTSUPP 45
#define SYSTRACE_EPFNOSUPPORT 46
#define SYSTRACE_EAFNOSUPPORT 47
#define SYSTRACE_EADDRINUSE 48
#define SYSTRACE_EADDRNOTAVAIL 49
#define SYSTRACE_ENETDOWN 50
#define SYSTRACE_ENETUNREACH 51
#define SYSTRACE_ENETRESET 52
#define SYSTRACE_ECONNABORTED 53
#define SYSTRACE_ECONNRESET 54
#define SYSTRACE_ENOBUFS 55
#define SYSTRACE_EISCONN 56
#define SYSTRACE_ENOTCONN 57
#define SYSTRACE_ESHUTDOWN 58
#define SYSTRACE_ETOOMANYREFS 59
#define SYSTRACE_ETIMEDOUT 60
#define SYSTRACE_ECONNREFUSED 61
#define SYSTRACE_ELOOP 62
#define SYSTRACE_ENAMETOOLONG 63
#define SYSTRACE_EHOSTDOWN 64
#define SYSTRACE_EHOSTUNREACH 65
#define SYSTRACE_ENOTEMPTY 66
#define SYSTRACE_EPROCLIM 67
#define SYSTRACE_EUSERS 68
#define SYSTRACE_EDQUOT 69
#define SYSTRACE_ESTALE 70
#define SYSTRACE_EREMOTE 71
#define SYSTRACE_EBADRPC 72
#define SYSTRACE_ERPCMISMATCH 73
#define SYSTRACE_EPROGUNAVAIL 74
#define SYSTRACE_EPROGMISMATCH 75
#define SYSTRACE_EPROCUNAVAIL 76
#define SYSTRACE_ENOLCK 77
#define SYSTRACE_ENOSYS 78
#define SYSTRACE_EFTYPE 79
#define SYSTRACE_EAUTH 80
#define SYSTRACE_ENEEDAUTH 81
#define SYSTRACE_EIPSEC 82
#define SYSTRACE_ELAST 82
#endif

View File

@ -0,0 +1,151 @@
/* $NetBSD: systrace-error.c,v 1.1 2002/06/17 16:29:10 christos Exp $ */
/* $OpenBSD: systrace-error.c,v 1.1 2002/06/04 17:20:04 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or withou
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyrigh
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyrigh
* 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, BU
* 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 TOR
* (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/cdefs.h>
__RCSID("$NetBSD: systrace-error.c,v 1.1 2002/06/17 16:29:10 christos Exp $");
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/tree.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "intercept.h"
#include "systrace.h"
#include "systrace-errno.h"
struct systrace_error {
char *name;
int errno;
} systrace_errors[] = {
{ "EPERM", SYSTRACE_EPERM },
{ "ENOENT", SYSTRACE_ENOENT },
{ "ESRCH", SYSTRACE_ESRCH },
{ "EINTR", SYSTRACE_EINTR },
{ "EIO", SYSTRACE_EIO },
{ "ENXIO", SYSTRACE_ENXIO },
{ "E2BIG", SYSTRACE_E2BIG },
{ "ENOEXEC", SYSTRACE_ENOEXEC },
{ "EBADF", SYSTRACE_EBADF },
{ "ECHILD", SYSTRACE_ECHILD },
{ "EDEADLK", SYSTRACE_EDEADLK },
{ "ENOMEM", SYSTRACE_ENOMEM },
{ "EACCES", SYSTRACE_EACCES },
{ "EFAULT", SYSTRACE_EFAULT },
{ "ENOTBLK", SYSTRACE_ENOTBLK },
{ "EBUSY", SYSTRACE_EBUSY },
{ "EEXIST", SYSTRACE_EEXIST },
{ "EXDEV", SYSTRACE_EXDEV },
{ "ENODEV", SYSTRACE_ENODEV },
{ "ENOTDIR", SYSTRACE_ENOTDIR },
{ "EISDIR", SYSTRACE_EISDIR },
{ "EINVAL", SYSTRACE_EINVAL },
{ "ENFILE", SYSTRACE_ENFILE },
{ "EMFILE", SYSTRACE_EMFILE },
{ "ENOTTY", SYSTRACE_ENOTTY },
{ "ETXTBSY", SYSTRACE_ETXTBSY },
{ "EFBIG", SYSTRACE_EFBIG },
{ "ENOSPC", SYSTRACE_ENOSPC },
{ "ESPIPE", SYSTRACE_ESPIPE },
{ "EROFS", SYSTRACE_EROFS },
{ "EMLINK", SYSTRACE_EMLINK },
{ "EPIPE", SYSTRACE_EPIPE },
{ "EDOM", SYSTRACE_EDOM },
{ "ERANGE", SYSTRACE_ERANGE },
{ "EAGAIN", SYSTRACE_EAGAIN },
{ "EWOULDBLOCK", SYSTRACE_EWOULDBLOCK },
{ "EINPROGRESS", SYSTRACE_EINPROGRESS },
{ "EALREADY", SYSTRACE_EALREADY },
{ "ENOTSOCK", SYSTRACE_ENOTSOCK },
{ "EDESTADDRREQ", SYSTRACE_EDESTADDRREQ },
{ "EMSGSIZE", SYSTRACE_EMSGSIZE },
{ "EPROTOTYPE", SYSTRACE_EPROTOTYPE },
{ "ENOPROTOOPT", SYSTRACE_ENOPROTOOPT },
{ "EPROTONOSUPPORT", SYSTRACE_EPROTONOSUPPORT },
{ "ESOCKTNOSUPPORT", SYSTRACE_ESOCKTNOSUPPORT },
{ "EOPNOTSUPP", SYSTRACE_EOPNOTSUPP },
{ "EPFNOSUPPORT", SYSTRACE_EPFNOSUPPORT },
{ "EAFNOSUPPORT", SYSTRACE_EAFNOSUPPORT },
{ "EADDRINUSE", SYSTRACE_EADDRINUSE },
{ "EADDRNOTAVAIL", SYSTRACE_EADDRNOTAVAIL },
{ "ENETDOWN", SYSTRACE_ENETDOWN },
{ "ENETUNREACH", SYSTRACE_ENETUNREACH },
{ "ENETRESET", SYSTRACE_ENETRESET },
{ "ECONNABORTED", SYSTRACE_ECONNABORTED },
{ "ECONNRESET", SYSTRACE_ECONNRESET },
{ "ENOBUFS", SYSTRACE_ENOBUFS },
{ "EISCONN", SYSTRACE_EISCONN },
{ "ENOTCONN", SYSTRACE_ENOTCONN },
{ "ESHUTDOWN", SYSTRACE_ESHUTDOWN },
{ "ETOOMANYREFS", SYSTRACE_ETOOMANYREFS },
{ "ETIMEDOUT", SYSTRACE_ETIMEDOUT },
{ "ECONNREFUSED", SYSTRACE_ECONNREFUSED },
{ "ELOOP", SYSTRACE_ELOOP },
{ "ENAMETOOLONG", SYSTRACE_ENAMETOOLONG },
{ "EHOSTDOWN", SYSTRACE_EHOSTDOWN },
{ "EHOSTUNREACH", SYSTRACE_EHOSTUNREACH },
{ "ENOTEMPTY", SYSTRACE_ENOTEMPTY },
{ "EPROCLIM", SYSTRACE_EPROCLIM },
{ "EUSERS", SYSTRACE_EUSERS },
{ "EDQUOT", SYSTRACE_EDQUOT },
{ "ESTALE", SYSTRACE_ESTALE },
{ "EREMOTE", SYSTRACE_EREMOTE },
{ "EBADRPC", SYSTRACE_EBADRPC },
{ "ERPCMISMATCH", SYSTRACE_ERPCMISMATCH },
{ "EPROGUNAVAIL", SYSTRACE_EPROGUNAVAIL },
{ "EPROGMISMATCH", SYSTRACE_EPROGMISMATCH },
{ "EPROCUNAVAIL", SYSTRACE_EPROCUNAVAIL },
{ "ENOLCK", SYSTRACE_ENOLCK },
{ "ENOSYS", SYSTRACE_ENOSYS },
{ "EFTYPE", SYSTRACE_EFTYPE },
{ "EAUTH", SYSTRACE_EAUTH },
{ "ENEEDAUTH", SYSTRACE_ENEEDAUTH },
{ "EIPSEC", SYSTRACE_EIPSEC },
{ "ELAST", SYSTRACE_ELAST },
{ NULL, 0}
};
int
systrace_error_translate(char *name)
{
struct systrace_error *error = systrace_errors;
while (error->name != NULL) {
if (!strcasecmp(error->name, name))
return (error->errno);
error++;
}
return (-1);
}

View File

@ -0,0 +1,190 @@
/* $NetBSD: systrace-translate.c,v 1.1 2002/06/17 16:29:10 christos Exp $ */
/* $OpenBSD: systrace-translate.c,v 1.2 2002/06/04 19:09:45 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: systrace-translate.c,v 1.1 2002/06/17 16:29:10 christos Exp $");
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/tree.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <err.h>
#ifndef __NetBSD__
#include "../../sys/compat/linux/linux_types.h"
#include "../../sys/compat/linux/linux_fcntl.h"
#endif
#include "intercept.h"
#include "systrace.h"
#define FL(w,c) do { \
if (flags & (w)) \
*p++ = (c); \
} while (0)
static int print_oflags(char *, size_t, struct intercept_translate *);
#ifndef __NetBSD__
static int linux_print_oflags(char *, size_t, struct intercept_translate *);
#endif
static int print_modeflags(char *, size_t, struct intercept_translate *);
static int print_number(char *, size_t, struct intercept_translate *);
static int
print_oflags(char *buf, size_t buflen, struct intercept_translate *tl)
{
char str[32], *p;
int flags = (int)tl->trans_addr;
p = str;
switch (flags & O_ACCMODE) {
case O_RDONLY:
strcpy(p, "ro");
break;
case O_WRONLY:
strcpy(p, "wo");
break;
case O_RDWR:
strcpy(p, "rw");
break;
default:
strcpy(p, "--");
break;
}
p += 2;
FL(O_NONBLOCK, 'n');
FL(O_APPEND, 'a');
FL(O_CREAT, 'c');
FL(O_TRUNC, 't');
*p = '\0';
strlcpy(buf, str, buflen);
return (0);
}
#ifndef __NetBSD__
static int
linux_print_oflags(char *buf, size_t buflen, struct intercept_translate *tl)
{
char str[32], *p;
int flags = (int)tl->trans_addr;
p = str;
switch (flags & LINUX_O_ACCMODE) {
case LINUX_O_RDONLY:
strcpy(p, "ro");
break;
case LINUX_O_WRONLY:
strcpy(p, "wo");
break;
case LINUX_O_RDWR:
strcpy(p, "rw");
break;
default:
strcpy(p, "--");
break;
}
p += 2;
FL(LINUX_O_APPEND, 'a');
FL(LINUX_O_CREAT, 'c');
FL(LINUX_O_TRUNC, 't');
*p = '\0';
strlcpy(buf, str, buflen);
return (0);
}
#endif /* !NetBSD */
static int
print_modeflags(char *buf, size_t buflen, struct intercept_translate *tl)
{
int mode = (int)tl->trans_addr;
mode &= 00007777;
snprintf(buf, buflen, "%o", mode);
return (0);
}
static int
print_number(char *buf, size_t buflen, struct intercept_translate *tl)
{
int number = (int)tl->trans_addr;
snprintf(buf, buflen, "%d", number);
return (0);
}
struct intercept_translate oflags = {
"oflags",
NULL, print_oflags,
};
#ifndef __NetBSD__
struct intercept_translate linux_oflags = {
"oflags",
NULL, linux_print_oflags,
};
#endif
struct intercept_translate modeflags = {
"mode",
NULL, print_modeflags,
};
struct intercept_translate uidt = {
"uid",
NULL, print_number,
};
struct intercept_translate gidt = {
"gid",
NULL, print_number,
};
struct intercept_translate fdt = {
"fd",
NULL, print_number,
};

186
bin/systrace/systrace.1 Normal file
View File

@ -0,0 +1,186 @@
.\" $NetBSD: systrace.1,v 1.1 2002/06/17 16:29:11 christos Exp $
.\" $OpenBSD: systrace.1,v 1.16 2002/06/13 00:15:00 provos Exp $
.\"
.\" Copyright 2002 Niels Provos <provos@citi.umich.edu>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Niels Provos.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" Manual page, using -mandoc macros
.\"
.Dd June 3, 2002
.Dt SYSTRACE 1
.Os
.Sh NAME
.Nm systrace
.Nd generates and enforces system call policies
.Sh SYNOPSIS
.Nm systrace
.Op Fl aAitU
.Op Fl g Ar gui
.Op Fl f Ar file
.Op Fl p Ar pid
.Ar command ...
.Sh DESCRIPTION
The
.Nm
utility enforces system call policies for applications by
constraining the application's access to the system.
The policy is generated interactively.
Operations not covered by the policy raise an
alarm and allow an user to refine the currently configured policy.
.Pp
The options are as follows:
.Bl -tag -width Dfxfile
.It Fl a
Enables automatic enforcement of configured policies.
An operation not covered by policy is denied and logged via
.Xr syslog 3 .
.It Fl A
Automatically generate a policy that allows every operation the
application executes.
The created policy functions as a base that can be refined.
.It Fl i
Inherits the policy of the first executed binary to all children.
.It Fl t
Uses text mode to ask for interactive policy generation.
.It Fl U
Ignore user configured policies and use only global system policies.
.It Fl g Ar gui
Specifies an alternative location for the notification user interface.
.It Fl f Ar file
The policies specified in
.Ar file
are added to the policies that
.Nm
knows about.
.It Fl p Ar pid
Specifies the pid of a process that
.Nm
should attach to.
The full path name of the corresponding binary has to be specified
as
.Ar command .
.El
.Pp
.Sh POLICY
The policy is specified via the following grammar:
.Bd -literal -offset 4
filter = expression "then" action errorcode
expression = symbol | "not" expression | "(" expression ")" |
expression "and" expression | expression "or" expression
symbol = string typeoff "match" cmdstring |
string typeoff "eq" cmdstring | string typeoff "neq" cmdstring |
string typeoff "sub" cmdstring | string typeoff "nsub" cmdstring |
string typeoff "inpath" cmdstring | "true"
typeoff = /* empty */ | "[" number "]"
action = "permit" | "deny"
errorcode = /* empty */ | "[" string "]"
.Ed
.Pp
The
.Va cmdstring
is an arbitrary string enclosed with quotation marks.
The
.Va errorcode
is used to return an
.Xr errno 2
value to the system call when using a
.Va deny
action. The value
.Do
inherit
.Dc
has a special meaning when used with a
.Va permit
rule for the
.Va execve
system call.
In that case, the current policy is inherited for the new binary.
.Pp
The filter operations have the following meaning:
.Bl -hang -width Dinpath -offset AAA
.It match
Evaluates to true if file name globbing according to
.Xr fnmatch 3
succeeds.
.It eq
Evaluates to true if the system call argument matches
.Va cmdstring
exactly.
.It neq
This is the logical negation of
.Va eq .
.It sub
Performs a substring match on the system call argument.
.It nsub
This is the logical negation of
.Va sub .
.It inpath
Evaluates to true if the system call argument is a subpath of
.Va cmdstring .
.El
.Pp
Policy entries may contain an appended predicate.
Predicates have the following format:
.Bd -literal -offset 4
", if" {"user", "group"} {"=", "!="} string
.Ed
.Pp
A rule is added to the configured policy only if its predicate
evaluates to true.
.Sh EXAMPLES
An excerpt from a sample
.Xr ls 1
policy might look as follows:
.Bd -literal -offset 4
Policy: /bin/ls, Emulation: native
[...]
native-open: filename eq "$HOME" and oflags sub "ro" then permit
native-fchdir: permit
[...]
native-open: filename eq "/tmp" and oflags sub "ro" then permit
native-stat: permit
native-open: filename match "$HOME/*" and oflags sub "ro" then permit
native-open: filename eq "/etc/pwd.db" and oflags sub "ro" then permit
[...]
native-open: filename eq "/etc" then deny[eperm], if group != wheel
.Ed
.Sh FILES
.Bl -tag -width xHOME/xsystrace -compact
.It Pa /dev/systrace
systrace device
.It Pa /etc/systrace
global systrace policies
.It Pa $HOME/.systrace
user specified policies
.El
.Sh SEE ALSO
.Xr systrace 4
.Sh AUTHORS
The
.Nm
utility has been developed by Niels Provos.

580
bin/systrace/systrace.c Normal file
View File

@ -0,0 +1,580 @@
/* $NetBSD: systrace.c,v 1.1 2002/06/17 16:29:11 christos Exp $ */
/* $OpenBSD: systrace.c,v 1.16 2002/06/12 22:14:51 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: systrace.c,v 1.1 2002/06/17 16:29:11 christos Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/tree.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>
#include <err.h>
#include <errno.h>
#include "intercept.h"
#include "systrace.h"
#include "util.h"
pid_t trpid;
int trfd;
int connected = 0; /* Connected to GUI */
int inherit = 0; /* Inherit policy to childs */
int automatic = 0; /* Do not run interactively */
int allow = 0; /* Allow all and generate */
int userpolicy = 1; /* Permit user defined policies */
char *username = NULL; /* Username in automatic mode */
char cwd[MAXPATHLEN]; /* Current working directory of process */
static short trans_cb(int, pid_t, int, const char *, int, const char *, void *,
int, struct intercept_tlq *, void *);
static short gen_cb(int, pid_t, int, const char *, int, const char *, void *,
int, void *);
static void execres_cb(int, pid_t, int, const char *, const char *, void *);
static void child_handler(int);
static void systrace_initcb(void);
static void usage(void);
static int requestor_start(char *);
static short
trans_cb(int fd, pid_t pid, int policynr,
const char *name, int code, const char *emulation,
void *args, int argsize, struct intercept_tlq *tls, void *cbarg)
{
short action, future;
struct policy *policy;
struct intercept_translate *tl;
struct intercept_pid *ipid;
struct filterq *pflq = NULL;
char output[1024], *p, *line;
int size;
action = ICPOLICY_PERMIT;
if (policynr == -1)
goto out;
if ((policy = systrace_findpolnr(policynr)) == NULL)
errx(1, "%s:%d: find %d", __func__, __LINE__,
policynr);
if ((pflq = systrace_policyflq(policy, emulation, name)) == NULL)
errx(1, "%s:%d: no filter queue", __func__, __LINE__);
ipid = intercept_getpid(pid);
ipid->uflags = 0;
snprintf(output, sizeof(output),
"%s, pid: %d(%d), policy: %s, filters: %d, syscall: %s-%s(%d)",
ipid->name != NULL ? ipid->name : policy->name, pid, policynr,
policy->name, policy->nfilters, emulation, name, code);
p = output + strlen(output);
size = sizeof(output) - strlen(output);
TAILQ_FOREACH(tl, tls, next) {
if (!tl->trans_valid)
break;
line = intercept_translate_print(tl);
if (line != NULL) {
snprintf(p, size, ", %s: %s", tl->name, line);
p = output + strlen(output);
size = sizeof(output) - strlen(output);
}
}
action = filter_evaluate(tls, pflq, &ipid->uflags);
if (action != ICPOLICY_ASK)
goto out;
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
syslog(LOG_WARNING, "user: %s, prog: %s", username, output);
goto out;
}
action = filter_ask(tls, pflq, policynr, emulation, name,
output, &future, &ipid->uflags);
if (future != ICPOLICY_ASK)
systrace_modifypolicy(fd, policynr, name, future);
if (policy->flags & POLICY_DETACHED) {
if (intercept_detach(fd, pid) == -1)
err(1, "intercept_detach");
} else if (action == ICPOLICY_KILL) {
kill(pid, SIGKILL);
action = ICPOLICY_NEVER;
}
out:
return (action);
}
static short
gen_cb(int fd, pid_t pid, int policynr, const char *name, int code,
const char *emulation, void *args, int argsize, void *cbarg)
{
char output[1024];
struct policy *policy;
struct intercept_pid *ipid;
short action = ICPOLICY_PERMIT;
short future;
if (policynr == -1)
goto out;
if ((policy = systrace_findpolnr(policynr)) == NULL)
errx(1, "%s:%d: find %d", __func__, __LINE__,
policynr);
ipid = intercept_getpid(pid);
ipid->uflags = 0;
snprintf(output, sizeof(output),
"%s, pid: %d(%d), policy: %s, filters: %d, syscall: %s-%s(%d), args: %d",
ipid->name != NULL ? ipid->name : policy->name, pid, policynr,
policy->name, policy->nfilters, emulation, name, code, argsize);
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
syslog(LOG_WARNING, "user: %s, prog: %s", username, output);
goto out;
}
action = filter_ask(NULL, NULL, policynr, emulation, name,
output, &future, &ipid->uflags);
if (future != ICPOLICY_ASK)
systrace_modifypolicy(fd, policynr, name, future);
if (policy->flags & POLICY_DETACHED) {
if (intercept_detach(fd, pid) == -1)
err(1, "intercept_detach");
} else if (action == ICPOLICY_KILL) {
kill(pid, SIGKILL);
action = ICPOLICY_NEVER;
}
out:
return (action);
}
static void
execres_cb(int fd, pid_t pid, int policynr, const char *emulation,
const char *name, void *arg)
{
struct policy *policy;
if (policynr != -1) {
struct intercept_pid *ipid;
if (inherit)
return;
ipid = intercept_getpid(pid);
if (ipid->uflags & PROCESS_INHERIT_POLICY)
return;
}
if ((policy = systrace_newpolicy(emulation, name)) == NULL)
goto error;
/* See if this policies runs without interactive feedback */
if (automatic)
policy->flags |= POLICY_UNSUPERVISED;
policynr = policy->policynr;
/* Try to find existing policy in file system */
if (policynr == -1 && TAILQ_FIRST(&policy->prefilters) == NULL)
systrace_addpolicy(name);
if (policy->flags & POLICY_DETACHED) {
if (intercept_detach(fd, pid) == -1)
err(1, "intercept_detach");
return;
}
if (policynr == -1) {
policynr = systrace_newpolicynr(fd, policy);
if (policynr == -1)
goto error;
}
if (intercept_assignpolicy(fd, pid, policynr) == -1)
goto error;
if (TAILQ_FIRST(&policy->prefilters) != NULL)
filter_prepolicy(fd, policy);
return;
error:
kill(pid, SIGKILL);
fprintf(stderr, "Terminating %d: %s\n", pid, name);
}
static void
child_handler(int sig)
{
int s = errno, status;
if (signal(SIGCHLD, child_handler) == SIG_ERR) {
close(trfd);
}
while (wait4(-1, &status, WNOHANG, NULL) > 0)
;
errno = s;
}
#define X(x) if ((x) == -1) \
err(1, "%s:%d: intercept failed", __func__, __LINE__)
static void
systrace_initcb(void)
{
X(intercept_init());
X(intercept_register_gencb(gen_cb, NULL));
#ifdef __NetBSD__
X(intercept_register_sccb("netbsd", "open", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "open", 0));
X(intercept_register_translation("netbsd", "open", 1, &oflags));
X(intercept_register_sccb("netbsd", "connect", trans_cb, NULL));
X(intercept_register_translation("netbsd", "connect", 1,
&ic_translate_connect));
X(intercept_register_sccb("netbsd", "sendto", trans_cb, NULL));
X(intercept_register_translation("netbsd", "sendto", 4,
&ic_translate_connect));
X(intercept_register_sccb("netbsd", "bind", trans_cb, NULL));
X(intercept_register_translation("netbsd", "bind", 1,
&ic_translate_connect));
X(intercept_register_sccb("netbsd", "execve", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "execve", 0));
X(intercept_register_sccb("netbsd", "__stat13", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "__stat13", 0));
X(intercept_register_sccb("netbsd", "__lstat13", trans_cb, NULL));
X(intercept_register_translink("netbsd", "__lstat13", 0));
X(intercept_register_sccb("netbsd", "unlink", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "unlink", 0));
X(intercept_register_sccb("netbsd", "chown", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "chown", 0));
X(intercept_register_translation("netbsd", "chown", 1, &uidt));
X(intercept_register_translation("netbsd", "chown", 2, &gidt));
X(intercept_register_sccb("netbsd", "__posix_chown", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "__posix_chown", 0));
X(intercept_register_translation("netbsd", "__posix_chown", 1, &uidt));
X(intercept_register_translation("netbsd", "__posix_chown", 2, &gidt));
X(intercept_register_sccb("netbsd", "fchown", trans_cb, NULL));
X(intercept_register_translation("netbsd", "fchown", 0, &fdt));
X(intercept_register_translation("netbsd", "fchown", 1, &uidt));
X(intercept_register_translation("netbsd", "fchown", 2, &gidt));
X(intercept_register_sccb("netbsd", "__posix_fchown", trans_cb, NULL));
X(intercept_register_translation("netbsd", "__posix_fchown", 0, &fdt));
X(intercept_register_translation("netbsd", "__posix_fchown", 1, &uidt));
X(intercept_register_translation("netbsd", "__posix_fchown", 2, &gidt));
X(intercept_register_sccb("netbsd", "chmod", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "chmod", 0));
X(intercept_register_translation("netbsd", "chmod", 1, &modeflags));
X(intercept_register_sccb("netbsd", "readlink", trans_cb, NULL));
X(intercept_register_translink("netbsd", "readlink", 0));
X(intercept_register_sccb("netbsd", "chdir", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "chdir", 0));
X(intercept_register_sccb("netbsd", "access", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "access", 0));
X(intercept_register_sccb("netbsd", "mkdir", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "mkdir", 0));
X(intercept_register_sccb("netbsd", "rmdir", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "rmdir", 0));
X(intercept_register_sccb("netbsd", "rename", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "rename", 0));
X(intercept_register_transfn("netbsd", "rename", 1));
X(intercept_register_sccb("netbsd", "__posix_rename", trans_cb, NULL));
X(intercept_register_transfn("netbsd", "__posix_rename", 0));
X(intercept_register_transfn("netbsd", "__posix_rename", 1));
X(intercept_register_sccb("netbsd", "symlink", trans_cb, NULL));
X(intercept_register_transstring("netbsd", "symlink", 0));
X(intercept_register_translink("netbsd", "symlink", 1));
#else
X(intercept_register_sccb("native", "open", trans_cb, NULL));
X(intercept_register_transfn("native", "open", 0));
X(intercept_register_translation("native", "open", 1, &oflags));
X(intercept_register_sccb("native", "connect", trans_cb, NULL));
X(intercept_register_translation("native", "connect", 1,
&ic_translate_connect));
X(intercept_register_sccb("native", "sendto", trans_cb, NULL));
X(intercept_register_translation("native", "sendto", 4,
&ic_translate_connect));
X(intercept_register_sccb("native", "bind", trans_cb, NULL));
X(intercept_register_translation("native", "bind", 1,
&ic_translate_connect));
X(intercept_register_sccb("native", "execve", trans_cb, NULL));
X(intercept_register_transfn("native", "execve", 0));
X(intercept_register_sccb("native", "stat", trans_cb, NULL));
X(intercept_register_transfn("native", "stat", 0));
X(intercept_register_sccb("native", "lstat", trans_cb, NULL));
X(intercept_register_translink("native", "lstat", 0));
X(intercept_register_sccb("native", "unlink", trans_cb, NULL));
X(intercept_register_transfn("native", "unlink", 0));
X(intercept_register_sccb("native", "chown", trans_cb, NULL));
X(intercept_register_transfn("native", "chown", 0));
X(intercept_register_translation("native", "chown", 1, &uidt));
X(intercept_register_translation("native", "chown", 2, &gidt));
X(intercept_register_sccb("native", "fchown", trans_cb, NULL));
X(intercept_register_translation("native", "fchown", 0, &fdt));
X(intercept_register_translation("native", "fchown", 1, &uidt));
X(intercept_register_translation("native", "fchown", 2, &gidt));
X(intercept_register_sccb("native", "chmod", trans_cb, NULL));
X(intercept_register_transfn("native", "chmod", 0));
X(intercept_register_translation("native", "chmod", 1, &modeflags));
X(intercept_register_sccb("native", "readlink", trans_cb, NULL));
X(intercept_register_translink("native", "readlink", 0));
X(intercept_register_sccb("native", "chdir", trans_cb, NULL));
X(intercept_register_transfn("native", "chdir", 0));
X(intercept_register_sccb("native", "access", trans_cb, NULL));
X(intercept_register_transfn("native", "access", 0));
X(intercept_register_sccb("native", "mkdir", trans_cb, NULL));
X(intercept_register_transfn("native", "mkdir", 0));
X(intercept_register_sccb("native", "rmdir", trans_cb, NULL));
X(intercept_register_transfn("native", "rmdir", 0));
X(intercept_register_sccb("native", "rename", trans_cb, NULL));
X(intercept_register_transfn("native", "rename", 0));
X(intercept_register_transfn("native", "rename", 1));
X(intercept_register_sccb("native", "symlink", trans_cb, NULL));
X(intercept_register_transstring("native", "symlink", 0));
X(intercept_register_translink("native", "symlink", 1));
X(intercept_register_sccb("linux", "open", trans_cb, NULL));
X(intercept_register_translink("linux", "open", 0));
X(intercept_register_translation("linux", "open", 1, &linux_oflags));
X(intercept_register_sccb("linux", "stat", trans_cb, NULL));
X(intercept_register_translink("linux", "stat", 0));
X(intercept_register_sccb("linux", "lstat", trans_cb, NULL));
X(intercept_register_translink("linux", "lstat", 0));
X(intercept_register_sccb("linux", "execve", trans_cb, NULL));
X(intercept_register_translink("linux", "execve", 0));
X(intercept_register_sccb("linux", "access", trans_cb, NULL));
X(intercept_register_translink("linux", "access", 0));
X(intercept_register_sccb("linux", "symlink", trans_cb, NULL));
X(intercept_register_transstring("linux", "symlink", 0));
X(intercept_register_translink("linux", "symlink", 1));
X(intercept_register_sccb("linux", "readlink", trans_cb, NULL));
X(intercept_register_translink("linux", "readlink", 0));
X(intercept_register_sccb("linux", "rename", trans_cb, NULL));
X(intercept_register_translink("linux", "rename", 0));
X(intercept_register_translink("linux", "rename", 1));
X(intercept_register_sccb("linux", "mkdir", trans_cb, NULL));
X(intercept_register_translink("linux", "mkdir", 0));
X(intercept_register_sccb("linux", "rmdir", trans_cb, NULL));
X(intercept_register_translink("linux", "rmdir", 0));
X(intercept_register_sccb("linux", "unlink", trans_cb, NULL));
X(intercept_register_translink("linux", "unlink", 0));
X(intercept_register_sccb("linux", "chmod", trans_cb, NULL));
X(intercept_register_translink("linux", "chmod", 0));
X(intercept_register_translation("linux", "chmod", 1, &modeflags));
#endif
X(intercept_register_execcb(execres_cb, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s [-ait] [-g gui] [-f policy] [-p pid] command ...\n",
getprogname());
exit(1);
}
static int
requestor_start(char *path)
{
char *argv[2];
int pair[2];
pid_t pid;
argv[0] = path;
argv[1] = NULL;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
err(1, "socketpair");
pid = fork();
if (pid == -1)
err(1, "fork");
if (pid == 0) {
close(pair[0]);
if (dup2(pair[1], fileno(stdin)) == -1)
err(1, "dup2");
if (dup2(pair[1], fileno(stdout)) == -1)
err(1, "dup2");
setlinebuf(stdout);
close(pair[1]);
execvp(path, argv);
err(1, "execvp: %s", path);
}
close(pair[1]);
if (dup2(pair[0], fileno(stdin)) == -1)
err(1, "dup2");
if (dup2(pair[0], fileno(stdout)) == -1)
err(1, "dup2");
close(pair[0]);
setlinebuf(stdout);
connected = 1;
return (0);
}
int
main(int argc, char **argv)
{
int i, c;
char **args;
char *filename = NULL;
char *guipath = _PATH_XSYSTRACE;
pid_t pidattach = 0;
int usex11 = 1;
while ((c = getopt(argc, argv, "aAitUg:f:p:")) != -1) {
switch (c) {
case 'a':
automatic = 1;
break;
case 'A':
allow = 1;
break;
case 'i':
inherit = 1;
break;
case 'g':
guipath = optarg;
break;
case 'f':
filename = optarg;
break;
case 'p':
if ((pidattach = atoi(optarg)) == 0) {
warnx("bad pid: %s", optarg);
usage();
}
break;
case 't':
usex11 = 0;
break;
case 'U':
userpolicy = 0;
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (argc == 0 || (pidattach && *argv[0] != '/'))
usage();
/* Username for automatic mode, and policy predicates */
username = uid_to_name(getuid());
/* Determine current working directory for filtering */
if (getcwd(cwd, sizeof(cwd)) == NULL)
err(1, "getcwd");
if (signal(SIGCHLD, child_handler) == SIG_ERR)
err(1, "signal");
/* Local initalization */
systrace_initpolicy(filename);
systrace_initcb();
if ((trfd = intercept_open()) == -1)
exit(1);
if (pidattach == 0) {
/* Run a command and attach to it */
if ((args = malloc((argc + 1) * sizeof(char *))) == NULL)
err(1, "malloc");
for (i = 0; i < argc; i++)
args[i] = argv[i];
args[i] = NULL;
trpid = intercept_run(trfd, args[0], args);
if (trpid == -1)
err(1, "fork");
if (intercept_attach(trfd, trpid) == -1)
err(1, "attach");
if (kill(trpid, SIGCONT) == -1)
err(1, "kill");
} else {
/* Attach to a running command */
if (intercept_attachpid(trfd, pidattach, argv[0]) == -1)
err(1, "attachpid");
}
/* Start the policy gui if necessary */
if (usex11 && !automatic && !allow)
requestor_start(guipath);
while (intercept_read(trfd) != -1)
if (!intercept_existpids())
break;
if (userpolicy)
systrace_dumppolicy();
close(trfd);
exit(0);
}

135
bin/systrace/systrace.h Normal file
View File

@ -0,0 +1,135 @@
/* $NetBSD: systrace.h,v 1.1 2002/06/17 16:29:11 christos Exp $ */
/* $OpenBSD: systrace.h,v 1.5 2002/06/07 18:05:20 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYSTRACE_H_
#define _SYSTRACE_H_
#include <sys/queue.h>
#define _PATH_XSYSTRACE "/usr/X11R6/bin/xsystrace"
enum logicop { LOGIC_AND, LOGIC_OR, LOGIC_NOT, LOGIC_SINGLE };
struct logic {
enum logicop op;
struct logic *left;
struct logic *right;
char *type;
int typeoff;
void *filterdata;
size_t filterlen;
int (*filter_match)(struct intercept_translate *, struct logic *);
};
struct filter {
TAILQ_ENTRY(filter) next;
TAILQ_ENTRY(filter) policy_next;
char *rule;
char name[32];
char emulation[16];
struct logic *logicroot;
short match_action;
int match_error;
int match_flags;
int match_count; /* Number of times this filter matched */
};
TAILQ_HEAD(filterq, filter);
struct policy_syscall {
SPLAY_ENTRY(policy_syscall) node;
char name[64];
char emulation[16];
struct filterq flq;
};
struct policy {
SPLAY_ENTRY(policy) node;
SPLAY_ENTRY(policy) nrnode;
const char *name;
char emulation[16];
SPLAY_HEAD(syscalltree, policy_syscall) pflqs;
int policynr;
int flags;
struct filterq filters;
int nfilters;
struct filterq prefilters;
};
#define POLICY_PATH "/etc/systrace"
#define POLICY_UNSUPERVISED 0x01 /* Auto-Pilot */
#define POLICY_DETACHED 0x02 /* Ignore this program */
#define POLICY_CHANGED 0x04
#define PROCESS_INHERIT_POLICY 0x01 /* Process inherits policy */
int systrace_initpolicy(char *);
struct policy *systrace_newpolicy(const char *, const char *);
int systrace_newpolicynr(int, struct policy *);
int systrace_modifypolicy(int, int, const char *, short);
struct policy *systrace_findpolicy(const char *);
struct policy *systrace_findpolnr(int);
int systrace_dumppolicy(void);
int systrace_readpolicy(char *);
int systrace_addpolicy(const char *);
struct filterq *systrace_policyflq(struct policy *, const char *, const char *);
int systrace_error_translate(char *);
short filter_evaluate(struct intercept_tlq *, struct filterq *, int *);
short filter_ask(struct intercept_tlq *, struct filterq *, int, const char *,
const char *, char *, short *, int *);
void filter_free(struct filter *);
int filter_parse_simple(char *, short *, short *);
int filter_parse(char *, struct filter **);
int filter_prepolicy(int, struct policy *);
char *filter_expand(char *data);
int parse_filter(char *, struct filter **);
extern struct intercept_translate oflags;
extern struct intercept_translate modeflags;
extern struct intercept_translate fdt;
extern struct intercept_translate uidt;
extern struct intercept_translate gidt;
extern struct intercept_translate linux_oflags;
#endif /* _SYSTRACE_H_ */

669
bin/systrace/tree.h Normal file
View File

@ -0,0 +1,669 @@
/* $NetBSD: tree.h,v 1.1 2002/06/17 16:29:11 christos Exp $ */
/* $OpenBSD: tree.h,v 1.4 2002/03/26 02:47:28 hugh Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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 _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
\
static __inline void \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return; \
} \
(head)->sph_root = (elm); \
} \
\
static __inline void \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return; \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
} \
} \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
void name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root))) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-back tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
RB_AUGMENT(RB_PARENT(elm, field)); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
RB_AUGMENT(RB_PARENT(elm, field)); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
void name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct name *, struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)))\
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)))\
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
void \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *old = elm, *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
struct type * \
name##_RB_NEXT(struct name *head, struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(x, y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(head, x))
#endif /* _SYS_TREE_H_ */

232
bin/systrace/util.c Normal file
View File

@ -0,0 +1,232 @@
/* $NetBSD: util.c,v 1.1 2002/06/17 16:29:12 christos Exp $ */
/* $OpenBSD: util.c,v 1.5 2002/06/09 05:27:50 todd Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: util.c,v 1.1 2002/06/17 16:29:12 christos Exp $");
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <pwd.h>
#include "util.h"
char *
strrpl(char *str, size_t size, char *match, char *value)
{
char *p, *e;
int len, rlen;
p = str;
e = p + strlen(p);
len = strlen(match);
/* Try to match against the variable */
while ((p = strchr(p, match[0])) != NULL) {
if (!strncmp(p, match, len) && !isalnum(p[len]))
break;
p += len;
if (p >= e)
return (NULL);
}
if (p == NULL)
return (NULL);
rlen = strlen(value);
if (strlen(str) - len + rlen > size)
return (NULL);
memmove(p + rlen, p + len, strlen(p + len) + 1);
memcpy(p, value, rlen);
return (p);
}
char *
uid_to_name(uid_t uid)
{
static char buf[128];
struct passwd *pw;
if ((pw = getpwuid(uid)) == NULL)
snprintf(buf, sizeof(buf), "uid %d", uid);
else
snprintf(buf, sizeof(buf), "%s", pw->pw_name);
return (buf);
}
/* simplify_path is from pdksh and apparently in the public domain */
/* ISABSPATH() means path is fully and completely specified,
* ISROOTEDPATH() means a .. as the first component is a no-op,
* ISRELPATH() means $PWD can be tacked on to get an absolute path.
*
* OS Path ISABSPATH ISROOTEDPATH ISRELPATH
* unix /foo yes yes no
* unix foo no no yes
* unix ../foo no no yes
* os2+cyg a:/foo yes yes no
* os2+cyg a:foo no no no
* os2+cyg /foo no yes no
* os2+cyg foo no no yes
* os2+cyg ../foo no no yes
* cyg //foo yes yes no
*/
#ifdef OS2
# define PATHSEP ';'
# define DIRSEP '/' /* even though \ is native */
# define DIRSEPSTR "\\"
# define ISDIRSEP(c) ((c) == '\\' || (c) == '/')
# define ISABSPATH(s) (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])))
# define ISROOTEDPATH(s) (ISDIRSEP((s)[0]) || ISABSPATH(s))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
# define FILECHCONV(c) (isascii(c) && isupper(c) ? tolower(c) : c)
# define FILECMP(s1, s2) stricmp(s1, s2)
# define FILENCMP(s1, s2, n) strnicmp(s1, s2, n)
extern char *ksh_strchr_dirsep(const char *path);
extern char *ksh_strrchr_dirsep(const char *path);
# define chdir _chdir2
# define getcwd _getcwd2
#else
# define PATHSEP ':'
# define DIRSEP '/'
# define DIRSEPSTR "/"
# define ISDIRSEP(c) ((c) == '/')
#ifdef __CYGWIN__
# define ISABSPATH(s) \
(((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])) || ISDIRSEP((s)[0]))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
#else /* __CYGWIN__ */
# define ISABSPATH(s) ISDIRSEP((s)[0])
# define ISRELPATH(s) (!ISABSPATH(s))
#endif /* __CYGWIN__ */
# define ISROOTEDPATH(s) ISABSPATH(s)
# define FILECHCONV(c) c
# define FILECMP(s1, s2) strcmp(s1, s2)
# define FILENCMP(s1, s2, n) strncmp(s1, s2, n)
# define ksh_strchr_dirsep(p) strchr(p, DIRSEP)
# define ksh_strrchr_dirsep(p) strrchr(p, DIRSEP)
#endif
/* simplify_path is from pdksh */
/*
* Simplify pathnames containing "." and ".." entries.
* ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
*/
void
simplify_path(path)
char *path;
{
char *cur;
char *t;
int isrooted;
char *very_start = path;
char *start;
if (!*path)
return;
if ((isrooted = ISROOTEDPATH(path)))
very_start++;
#if defined (OS2) || defined (__CYGWIN__)
if (path[0] && path[1] == ':') /* skip a: */
very_start += 2;
#endif /* OS2 || __CYGWIN__ */
/* Before After
* /foo/ /foo
* /foo/../../bar /bar
* /foo/./blah/.. /foo
* . .
* .. ..
* ./foo foo
* foo/../../../bar ../../bar
* OS2 and CYGWIN:
* a:/foo/../.. a:/
* a:. a:
* a:.. a:..
* a:foo/../../blah a:../blah
*/
#ifdef __CYGWIN__
/* preserve leading double-slash on pathnames (for UNC paths) */
if (path[0] && ISDIRSEP(path[0]) && path[1] && ISDIRSEP(path[1]))
very_start++;
#endif /* __CYGWIN__ */
for (cur = t = start = very_start; ; ) {
/* treat multiple '/'s as one '/' */
while (ISDIRSEP(*t))
t++;
if (*t == '\0') {
if (cur == path)
/* convert empty path to dot */
*cur++ = '.';
*cur = '\0';
break;
}
if (t[0] == '.') {
if (!t[1] || ISDIRSEP(t[1])) {
t += 1;
continue;
} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
if (!isrooted && cur == start) {
if (cur != very_start)
*cur++ = DIRSEP;
*cur++ = '.';
*cur++ = '.';
start = cur;
} else if (cur != start)
while (--cur > start && !ISDIRSEP(*cur))
;
t += 2;
continue;
}
}
if (cur != very_start)
*cur++ = DIRSEP;
/* find/copy next component of pathname */
while (*t && !ISDIRSEP(*t))
*cur++ = *t++;
}
}

36
bin/systrace/util.h Normal file
View File

@ -0,0 +1,36 @@
/* $NetBSD: util.h,v 1.1 2002/06/17 16:29:12 christos Exp $ */
/* $OpenBSD: parse.y,v 1.4 2002/06/05 17:22:38 mickey Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void simplify_path(char *);
char *uid_to_name(uid_t);
char *strrpl(char *, size_t, char *, char *);