Add userland portion of systrace.
This commit is contained in:
parent
581a55332b
commit
5039a9e5ee
@ -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
18
bin/systrace/Makefile
Normal 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
577
bin/systrace/filter.c
Normal 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
40
bin/systrace/filter.h
Normal 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 *);
|
285
bin/systrace/intercept-translate.c
Normal file
285
bin/systrace/intercept-translate.c
Normal 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
566
bin/systrace/intercept.c
Normal 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
155
bin/systrace/intercept.h
Normal 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
113
bin/systrace/lex.l
Normal 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
|
585
bin/systrace/netbsd-syscalls.c
Normal file
585
bin/systrace/netbsd-syscalls.c
Normal 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,
|
||||
};
|
543
bin/systrace/openbsd-syscalls.c
Normal file
543
bin/systrace/openbsd-syscalls.c
Normal 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
329
bin/systrace/parse.y
Normal 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
560
bin/systrace/policy.c
Normal 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);
|
||||
}
|
122
bin/systrace/systrace-errno.h
Normal file
122
bin/systrace/systrace-errno.h
Normal 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
|
151
bin/systrace/systrace-error.c
Normal file
151
bin/systrace/systrace-error.c
Normal 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);
|
||||
}
|
190
bin/systrace/systrace-translate.c
Normal file
190
bin/systrace/systrace-translate.c
Normal 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
186
bin/systrace/systrace.1
Normal 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
580
bin/systrace/systrace.c
Normal 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
135
bin/systrace/systrace.h
Normal 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
669
bin/systrace/tree.h
Normal 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
232
bin/systrace/util.c
Normal 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
36
bin/systrace/util.h
Normal 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 *);
|
Loading…
x
Reference in New Issue
Block a user