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 <sys/wait.h>
#include <sys/tree.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
@@ -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;