summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorSebastien Marie <semarie@cvs.openbsd.org>2015-08-24 09:21:11 +0000
committerSebastien Marie <semarie@cvs.openbsd.org>2015-08-24 09:21:11 +0000
commit7de616c4841228754c8c50047f5035869004c614 (patch)
tree8de1e3a8330e885f2c3b40a91a2d34f1346abd5f /regress
parenta0f40112b4aa873c64555c2e71250a82a8cf1589 (diff)
add new (extensible) testsuite for tame(2)
Diffstat (limited to 'regress')
-rw-r--r--regress/sys/kern/tame/generic/Makefile21
-rw-r--r--regress/sys/kern/tame/generic/actions.c102
-rw-r--r--regress/sys/kern/tame/generic/actions.h29
-rw-r--r--regress/sys/kern/tame/generic/main.c138
-rw-r--r--regress/sys/kern/tame/generic/manager.c286
-rw-r--r--regress/sys/kern/tame/generic/parse_tame.c88
-rw-r--r--regress/sys/kern/tame/generic/tests.out23
7 files changed, 687 insertions, 0 deletions
diff --git a/regress/sys/kern/tame/generic/Makefile b/regress/sys/kern/tame/generic/Makefile
new file mode 100644
index 00000000000..dd65596b3f9
--- /dev/null
+++ b/regress/sys/kern/tame/generic/Makefile
@@ -0,0 +1,21 @@
+# $OpenBSD: Makefile,v 1.1 2015/08/24 09:21:10 semarie Exp $
+PROG= generic
+SRCS+= main.c manager.c parse_tame.c actions.c
+NOMAN= yes
+
+CFLAGS+= -Wall
+
+REGRESS_TARGETS+= test_normal test_systrace
+REGRESS_SKIP_TARGETS+= test_systrace
+
+test_normal: ${PROG}
+ env LD_BIND_NOW=1 ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
+
+test_systrace: ${PROG}
+ env LD_BIND_NOW=1 systrace -A ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
+
+regenerate: ${PROG}
+ echo '# $$OpenBSD: Makefile,v 1.1 2015/08/24 09:21:10 semarie Exp $$' > ${.CURDIR}/tests.out
+ env LD_BIND_NOW=1 ./${PROG} | tee -a ${.CURDIR}/tests.out
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/kern/tame/generic/actions.c b/regress/sys/kern/tame/generic/actions.c
new file mode 100644
index 00000000000..9d41a905c7c
--- /dev/null
+++ b/regress/sys/kern/tame/generic/actions.c
@@ -0,0 +1,102 @@
+/* $OpenBSD: actions.c,v 1.1 2015/08/24 09:21:10 semarie Exp $ */
+/*
+ * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "actions.h"
+
+int
+execute_action(action_t action, va_list opts)
+{
+ errno = 0;
+
+ switch (action) {
+ case AC_EXIT:
+ /* should be catched by manager.c (before been here) */
+ _exit(ENOTSUP);
+ /* NOTREACHED */
+
+ case AC_KILL:
+ kill(0, SIGINT);
+ break;
+
+ case AC_INET:
+ socket(AF_INET, SOCK_STREAM, 0);
+ break;
+
+ case AC_TAME:
+ tame(va_arg(opts, int), NULL);
+ break;
+
+ case AC_ALLOWED_SYSCALLS:
+ clock_getres(CLOCK_MONOTONIC, NULL);
+ clock_gettime(CLOCK_MONOTONIC, NULL);
+ /* fchdir(); */
+ getdtablecount();
+ getegid();
+ geteuid();
+ getgid();
+ getgroups(0, NULL);
+ getitimer(ITIMER_REAL, NULL);
+ getlogin();
+ getpgid(0);
+ getpgrp();
+ getpid();
+ getppid();
+ /* getresgid(); */
+ /* getresuid(); */
+ { struct rlimit rl; getrlimit(RLIMIT_CORE, &rl); }
+ getsid(0);
+ getthrid();
+ { struct timeval tp; gettimeofday(&tp, NULL); }
+ getuid();
+ geteuid();
+ issetugid();
+ /* nanosleep(); */
+ /* sigreturn(); */
+ umask(0000);
+ /* wait4(); */
+
+ break;
+
+ case AC_OPENFILE_RDONLY:
+ {
+ const char *filename = va_arg(opts, const char *);
+ int fd = open(filename, O_RDONLY);
+ if (fd != -1)
+ close(fd);
+ }
+ break;
+ }
+
+ return (errno);
+}
diff --git a/regress/sys/kern/tame/generic/actions.h b/regress/sys/kern/tame/generic/actions.h
new file mode 100644
index 00000000000..17b9e1fb2fa
--- /dev/null
+++ b/regress/sys/kern/tame/generic/actions.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: actions.h,v 1.1 2015/08/24 09:21:10 semarie Exp $ */
+/*
+ * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _ACTIONS_H_
+#define _ACTIONS_H_
+
+typedef enum {
+ AC_EXIT,
+ AC_KILL,
+ AC_INET,
+ AC_TAME,
+ AC_ALLOWED_SYSCALLS,
+ AC_OPENFILE_RDONLY,
+} action_t;
+
+#endif /* _ACTIONS_H_ */
diff --git a/regress/sys/kern/tame/generic/main.c b/regress/sys/kern/tame/generic/main.c
new file mode 100644
index 00000000000..273494d6226
--- /dev/null
+++ b/regress/sys/kern/tame/generic/main.c
@@ -0,0 +1,138 @@
+/* $OpenBSD: main.c,v 1.1 2015/08/24 09:21:10 semarie Exp $ */
+/*
+ * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/tame.h>
+
+#include <err.h>
+#include <stdlib.h>
+
+#include "actions.h"
+
+void start_test(int *ret, int ntest, int flags, const char *paths[], ...);
+
+#define start_test1(ret,ntest,flags,path,...) \
+ do { \
+ const char *_paths[] = {path, NULL}; \
+ start_test(ret,ntest,flags,_paths,__VA_ARGS__); \
+ } while (0)
+
+
+int
+main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ if (argc != 1)
+ errx(1, "usage: %s", argv[0]);
+
+ /* check for env */
+ if (getenv("LD_BIND_NOW") == NULL)
+ errx(1, "should use LD_BIND_NOW=1 in env");
+
+ /*
+ * testsuite
+ */
+
+ /* _exit is always allowed, and nothing else under flags=0 */
+ start_test(&ret, 1, 0, NULL, AC_EXIT);
+ start_test(&ret, 2, 0, NULL, AC_INET, AC_EXIT);
+
+ /* test coredump */
+ start_test(&ret, 3, TAME_ABORT, NULL, AC_INET, AC_EXIT);
+
+ /* inet under inet is ok */
+ start_test(&ret, 4, TAME_INET, NULL, AC_INET, AC_EXIT);
+
+ /* kill under inet is forbidden */
+ start_test(&ret, 5, TAME_INET, NULL, AC_KILL, AC_EXIT);
+
+ /* kill under proc is allowed */
+ start_test(&ret, 6, TAME_PROC, NULL, AC_KILL, AC_EXIT);
+
+ /* tests several permitted syscalls */
+ start_test(&ret, 7, TAME_DNS, NULL, AC_ALLOWED_SYSCALLS, AC_EXIT);
+ start_test(&ret, 8, TAME_INET, NULL, AC_ALLOWED_SYSCALLS, AC_EXIT);
+
+ /* these TAME_* don't have "permitted syscalls" */
+ // XXX it is a documentation bug
+ start_test(&ret, 9, TAME_PROC, NULL, AC_ALLOWED_SYSCALLS, AC_EXIT);
+
+ /*
+ * test absolute whitelist path
+ */
+ /* without wpaths */
+ start_test(&ret, 10, TAME_RPATH, NULL,
+ AC_OPENFILE_RDONLY, "/etc/passwd",
+ AC_EXIT);
+ /* exact match */
+ start_test1(&ret, 11, TAME_RPATH, "/etc/passwd",
+ AC_OPENFILE_RDONLY, "/etc/passwd",
+ AC_EXIT);
+ /* subdir match */
+ start_test1(&ret, 12, TAME_RPATH, "/etc/",
+ AC_OPENFILE_RDONLY, "/etc/passwd",
+ AC_EXIT);
+ /* same without trailing '/' */
+ start_test1(&ret, 13, TAME_RPATH, "/etc",
+ AC_OPENFILE_RDONLY, "/etc/passwd",
+ AC_EXIT);
+ /* failing one */
+ start_test1(&ret, 14, TAME_RPATH, "/bin",
+ AC_OPENFILE_RDONLY, "/etc/passwd",
+ AC_EXIT);
+
+ /*
+ * test relative whitelist path
+ */
+ /* without wpaths */
+ start_test(&ret, 15, TAME_RPATH, NULL,
+ AC_OPENFILE_RDONLY, "generic",
+ AC_EXIT);
+ /* exact match */
+ start_test1(&ret, 16, TAME_RPATH, "generic",
+ AC_OPENFILE_RDONLY, "generic",
+ AC_EXIT);
+ /* subdir match */
+ start_test1(&ret, 17, TAME_RPATH, "./",
+ AC_OPENFILE_RDONLY, "generic",
+ AC_EXIT);
+ /* same without trailing '/' */
+ start_test1(&ret, 18, TAME_RPATH, ".",
+ AC_OPENFILE_RDONLY, "generic",
+ AC_EXIT);
+ /* failing one */
+ start_test1(&ret, 19, TAME_RPATH, ".",
+ AC_OPENFILE_RDONLY, "../../../../../../../../../../../../../../../etc/passwd",
+ AC_EXIT);
+
+ /* tame: test reducing flags */
+ start_test1(&ret, 20, TAME_RPATH | TAME_WPATH, NULL,
+ AC_TAME, TAME_RPATH,
+ AC_EXIT);
+
+ /* tame: test adding flags */
+ start_test1(&ret, 21, TAME_RPATH, NULL,
+ AC_TAME, TAME_RPATH | TAME_WPATH,
+ AC_EXIT);
+
+ /* tame: test replacing flags */
+ start_test1(&ret, 22, TAME_RPATH, NULL,
+ AC_TAME, TAME_WPATH,
+ AC_EXIT);
+
+ return (ret);
+}
diff --git a/regress/sys/kern/tame/generic/manager.c b/regress/sys/kern/tame/generic/manager.c
new file mode 100644
index 00000000000..235c9a8983e
--- /dev/null
+++ b/regress/sys/kern/tame/generic/manager.c
@@ -0,0 +1,286 @@
+/* $OpenBSD: manager.c,v 1.1 2015/08/24 09:21:10 semarie Exp $ */
+/*
+ * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/syslimits.h>
+#include <sys/tame.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "actions.h"
+
+extern char *__progname;
+
+int parse_flags(char *);
+int execute_action(action_t, va_list);
+
+static const char *
+coredump_name()
+{
+ static char coredump[PATH_MAX] = "";
+
+ if (*coredump)
+ return (coredump);
+
+ if (strlcpy(coredump, __progname, sizeof(coredump)) >= sizeof(coredump))
+ errx(1, "coredump: strlcpy");
+
+ if (strlcat(coredump, ".core", sizeof(coredump)) >= sizeof(coredump))
+ errx(1, "coredump: strlcat");
+
+ return (coredump);
+}
+
+
+static int
+check_coredump()
+{
+ const char *coredump = coredump_name();
+ int fd;
+
+ if ((fd = open(coredump, O_RDONLY)) == -1) {
+ if (errno == ENOENT)
+ return (1); /* coredump not found */
+ else
+ return (-1); /* error */
+ }
+
+ (void)close(fd);
+ return (0); /* coredump found */
+}
+
+
+static int
+clear_coredump(int *ret, int ntest)
+{
+ int saved_errno = errno;
+ int u;
+
+ if (((u = unlink(coredump_name())) != 0) && (errno != ENOENT)) {
+ warn("test(%d): clear_coredump", ntest);
+ *ret = EXIT_FAILURE;
+ return (-1);
+ }
+ errno = saved_errno;
+
+ return (0);
+}
+
+
+static int
+grab_syscall(pid_t pid)
+{
+ int ret = -1;
+ char *search = NULL;
+ int searchlen;
+ FILE *fd;
+ char line[1024];
+ char *end;
+
+ /* build searched string */
+ if ((searchlen = asprintf(&search, "%s(%d): syscall ", __progname, pid))
+ <= 0)
+ goto out;
+
+ /* call dmesg */
+ if ((fd = popen("/sbin/dmesg", "r")) == NULL)
+ goto out;
+
+ /* search the string */
+ while (1) {
+ /* read a line */
+ fgets(line, sizeof(line), fd);
+
+ /* error checking */
+ if (ferror(fd)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* quit */
+ if (feof(fd))
+ break;
+
+ /* strip trailing '\n' */
+ end = strchr(line, '\n');
+ if (*end == '\n')
+ *end = '\0';
+
+ /* check if found */
+ if (strncmp(search, line, searchlen) == 0) {
+ const char *errstr = NULL;
+ /* found */
+ ret = strtonum(line + searchlen, 0, 255, &errstr);
+ if (errstr) {
+ warn("strtonum: line=%s err=%s", line, errstr);
+ return (-1);
+ }
+ }
+ }
+
+ /* cleanup */
+ if (pclose(fd) == -1)
+ goto out;
+
+ /* not found */
+ if (ret == -1)
+ ret = 0;
+
+out:
+ free(search);
+ return (ret);
+}
+
+
+void
+start_test(int *ret, int ntest, int flags, char *paths[], ...)
+{
+ static int ntest_check = 0;
+ pid_t pid;
+ int status;
+ va_list ap;
+ action_t action;
+ int i;
+
+#ifndef DEBUG
+ /* check ntest (useful for dev) */
+ if (ntest != ++ntest_check)
+ errx(EXIT_FAILURE,
+ "invalid test number: should be %d but is %d",
+ ntest_check, ntest);
+#endif /* DEBUG */
+
+ /* unlink previous coredump (if exists) */
+ if (clear_coredump(ret, ntest) == -1)
+ return;
+
+ /* fork and launch the test */
+ switch (pid = fork()) {
+ case -1:
+ warn("test(%d) fork", ntest);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0:
+ /* create a new session (for AC_KILL) */
+ setsid();
+
+ /* XXX redirect output to /dev/null ? */
+ if (tame(flags, paths) != 0)
+ err(errno, "tame");
+
+ va_start(ap, paths);
+ while ((action = va_arg(ap, action_t)) != AC_EXIT) {
+ execute_action(action, ap);
+ if (errno != 0)
+ _exit(errno);
+ }
+ va_end(ap);
+
+ _exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+ }
+
+ /* wait for test to terminate */
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EAGAIN)
+ continue;
+ warn("test(%d): waitpid", ntest);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ /* show status and details */
+ printf("test(%d): tame=(0x%x,{", ntest, flags);
+ for (i = 0; paths && paths[i] != NULL; i++)
+ printf("\"%s\",", paths[i]);
+ printf("NULL}) status=%d", status);
+
+ if (WIFCONTINUED(status))
+ printf(" continued");
+
+ if (WIFEXITED(status)) {
+ int e = WEXITSTATUS(status);
+ printf(" exit=%d", e);
+ if (e > 0 && e <= ELAST)
+ printf(" (errno: \"%s\")", strerror(e));
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signal = WTERMSIG(status);
+ printf(" signal=%d", signal);
+
+ /* check if core file is really here ? */
+ if (WCOREDUMP(status)) {
+ int coredump = check_coredump();
+
+ switch(coredump) {
+ case -1: /* error */
+ warn("test(%d): check_coredump", ntest);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0: /* found */
+ printf(" coredump=present");
+ break;
+
+ case 1: /* not found */
+ printf(" coredump=absent");
+ break;
+
+ default:
+ warnx("test(%d): unknown coredump code %d",
+ ntest, coredump);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ }
+
+ /* grab tamed syscall from dmesg */
+ if ((signal == SIGKILL) || (signal = SIGABRT)) {
+ int syscall = grab_syscall(pid);
+ switch (syscall) {
+ case -1: /* error */
+ warn("test(%d): grab_syscall pid=%d", ntest,
+ pid);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0: /* not found */
+ printf(" tamed_syscall=not_found");
+ break;
+
+ default:
+ printf(" tamed_syscall=%d", syscall);
+ }
+ }
+ }
+
+ if (WIFSTOPPED(status))
+ printf(" stop=%d", WSTOPSIG(status));
+
+ printf("\n");
+}
diff --git a/regress/sys/kern/tame/generic/parse_tame.c b/regress/sys/kern/tame/generic/parse_tame.c
new file mode 100644
index 00000000000..b11113bafc2
--- /dev/null
+++ b/regress/sys/kern/tame/generic/parse_tame.c
@@ -0,0 +1,88 @@
+/* $OpenBSD: parse_tame.c,v 1.1 2015/08/24 09:21:10 semarie Exp $ */
+/*
+ * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/tame.h>
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define tameflag(x) { #x, x }
+
+/* list of defined TAME_ flags */
+struct {
+ char *name;
+ int flag;
+} flags_list[] = {
+ tameflag(TAME_MALLOC),
+ tameflag(TAME_RW),
+ tameflag(TAME_STDIO),
+ tameflag(TAME_RPATH),
+ tameflag(TAME_WPATH),
+ tameflag(TAME_TMPPATH),
+ tameflag(TAME_INET),
+ tameflag(TAME_UNIX),
+ tameflag(TAME_CMSG),
+ tameflag(TAME_DNS),
+ tameflag(TAME_IOCTL),
+ tameflag(TAME_GETPW),
+ tameflag(TAME_PROC),
+ tameflag(TAME_CPATH),
+ tameflag(TAME_ABORT),
+ { NULL, 0 },
+};
+
+
+int
+parse_flags(char *str)
+{
+ int flags = 0;
+ char *current = str;
+ char *next = str;
+ int i;
+
+ if (str == NULL || *str == '\0')
+ return (0);
+
+ while (next) {
+ /* get only the current word */
+ next = strchr(current, ',');
+ if (next == '\0')
+ next = NULL;
+ else
+ *next = '\0';
+
+ /* search word in flags_list */
+ for (i = 0; (flags_list[i].name != NULL)
+ && (strcmp(current, flags_list[i].name) != 0); i++);
+
+ if (flags_list[i].name != NULL) {
+ if (flags & flags_list[i].flag)
+ errx(1, "parse_flags: flag already setted: %s",
+ flags_list[i].name);
+ else
+ flags |= flags_list[i].flag;
+ } else
+ errx(1, "parse_flags: unknown flag: %s", current);
+
+ /* advance to next word */
+ if (next)
+ current = next + 1;
+ }
+
+ return (flags);
+}
diff --git a/regress/sys/kern/tame/generic/tests.out b/regress/sys/kern/tame/generic/tests.out
new file mode 100644
index 00000000000..2e447205287
--- /dev/null
+++ b/regress/sys/kern/tame/generic/tests.out
@@ -0,0 +1,23 @@
+# $OpenBSD: tests.out,v 1.1 2015/08/24 09:21:10 semarie Exp $
+test(1): tame=(0x0,{NULL}) status=0 exit=0
+test(2): tame=(0x0,{NULL}) status=9 signal=9 tamed_syscall=97
+test(3): tame=(0x8000000,{NULL}) status=134 signal=6 coredump=present tamed_syscall=97
+test(4): tame=(0x83,{NULL}) status=0 exit=0
+test(5): tame=(0x83,{NULL}) status=9 signal=9 tamed_syscall=37
+test(6): tame=(0x1000,{NULL}) status=2 signal=2 tamed_syscall=not_found
+test(7): tame=(0xd,{NULL}) status=0 exit=0
+test(8): tame=(0x83,{NULL}) status=0 exit=0
+test(9): tame=(0x1000,{NULL}) status=9 signal=9 tamed_syscall=89
+test(10): tame=(0x13,{NULL}) status=0 exit=0
+test(11): tame=(0x13,{"/etc/passwd",NULL}) status=0 exit=0
+test(12): tame=(0x13,{"/etc/",NULL}) status=0 exit=0
+test(13): tame=(0x13,{"/etc",NULL}) status=0 exit=0
+test(14): tame=(0x13,{"/bin",NULL}) status=512 exit=2 (errno: "No such file or directory")
+test(15): tame=(0x13,{NULL}) status=0 exit=0
+test(16): tame=(0x13,{"generic",NULL}) status=0 exit=0
+test(17): tame=(0x13,{"./",NULL}) status=0 exit=0
+test(18): tame=(0x13,{".",NULL}) status=0 exit=0
+test(19): tame=(0x13,{".",NULL}) status=512 exit=2 (errno: "No such file or directory")
+test(20): tame=(0x33,{NULL}) status=0 exit=0
+test(21): tame=(0x13,{NULL}) status=256 exit=1 (errno: "Operation not permitted")
+test(22): tame=(0x13,{NULL}) status=256 exit=1 (errno: "Operation not permitted")