Index: policy.c =================================================================== RCS file: /cvsroot/src/bin/systrace/policy.c,v retrieving revision 1.15 diff -u -p -r1.15 policy.c --- policy.c 2003/08/01 05:42:48 1.15 +++ policy.c 2003/09/29 11:55:52 @@ -50,6 +50,8 @@ __RCSID("$NetBSD: policy.c,v 1.15 2003/0 #include "intercept.h" #include "systrace.h" +extern int erratic; + static int psccompare(struct policy_syscall *, struct policy_syscall *); static int policycompare(struct policy *, struct policy *); static int polnrcompare(struct policy *, struct policy *); @@ -579,8 +581,14 @@ systrace_policyprocess(struct policy *po snprintf(line, sizeof(line), "true then %s", rule); rule = line; } - } else if (filter_parse_simple(rule, &action, &future) == 0) - resolved = 1; + } else if (filter_parse_simple(rule, &action, &future) == 0) { + if (erratic) { + /* Need to make a real policy out of it */ + snprintf(line, sizeof(line), "true then %s", rule); + rule = line; + } else + resolved = 1; + } /* For now, everything that does not seem to be a valid syscall * does not get fast kernel policies even though the aliasing @@ -690,6 +698,7 @@ systrace_writepolicy(struct policy *poli char tmpname[2*MAXPATHLEN]; char finalname[2*MAXPATHLEN]; struct filter *filter; + short action, future; if ((p = systrace_policyfilename(policydir, policy->name)) == NULL) return (-1); @@ -717,8 +726,15 @@ systrace_writepolicy(struct policy *poli filter->emulation, filter->name, filter->rule); } TAILQ_FOREACH(filter, &policy->filters, policy_next) { + if (erratic && + !strncmp(filter->rule, "true then ", 10)) { + p = filter->rule + 10; + if (filter_parse_simple(p, &action, &future)) + p = filter->rule; + } else + p = filter->rule; fprintf(fp, "\t%s-%s: %s\n", - filter->emulation, filter->name, filter->rule); + filter->emulation, filter->name, p); } } fprintf(fp, "\n"); Index: systrace.1 =================================================================== RCS file: /cvsroot/src/bin/systrace/systrace.1,v retrieving revision 1.25 diff -u -p -r1.25 systrace.1 --- systrace.1 2003/08/20 01:28:44 1.25 +++ systrace.1 2003/09/29 11:55:52 @@ -39,12 +39,13 @@ .Nd generate and enforce system call policies .Sh SYNOPSIS .Nm systrace -.Op Fl AaitUu +.Op Fl AaiktUu .Op Fl c Ar uid:gid .Op Fl d Ar policydir .Op Fl f Ar file .Op Fl g Ar gui .Op Fl p Ar pid +.Op Fl r Ar chance Ns Op Ar -seed .Ar command ... .Sh DESCRIPTION The @@ -108,6 +109,11 @@ knows about. 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 k +When used in conjunction with +.Fl a , +operations not covered by policy result in the process being killed +after the operation has been logged. .It Fl p Ar pid Specifies the pid of a process that .Nm @@ -115,6 +121,15 @@ should attach to. The full path name of the corresponding binary has to be specified as .Ar command . +.It Fl r Ar chance Ns Op Ar -seed +Randomly cause operations to fail with a probability of one in +.Ar chance . +.Pp +.Ar seed +specifies the initial conditions for the random number generator used. +By specifying the same +.Ar seed +for multiple invocations, test cases may be reproduced. .It Fl t Uses text mode to ask for interactive policy generation. .It Fl U Index: systrace.c =================================================================== RCS file: /cvsroot/src/bin/systrace/systrace.c,v retrieving revision 1.23 diff -u -p -r1.23 systrace.c --- systrace.c 2003/08/25 09:12:46 1.23 +++ systrace.c 2003/09/29 11:55:52 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,8 @@ int allow = 0; /* Allow all and genera int userpolicy = 1; /* Permit user defined policies */ int noalias = 0; /* Do not do system call aliasing */ int iamroot = 0; /* Set if we are running as root */ +int auto_kill = 0; /* Kill process when policy is violated */ +int erratic = 0; /* Probability of artificial syscall denial */ char cwd[MAXPATHLEN]; /* Current working directory */ char home[MAXPATHLEN]; /* Home directory of user */ char username[LOGIN_NAME_MAX]; /* Username: predicate match and expansion */ @@ -68,6 +71,8 @@ char username[LOGIN_NAME_MAX]; /* Userna static void child_handler(int); static void usage(void); static int requestor_start(char *); +static int erratic_failure(short *); +static void seed_erratic(char *); void systrace_parameters(void) @@ -156,12 +161,14 @@ trans_cb(int fd, pid_t pid, int policynr const char *binname = NULL; char output[_POSIX2_LINE_MAX]; pid_t ppid; - int dolog = 0; action = ICPOLICY_PERMIT; if (policynr == -1) - goto out; + return (action); + + if (erratic && erratic_failure(&action)) + return (action); if ((policy = systrace_findpolnr(policynr)) == NULL) errx(1, "%s:%d: find %d", __func__, __LINE__, @@ -218,8 +225,10 @@ trans_cb(int fd, pid_t pid, int policynr if (policy->flags & POLICY_UNSUPERVISED) { action = ICPOLICY_NEVER; - dolog = 1; - goto out; + ipid->uflags |= SYSCALL_LOG; + if (auto_kill) + action = ICPOLICY_KILL; + goto done; } action = filter_ask(fd, tls, pflq, policynr, emulation, name, @@ -231,22 +240,20 @@ trans_cb(int fd, pid_t pid, int policynr if (intercept_detach(fd, pid) == -1) err(1, "intercept_detach"); return (action); - } else if (action == ICPOLICY_KILL) { - kill(pid, SIGKILL); - return (ICPOLICY_NEVER); } done: /* Log the result if requested */ if (ipid->uflags & SYSCALL_LOG) - dolog = 1; - - out: - if (dolog) syslog(LOG_WARNING, "%s user: %s, prog: %s", - action < ICPOLICY_NEVER ? "permit" : "deny", + action < ICPOLICY_KILL ? "permit" : "deny", ipid->username, output); + if (action == ICPOLICY_KILL) { + kill(pid, SIGKILL); + return (ICPOLICY_NEVER); + } + /* Argument replacement in intercept might still fail */ return (action); @@ -262,11 +269,14 @@ gen_cb(int fd, pid_t pid, int policynr, struct filterq *pflq = NULL; short action = ICPOLICY_PERMIT; short future; - int len, off, dolog = 0; + int len, off; if (policynr == -1) - goto out; + return (action); + if (erratic && erratic_failure(&action)) + return (action); + if ((policy = systrace_findpolnr(policynr)) == NULL) errx(1, "%s:%d: find %d", __func__, __LINE__, policynr); @@ -290,16 +300,15 @@ gen_cb(int fd, pid_t pid, int policynr, action = filter_evaluate(NULL, pflq, ipid); - if (ipid->uflags & SYSCALL_LOG) - dolog = 1; - if (action != ICPOLICY_ASK) - goto out; + goto done; if (policy->flags & POLICY_UNSUPERVISED) { action = ICPOLICY_NEVER; - dolog = 1; - goto out; + ipid->uflags |= SYSCALL_LOG; + if (auto_kill) + action = ICPOLICY_KILL; + goto done; } action = filter_ask(fd, NULL, pflq, policynr, emulation, name, @@ -310,16 +319,19 @@ gen_cb(int fd, pid_t pid, int policynr, if (policy->flags & POLICY_DETACHED) { if (intercept_detach(fd, pid) == -1) err(1, "intercept_detach"); - } else if (action == ICPOLICY_KILL) { - kill(pid, SIGKILL); - return (ICPOLICY_NEVER); } - out: - if (dolog) + + done: + if (ipid->uflags & SYSCALL_LOG) syslog(LOG_WARNING, "%s user: %s, prog: %s", - action < ICPOLICY_NEVER ? "permit" : "deny", + action < ICPOLICY_KILL ? "permit" : "deny", ipid->username, output); + if (action == ICPOLICY_KILL) { + kill(pid, SIGKILL); + return (ICPOLICY_NEVER); + } + return (action); } @@ -394,6 +406,18 @@ policyfree_cb(int policynr, void *arg) systrace_freepolicy(policy); } +static int +erratic_failure(short *action) +{ + short errnos[] = { EPERM, EINTR, EINVAL, EAGAIN, ENOENT }; + + if (!(random() % erratic)) { + *action = errnos[random()%(sizeof(errnos)/sizeof(errnos[0]))]; + return 1; + } + return 0; +} + static void child_handler(int sig) { @@ -413,8 +437,8 @@ static void usage(void) { fprintf(stderr, - "Usage: systrace [-AaitUu] [-c uid:gid] [-d policydir] [-f file]\n" - "\t [-g gui] [-p pid] command ...\n"); + "Usage: systrace [-AaiktUu] [-c uid:gid] [-d policydir] [-f file]\n" + "\t [-g gui] [-p pid] [-r chance[-seed]] command ...\n"); exit(1); } @@ -513,6 +537,35 @@ get_uid_gid(const char *argument, uid_t return (0); } +static void +seed_erratic(char *p) +{ + struct timeval tv; + unsigned long seed; + char *ep; + + erratic = strtoul(p, &ep, 10); + if (errno == ERANGE && erratic == ULONG_MAX) { + err(1, "invalid chance '%s'", p); + } else if (*ep == '\0') { + (void) gettimeofday(&tv, NULL); + seed = getpid() ^ tv.tv_sec ^ (tv.tv_usec << 1); + } else if (*ep == '-') { + ep++; + if (*ep == '\0') + errx(1, "%s: number expected after - is missing", p); + p = ep; + seed = strtoul(p, &ep, 10); + if (*ep != '\0') + errx(1, "could not parse seed"); + if (errno == ERANGE && seed == ULONG_MAX) + err(1, "invalid seed '%s'", p); + } else + errx(1, "unknown trailing characters in `chance'"); + + srandom(seed); +} + int main(int argc, char **argv) { @@ -529,7 +582,7 @@ main(int argc, char **argv) uid_t cr_uid; gid_t cr_gid; - while ((c = getopt(argc, argv, "c:aAituUd:g:f:p:")) != -1) { + while ((c = getopt(argc, argv, "c:aAiktuUd:g:f:p:r:")) != -1) { switch (c) { case 'c': setcredentials = 1; @@ -555,6 +608,9 @@ main(int argc, char **argv) case 'i': inherit = 1; break; + case 'k': + auto_kill = 1; + break; case 'g': guipath = optarg; break; @@ -568,6 +624,9 @@ main(int argc, char **argv) warnx("bad pid: %s", optarg); usage(); } + break; + case 'r': + seed_erratic(optarg); break; case 't': usex11 = 0;