diff options
-rw-r--r-- | bin/systrace/filter.c | 34 | ||||
-rw-r--r-- | bin/systrace/intercept.c | 5 | ||||
-rw-r--r-- | bin/systrace/lex.l | 3 | ||||
-rw-r--r-- | bin/systrace/openbsd-syscalls.c | 6 | ||||
-rw-r--r-- | bin/systrace/parse.y | 12 | ||||
-rw-r--r-- | bin/systrace/policy.c | 4 | ||||
-rw-r--r-- | bin/systrace/register.c | 5 | ||||
-rw-r--r-- | bin/systrace/systrace-translate.c | 16 | ||||
-rw-r--r-- | bin/systrace/systrace.1 | 117 | ||||
-rw-r--r-- | bin/systrace/systrace.c | 67 | ||||
-rw-r--r-- | bin/systrace/systrace.h | 3 |
11 files changed, 178 insertions, 94 deletions
diff --git a/bin/systrace/filter.c b/bin/systrace/filter.c index 1d9c10255a7..d26961bdd72 100644 --- a/bin/systrace/filter.c +++ b/bin/systrace/filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filter.c,v 1.27 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: filter.c,v 1.28 2003/07/19 11:48:57 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -182,6 +182,7 @@ filter_evaluate(struct intercept_tlq *tls, struct filterq *fls, /* Profile feedback optimization */ filter->match_count++; if (last != NULL && last->match_action == action && + last->match_flags == filter->match_flags && filter->match_count > last->match_count) { TAILQ_REMOVE(fls, last, next); TAILQ_INSERT_AFTER(fls, filter, last, next); @@ -492,10 +493,9 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, struct filter *filter; struct policy *policy; short action; - int first = 1, isalias; + int first = 1, isalias, isprompt = 0; *pfuture = ICPOLICY_ASK; - icpid->uflags = 0; isalias = systrace_find_reverse(emulation, name) != NULL; @@ -543,6 +543,11 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, } while (1) { + /* Special policy active that allows only yes or no */ + if (icpid->uflags & PROCESS_PROMPT) { + fprintf(stderr, "isprompt\n"); + isprompt = 1; + } filter = NULL; if (!allow) { @@ -557,7 +562,7 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, } if (fgets(line, sizeof(line), stdin) == NULL) - errx(1, "EOF"); + errx(1, "EOF on policy input request"); p = line; strsep(&p, "\n"); } else if (!first) { @@ -608,6 +613,9 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, } if (filter_parse_simple(line, &action, pfuture) != -1) { + /* Yes or no, no in-kernel policy allowed */ + if (isprompt) + *pfuture = ICPOLICY_ASK; if (*pfuture == ICPOLICY_ASK) goto out; /* We have a policy decision */ @@ -621,16 +629,32 @@ filter_ask(int fd, struct intercept_tlq *tls, struct filterq *fls, snprintf(line, sizeof(line), "true then %s", compose); } + if (isprompt) { + printf("Answer only \"permit\" or \"deny\". " + "This is a prompt.\n"); + continue; + } + if (fls == NULL) { printf("Syntax error.\n"); continue; } - if (filter_parse(line, &filter) == -1) + if (filter_parse(line, &filter) == -1) { + printf("Parse error.\n"); continue; + } TAILQ_INSERT_TAIL(fls, filter, next); action = filter_evaluate(tls, fls, icpid); + + /* If we get a prompt flag here, we ask again */ + if (icpid->uflags & PROCESS_PROMPT) { + filter_policyrecord(policy, filter, emulation, name, line); + printf("Answer only \"permit\" or \"deny\". " + "This is a prompt.\n"); + continue; + } if (action == ICPOLICY_ASK) { TAILQ_REMOVE(fls, filter, next); printf("Filter unmatched. Freeing it\n"); diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c index e1bf867753d..bb4e9edd317 100644 --- a/bin/systrace/intercept.c +++ b/bin/systrace/intercept.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept.c,v 1.40 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: intercept.c,v 1.41 2003/07/19 11:48:57 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -613,6 +613,7 @@ intercept_filename(int fd, pid_t pid, void *addr, int userp) errx(1, "cwd too long"); } + /* Need concatenated path for simplifypath */ if (havecwd && name[0] != '/') { if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd)) goto error; @@ -718,7 +719,7 @@ intercept_syscall(int fd, pid_t pid, u_int16_t seqnr, int policynr, flags = 0; icpid = intercept_getpid(pid); - + /* Special handling for the exec call */ if (!strcmp(name, "execve")) { void *addr; diff --git a/bin/systrace/lex.l b/bin/systrace/lex.l index 6369e737236..7e20e0cc4e4 100644 --- a/bin/systrace/lex.l +++ b/bin/systrace/lex.l @@ -1,4 +1,4 @@ -/* $OpenBSD: lex.l,v 1.14 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: lex.l,v 1.15 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> @@ -72,6 +72,7 @@ int quoteescape; %} %% +ask { return ASK; } deny { return DENY; } permit { return PERMIT; } and { return AND; } diff --git a/bin/systrace/openbsd-syscalls.c b/bin/systrace/openbsd-syscalls.c index 4cba9bcad71..99b4ec201db 100644 --- a/bin/systrace/openbsd-syscalls.c +++ b/bin/systrace/openbsd-syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openbsd-syscalls.c,v 1.19 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: openbsd-syscalls.c,v 1.20 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -352,7 +352,7 @@ obsd_translate_errno(int nerrno) } static int -obsd_answer(int fd, pid_t pid, u_int32_t seqnr, short policy, int errno, +obsd_answer(int fd, pid_t pid, u_int32_t seqnr, short policy, int nerrno, short flags, struct elevate *elevate) { struct systrace_answer ans; @@ -362,7 +362,7 @@ obsd_answer(int fd, pid_t pid, u_int32_t seqnr, short policy, int errno, ans.stra_seqnr = seqnr; ans.stra_policy = obsd_translate_policy(policy); ans.stra_flags = obsd_translate_flags(flags); - ans.stra_error = obsd_translate_errno(errno); + ans.stra_error = obsd_translate_errno(nerrno); if (elevate != NULL) { if (elevate->e_flags & ELEVATE_UID) { diff --git a/bin/systrace/parse.y b/bin/systrace/parse.y index 8173b8dce94..fdf401122a8 100644 --- a/bin/systrace/parse.y +++ b/bin/systrace/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.14 2003/05/29 00:39:12 itojun Exp $ */ +/* $OpenBSD: parse.y,v 1.15 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> @@ -66,7 +66,7 @@ extern int iamroot; %} -%token AND OR NOT LBRACE RBRACE LSQBRACE RSQBRACE THEN MATCH PERMIT DENY +%token AND OR NOT LBRACE RBRACE LSQBRACE RSQBRACE THEN MATCH PERMIT DENY ASK %token EQ NEQ TRUE SUB NSUB INPATH LOG COMMA IF USER GROUP EQUAL NEQUAL AS %token COLON RE LESSER GREATER %token <string> STRING @@ -121,6 +121,10 @@ fullexpression : expression THEN action errorcode logcode elevate predicate if ($5) flags |= SYSCALL_LOG; + /* Special policy that allows only yes or no */ + if ($3 == ICPOLICY_ASK) + flags |= PROCESS_PROMPT; + if ($4 != NULL) free($4); @@ -445,6 +449,10 @@ action : PERMIT { $$ = ICPOLICY_PERMIT; } + | ASK +{ + $$ = ICPOLICY_ASK; +} | DENY { $$ = ICPOLICY_NEVER; diff --git a/bin/systrace/policy.c b/bin/systrace/policy.c index 1f94338d567..72c7f685c12 100644 --- a/bin/systrace/policy.c +++ b/bin/systrace/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.28 2003/06/19 06:26:19 pvalchev Exp $ */ +/* $OpenBSD: policy.c,v 1.29 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -129,7 +129,7 @@ systrace_setupdir(char *path) if (!(sb.st_mode & S_IFDIR)) errx(1, "Not a directory: \"%s\"", policydir); } else if (mkdir(policydir, 0700) == -1) - err(1, "mdkdir(%s)", policydir); + err(1, "mkdir(%s)", policydir); } int diff --git a/bin/systrace/register.c b/bin/systrace/register.c index c21b7296491..c85ccb05719 100644 --- a/bin/systrace/register.c +++ b/bin/systrace/register.c @@ -1,4 +1,4 @@ -/* $OpenBSD: register.c,v 1.15 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: register.c,v 1.16 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -151,6 +151,9 @@ systrace_initcb(void) X(intercept_register_sccb("native", "socket", trans_cb, NULL)); intercept_register_translation("native", "socket", 0, &ic_sockdom); intercept_register_translation("native", "socket", 1, &ic_socktype); + X(intercept_register_sccb("native", "kill", trans_cb, NULL)); + intercept_register_translation("native", "kill", 0, &ic_pidname); + intercept_register_translation("native", "kill", 1, &ic_signame); X(intercept_register_sccb("linux", "open", trans_cb, NULL)); tl = intercept_register_translink("linux", "open", 0); diff --git a/bin/systrace/systrace-translate.c b/bin/systrace/systrace-translate.c index 959a459aece..a40291b5ebe 100644 --- a/bin/systrace/systrace-translate.c +++ b/bin/systrace/systrace-translate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace-translate.c,v 1.16 2003/04/14 02:13:30 deraadt Exp $ */ +/* $OpenBSD: systrace-translate.c,v 1.17 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -262,12 +262,14 @@ print_pidname(char *buf, size_t buflen, struct intercept_translate *tl) struct intercept_pid *icpid; pid_t pid = (intptr_t)tl->trans_addr; - icpid = intercept_getpid(pid); - snprintf(buf, buflen, "%s", - icpid->name != NULL ? icpid->name : "<unknown>"); - - if (icpid->name == NULL) - intercept_freepid(pid); + if (pid != 0) { + icpid = intercept_getpid(pid); + snprintf(buf, buflen, "%s", + icpid->name != NULL ? icpid->name : "<unknown>"); + if (icpid->name == NULL) + intercept_freepid(pid); + } else + strlcpy(buf, "<own process group>", buflen); return (0); } diff --git a/bin/systrace/systrace.1 b/bin/systrace/systrace.1 index 09e057addfc..5dc55a8d915 100644 --- a/bin/systrace/systrace.1 +++ b/bin/systrace/systrace.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: systrace.1,v 1.33 2003/05/29 00:39:12 itojun Exp $ +.\" $OpenBSD: systrace.1,v 1.34 2003/07/19 11:48:58 sturm Exp $ .\" .\" Copyright 2002 Niels Provos <provos@citi.umich.edu> .\" All rights reserved. @@ -30,7 +30,7 @@ .\" .\" Manual page, using -mandoc macros .\" -.Dd June 3, 2002 +.Dd May 21, 2003 .Dt SYSTRACE 1 .Os .Sh NAME @@ -38,15 +38,13 @@ .Nd generate and enforce system call policies .Sh SYNOPSIS .Nm systrace -.Bk -words -.Op Fl aAituU +.Op Fl AaitUu +.Op Fl c Ar uid:gid .Op Fl d Ar policydir -.Op Fl g Ar gui .Op Fl f Ar file -.Op Fl c Ar uid:gid +.Op Fl g Ar gui .Op Fl p Ar pid .Ar command ... -.Ek .Sh DESCRIPTION The .Nm @@ -65,63 +63,50 @@ system calls require root privilege. .Pp The access policy can be generated interactively or obtained from a policy file. -Interactive policy generation will be performed by the ``notification -user agent'', normally +Interactive policy generation will be performed by the +.Dq notification user agent , +normally .Xr xsystrace 1 , unless text mode is specified via .Fl t . .Pp -When running in ``automatic enforcement'' mode, -operations not covered by the policy raise an alarm and +When running in +.Dq automatic enforcement +mode, 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 u -Do not perform aliasing on system call names. -Aliasing is enabled by default to group similar system calls into a -single compound name. -For example, system calls that read from the file system -like -.Fn lstat -and -.Fn access -are translated to -.Fn fsread . -.It Fl i -Inherits the policy - child processes inherit policy of the parent binary. -.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 d Ar policydir -Specifies an alternative location for the user's directory from -which policies are loaded and to which changed policies are stored. -.It Fl g Ar gui -Specifies an alternative location for the notification user interface. +.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 c Ar uid:gid Specifies the .Va uid and .Va gid that the monitored application should be executed with, -which must be specified as non-negative integers (not as names). +which must be specified as nonnegative integers (not as names). This is useful in conjunction with privilege elevation and requires root privilege. +.It Fl d Ar policydir +Specifies an alternative location for the user's directory from +which policies are loaded and to which changed policies are stored. .It Fl f Ar file The policies specified in .Ar file are added to the policies that .Nm knows about. +.It Fl g Ar gui +Specifies an alternative location for the notification user interface. +.It Fl i +Inherits the policy - child processes inherit policy of the parent binary. .It Fl p Ar pid Specifies the pid of a process that .Nm @@ -129,10 +114,24 @@ should attach to. The full path name of the corresponding binary has to be specified as .Ar command . +.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 u +Do not perform aliasing on system call names. +Aliasing is enabled by default to group similar system calls into a +single compound name. +For example, system calls that read from the file system like +.Fn lstat +and +.Fn access +are translated to +.Fn fsread . .El .Ss POLICY The policy is specified via the following grammar: -.Bd -literal -offset AAA +.Bd -literal -offset 4 filter = expression "then" action errorcode logcode expression = symbol | "not" expression | "(" expression ")" | expression "and" expression | expression "or" expression @@ -142,7 +141,7 @@ symbol = string typeoff "match" cmdstring | string typeoff "inpath" cmdstring | string typeoff "re" cmdstring | "true" typeoff = /* empty */ | "[" number "]" -action = "permit" | "deny" +action = "permit" | "deny" | "ask" errorcode = /* empty */ | "[" string "]" logcode = /* empty */ | "log" .Ed @@ -168,7 +167,7 @@ detach have special meanings when used with a .Va permit rule for the -.Xr execve 2 +.Va execve system call. When using .Do @@ -183,9 +182,14 @@ detach, detaches from a process after successfully completing the -.Xr execve 2 +.Va execve system call. .Pp +The +.Va ask +action specifies that the user should be prompted for a decision +every time that the rule matches. +.Pp The filter operations have the following meaning: .Bl -hang -width Dinpath -offset AAA .It match @@ -215,28 +219,25 @@ the specified regular expression. By appending the .Va log statement to a rule, a matching system call and its arguments -are logged to +is logged to .Xr syslog 3 . This is useful, for example, to log all invocations of the -.Xr execve 2 +.Va execve system call. .Pp Policy entries may contain an appended predicate. Predicates have the following format: -.Bd -literal -offset AAA -", if" {"user", "group"} {"=", "!=", "<", ">" } {number, string} +.Bd -literal -offset 4 +", if" {"user", "group"} {"=", "!=", "\*[Lt]", "\*[Gt]" } {number, string} .Ed .Pp A rule is added to the configured policy only if its predicate evaluates to true. .Pp -The environment variables -.Ev $HOME , $USER -and -.Ev $CWD -are substituted in rules. -Comments, begun by an unquoted '#' character and -continuing to the end of the line, are ignored. +The environment variables $HOME, $USER and $CWD are substituted in rules. +Comments, begun by an unquoted +.Sq \&# +character and continuing to the end of the line, are ignored. .Sh PRIVILEGE ELEVATION With .Nm @@ -260,7 +261,7 @@ in a policy to elevate the privileges for the matching system call: .Bd -literal -offset 4 as user as user:group -as group +as :group .Ed .Pp The effective @@ -269,9 +270,9 @@ and .Va gid are elevated only for the duration of the system call, and are restored to the old values afterwards (except for the -.Xr seteuid 2 -and -.Xr setegid 2 +.Va seteuid +or +.Va setegid system calls). .Sh FILES .Bl -tag -width xHOME/xsystrace -compact @@ -287,7 +288,7 @@ replaced by the underscore character. An excerpt from a sample .Xr ls 1 policy might look as follows: -.Bd -literal -offset AAA +.Bd -literal -offset 4 Policy: /bin/ls, Emulation: native [...] native-fsread: filename eq "$HOME" then permit diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c index 9b5bd1c2be2..a5e5bdb8244 100644 --- a/bin/systrace/systrace.c +++ b/bin/systrace/systrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.c,v 1.43 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: systrace.c,v 1.44 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -44,6 +44,7 @@ #include <string.h> #include <err.h> #include <errno.h> +#include <grp.h> #include <pwd.h> #include "intercept.h" @@ -297,7 +298,7 @@ gen_cb(int fd, pid_t pid, int policynr, const char *name, int code, goto out; } - action = filter_ask(fd, NULL, NULL, policynr, emulation, name, + action = filter_ask(fd, NULL, pflq, policynr, emulation, name, output, &future, ipid); if (future != ICPOLICY_ASK) systrace_modifypolicy(fd, policynr, name, future); @@ -408,8 +409,8 @@ static void usage(void) { fprintf(stderr, - "Usage: systrace [-aAituU] [-d poldir] [-g gui] [-f policy]\n" - "\t [-c uid:gid] [-p pid] command ...\n"); + "Usage: systrace [-AaitUu] [-c uid:gid] [-d policydir] [-f file]\n" + "\t [-g gui] [-p pid] command ...\n"); exit(1); } @@ -460,6 +461,54 @@ requestor_start(char *path) return (0); } +static int +get_uid_gid(const char *argument, uid_t *uid, gid_t *gid) +{ + struct group *gp; + struct passwd *pw; + unsigned long ulval; + char uid_gid_str[128]; + char *endp, *g, *u; + + strlcpy(uid_gid_str, argument, sizeof(uid_gid_str)); + g = uid_gid_str; + u = strsep(&g, ":"); + + if ((pw = getpwnam(u)) != NULL) { + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + *uid = pw->pw_uid; + *gid = pw->pw_gid; + /* Ok if group not specified. */ + if (g == NULL) + return (0); + } else { + errno = 0; + ulval = strtoul(u, &endp, 10); + if (u[0] == '\0' || *endp != '\0') + errx(1, "no such user '%s'", u); + if (errno == ERANGE && ulval == ULONG_MAX) + errx(1, "invalid uid %s", u); + *uid = (uid_t)ulval; + } + + if (g == NULL) + return (-1); + + if ((gp = getgrnam(g)) != NULL) + *gid = gp->gr_gid; + else { + errno = 0; + ulval = strtoul(g, &endp, 10); + if (g[0] == '\0' || *endp != '\0') + errx(1, "no such group '%s'", g); + if (errno == ERANGE && ulval == ULONG_MAX) + errx(1, "invalid gid %s", g); + *gid = (gid_t)ulval; + } + + return (0); +} + int main(int argc, char **argv) { @@ -467,7 +516,7 @@ main(int argc, char **argv) char **args; char *filename = NULL; char *policypath = NULL; - char *guipath = _PATH_XSYSTRACE, *p; + char *guipath = _PATH_XSYSTRACE; struct timeval tv, tv_wait = {60, 0}; pid_t pidattach = 0; int usex11 = 1, count; @@ -479,14 +528,8 @@ main(int argc, char **argv) while ((c = getopt(argc, argv, "c:aAituUd:g:f:p:")) != -1) { switch (c) { case 'c': - p = strsep(&optarg, ":"); - if (optarg == NULL || *optarg == '\0') - usage(); setcredentials = 1; - cr_uid = atoi(p); - cr_gid = atoi(optarg); - - if (cr_uid <= 0 || cr_gid <= 0) + if (get_uid_gid(optarg, &cr_uid, &cr_gid) == -1) usage(); break; case 'a': diff --git a/bin/systrace/systrace.h b/bin/systrace/systrace.h index 9b676afcaef..99b5e819b49 100644 --- a/bin/systrace/systrace.h +++ b/bin/systrace/systrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.h,v 1.22 2003/06/16 06:36:40 itojun Exp $ */ +/* $OpenBSD: systrace.h,v 1.23 2003/07/19 11:48:58 sturm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -129,6 +129,7 @@ TAILQ_HEAD(tmplqueue, template); #define PROCESS_INHERIT_POLICY 0x01 /* Process inherits policy */ #define PROCESS_DETACH 0x02 /* Process gets detached */ #define SYSCALL_LOG 0x04 /* Log this system call */ +#define PROCESS_PROMPT 0x08 /* Prompt but nothing else */ void systrace_parameters(void); int systrace_initpolicy(char *, char *); |