--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2015/10/09 06:44:13 semarie Exp $
+
+SUBDIR += sigabrt
+SUBDIR += sigkill
+SUBDIR += generic
+
+.include <bsd.subdir.mk>
--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2015/10/09 06:44:13 semarie Exp $
+PROG= generic
+SRCS+= main.c manager.c
+NOMAN= yes
+
+CFLAGS+= -Wall -Werror
+
+REGRESS_TARGETS+= test_normal test_systrace
+REGRESS_SKIP_TARGETS+= test_systrace
+
+test_normal: ${PROG}
+ ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
+
+test_systrace: ${PROG}
+ systrace -A ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
+
+regenerate: ${PROG}
+ echo '# $$OpenBSD: Makefile,v 1.1 2015/10/09 06:44:13 semarie Exp $$' > ${.CURDIR}/tests.out
+ ./${PROG} | tee -a ${.CURDIR}/tests.out
+
+.include <bsd.regress.mk>
--- /dev/null
+/* $OpenBSD: main.c,v 1.1 2015/10/09 06:44:13 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/mman.h>
+#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 <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "manager.h"
+
+static void
+test_nop()
+{
+ /* nop */
+}
+
+static void
+test_inet()
+{
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ int saved_errno = errno;
+ close(fd);
+ errno = saved_errno ? saved_errno : errno;
+}
+
+static void
+test_kill()
+{
+ kill(0, SIGINT);
+}
+
+static void
+test_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(); */
+}
+
+
+static void
+open_close(const char *filename)
+{
+ int fd;
+ int saved_errno;
+
+ errno = 0;
+ printf("\n open_close(\"%s\")", filename);
+ fd = open(filename, O_RDONLY);
+ saved_errno = errno;
+ printf(" fd=%d errno=%d", fd, errno);
+ if (fd != -1)
+ close(fd);
+ errno = saved_errno;
+}
+
+static void
+test_wpaths()
+{
+ /* absolute file */
+ open_close("/etc/passwd");
+
+ /* relative */
+ open_close("generic");
+
+ /* relative */
+ open_close("../../../../../../../../../../../../../../../etc/passwd");
+
+ /* ENOENT */
+ open_close("/nonexistent");
+
+ /* calling exit to flush stdout */
+ printf("\n");
+ exit(EXIT_SUCCESS);
+}
+
+static void
+test_pledge()
+{
+ const char *wpaths[] = { "/sbin", NULL };
+
+ if (pledge("stdio rpath", wpaths) != 0)
+ _exit(errno);
+}
+
+static void
+do_stat(const char *path)
+{
+ char resolved[PATH_MAX];
+ struct stat sb;
+
+ printf("\n stat(\"%s\"):", path);
+
+ /* call realpath(3) */
+ errno = 0;
+ if (realpath(path, resolved) != NULL)
+ printf(" realpath=\"%s\"", resolved);
+ else
+ printf(" realpath=failed(%d)", errno);
+
+ /* call stat(2) */
+ errno = 0;
+ if (stat(path, &sb) == 0)
+ printf(" uid=%d gid=%d mode=%04o", sb.st_uid, sb.st_gid,
+ sb.st_mode);
+ else
+ printf(" errno=%d", errno);
+}
+
+static void
+test_stat()
+{
+ /* in whitelisted path */
+ do_stat("/usr/share/man/man8/afterboot.8");
+ do_stat("/usr/share/man/man8/");
+ do_stat("/usr/share/man");
+
+ /* parent of whitelisted path */
+ do_stat("/usr/share");
+ do_stat("/usr");
+ do_stat("/");
+
+ /* outside whitelisted path */
+ do_stat("/usr/bin/gzip");
+
+ /* calling exit to flush stdout */
+ printf("\n");
+ exit(EXIT_SUCCESS);
+}
+
+static void
+test_mmap()
+{
+ int fd;
+ void * data;
+
+ if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
+ _exit(errno);
+
+ data = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FILE|MAP_SHARED, fd, 0);
+
+ if (data == MAP_FAILED)
+ _exit(errno);
+
+ munmap(data, 4096);
+ close(fd);
+}
+
+static void
+test_rpath()
+{
+ int fd;
+ char data[512];
+
+ if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
+ _exit(errno);
+
+ if (read(fd, data, sizeof(data)) == -1)
+ _exit(errno);
+
+ close(fd);
+}
+
+static void
+test_wpath()
+{
+ int fd;
+ char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+ if ((fd = open("/dev/null", O_WRONLY, 0)) == -1)
+ _exit(errno);
+
+ if (write(fd, data, sizeof(data)) == -1)
+ _exit(errno);
+
+ close(fd);
+}
+
+static void
+test_cpath()
+{
+ const char filename[] = "/tmp/generic-test-cpath";
+
+ if (mkdir(filename, S_IRWXU) == -1)
+ _exit(errno);
+
+ if (rmdir(filename) == -1)
+ _exit(errno);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ if (argc != 1)
+ errx(1, "usage: %s", argv[0]);
+
+ /*
+ * testsuite
+ */
+
+ /* _exit is always allowed, and nothing else under flags=0 */
+ start_test(&ret, "", NULL, test_nop);
+ start_test(&ret, "", NULL, test_inet);
+
+ /* test coredump */
+ start_test(&ret, "abort", NULL, test_inet);
+
+ /* inet under inet is ok */
+ start_test(&ret, "inet", NULL, test_inet);
+
+ /* kill under inet is forbidden */
+ start_test(&ret, "inet", NULL, test_kill);
+
+ /* kill under proc is allowed */
+ start_test(&ret, "proc", NULL, test_kill);
+
+ /* tests PLEDGE_SELF for permitted syscalls */
+ start_test(&ret, "malloc", NULL, test_allowed_syscalls);
+ start_test(&ret, "rw", NULL, test_allowed_syscalls);
+ start_test(&ret, "stdio", NULL, test_allowed_syscalls);
+ start_test(&ret, "rpath", NULL, test_allowed_syscalls);
+ start_test(&ret, "wpath", NULL, test_allowed_syscalls);
+ start_test(&ret, "tmppath", NULL, test_allowed_syscalls);
+ start_test(&ret, "inet", NULL, test_allowed_syscalls);
+ start_test(&ret, "unix", NULL, test_allowed_syscalls);
+ start_test(&ret, "dns", NULL, test_allowed_syscalls);
+ start_test(&ret, "getpw", NULL, test_allowed_syscalls);
+
+ /* tests req without PLEDGE_SELF for "permitted syscalls" */
+ // XXX it is a documentation bug
+ start_test(&ret, "cmsg", NULL, test_allowed_syscalls);
+ start_test(&ret, "ioctl", NULL, test_allowed_syscalls);
+ start_test(&ret, "proc", NULL, test_allowed_syscalls);
+ start_test(&ret, "cpath", NULL, test_allowed_syscalls);
+ start_test(&ret, "abort", NULL, test_allowed_syscalls);
+ start_test(&ret, "fattr", NULL, test_allowed_syscalls);
+
+ start_test(&ret, "rpath", NULL, test_rpath);
+ start_test(&ret, "wpath", NULL, test_wpath);
+ start_test(&ret, "cpath", NULL, test_cpath);
+
+ /*
+ * test whitelist path
+ */
+ start_test(&ret, "stdio rpath", NULL, test_wpaths);
+ start_test1(&ret, "stdio rpath", NULL, test_wpaths);
+ start_test1(&ret, "stdio rpath", "/", test_wpaths);
+ start_test1(&ret, "stdio rpath", "/etc", test_wpaths);
+ start_test1(&ret, "stdio rpath", "/etc/", test_wpaths);
+ start_test1(&ret, "stdio rpath", "/etc/passwd", test_wpaths);
+ // XXX start_test1(&ret, "stdio rpath", "/etc/passwd/", test_wpaths);
+ start_test1(&ret, "stdio rpath", "/bin", test_wpaths);
+ start_test1(&ret, "stdio rpath", "generic", test_wpaths);
+ start_test1(&ret, "stdio rpath", "", test_wpaths);
+ start_test1(&ret, "stdio rpath", ".", test_wpaths);
+
+ /*
+ * test pledge(2) arguments
+ */
+ /* same request */
+ start_test(&ret, "stdio rpath", NULL, test_pledge);
+ /* same request (stdio = malloc rw) */
+ start_test(&ret, "malloc rw rpath", NULL, test_pledge);
+ /* reduce request */
+ start_test(&ret, "stdio rpath wpath", NULL, test_pledge);
+ /* reduce request (with same/other wpaths) */
+ start_test1(&ret, "stdio rpath wpath", "/sbin", test_pledge);
+ start_test1(&ret, "stdio rpath wpath", "/", test_pledge);
+ /* add request */
+ start_test(&ret, "stdio", NULL, test_pledge);
+ /* change request */
+ start_test(&ret, "unix", NULL, test_pledge);
+
+ /* test stat(2) */
+ start_test1(&ret, "stdio rpath", "/usr/share/man", test_stat);
+
+ /* mmap */
+ start_test1(&ret, "rpath malloc prot_exec", "/dev/zero", test_mmap);
+ start_test1(&ret, "rpath malloc", "/dev/zero", test_mmap);
+
+ return (ret);
+}
--- /dev/null
+/* $OpenBSD: manager.c,v 1.1 2015/10/09 06:44:13 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/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>
+
+extern char *__progname;
+
+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, const char *test_name)
+{
+ int saved_errno = errno;
+ int u;
+
+ if (((u = unlink(coredump_name())) != 0) && (errno != ENOENT)) {
+ warn("test(%s): clear_coredump", test_name);
+ *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);
+}
+
+/* mainly stolen from src/bin/cat/cat.c */
+static int
+drainfd(int rfd, int wfd)
+{
+ char buf[1024];
+ ssize_t nr, nw, off;
+
+ while ((nr = read(rfd, buf, sizeof(buf))) != -1 && nr != 0)
+ for (off = 0; nr; nr -= nw, off += nw)
+ if ((nw = write(wfd, buf + off, (size_t)nr)) == 0 ||
+ nw == -1)
+ return (-1);
+ if (nr < 0)
+ return (-1);
+
+ return (0);
+}
+
+void
+_start_test(int *ret, const char *test_name, const char *request,
+ const char *paths[], void (*test_func)(void))
+{
+ int fildes[2];
+ pid_t pid;
+ int status;
+ int i;
+
+ /* early print testname */
+ printf("test(%s): pledge=", test_name);
+ if (request) {
+ printf("(\"%s\",", request);
+ if (paths) {
+ printf("{");
+ for (i = 0; paths[i] != NULL; i++)
+ printf("\"%s\",", paths[i]);
+ printf("NULL})");
+ } else
+ printf("NULL)");
+ } else
+ printf("not-called");
+
+ /* unlink previous coredump (if exists) */
+ if (clear_coredump(ret, test_name) == -1)
+ return;
+
+ /* flush outputs (for STDOUT_FILENO manipulation) */
+ if (fflush(NULL) != 0) {
+ warn("test(%s) fflush", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ /* make pipe to grab output */
+ if (pipe(fildes) != 0) {
+ warn("test(%s) pipe", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ /* fork and launch the test */
+ switch (pid = fork()) {
+ case -1:
+ (void)close(fildes[0]);
+ (void)close(fildes[1]);
+
+ warn("test(%s) fork", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0:
+ /* output to pipe */
+ (void)close(fildes[0]);
+ while (dup2(fildes[1], STDOUT_FILENO) == -1)
+ if (errno != EINTR)
+ err(errno, "dup2");
+
+ /* create a new session (for kill) */
+ setsid();
+
+ /* set pledge policy */
+ if (request && pledge(request, paths) != 0)
+ err(errno, "pledge");
+
+ /* reset errno and launch test */
+ errno = 0;
+ test_func();
+
+ if (errno != 0)
+ _exit(errno);
+
+ _exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+ }
+
+ /* copy pipe to output */
+ (void)close(fildes[1]);
+ if (drainfd(fildes[0], STDOUT_FILENO) != 0) {
+ warn("test(%s): drainfd", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+ if (close(fildes[0]) != 0) {
+ warn("test(%s): close", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ /* wait for test to terminate */
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EAGAIN)
+ continue;
+ warn("test(%s): waitpid", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ /* show status and details */
+ printf(" 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(%s): check_coredump", test_name);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0: /* found */
+ printf(" coredump=present");
+ break;
+
+ case 1: /* not found */
+ printf(" coredump=absent");
+ break;
+
+ default:
+ warnx("test(%s): unknown coredump code %d",
+ test_name, coredump);
+ *ret = EXIT_FAILURE;
+ return;
+ }
+
+ }
+
+ /* grab pledged syscall from dmesg */
+ if ((signal == SIGKILL) || (signal = SIGABRT)) {
+ int syscall = grab_syscall(pid);
+ switch (syscall) {
+ case -1: /* error */
+ warn("test(%s): grab_syscall pid=%d", test_name,
+ pid);
+ *ret = EXIT_FAILURE;
+ return;
+
+ case 0: /* not found */
+ printf(" pledged_syscall=not_found");
+ break;
+
+ default:
+ printf(" pledged_syscall=%d", syscall);
+ }
+ }
+ }
+
+ if (WIFSTOPPED(status))
+ printf(" stop=%d", WSTOPSIG(status));
+
+ printf("\n");
+}
--- /dev/null
+/* $OpenBSD: manager.h,v 1.1 2015/10/09 06:44:13 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 _MANAGER_H_
+#define _MANAGER_H_
+
+void _start_test(int *ret, const char *test_name, const char *request,
+ const char *paths[], void (*test_func)(void));
+
+#define start_test(ret,req,paths,func) \
+ _start_test(ret,#func,req,paths,func)
+
+#define start_test1(ret,req,path,func) \
+ do { \
+ const char *_paths[] = {path, NULL}; \
+ start_test(ret,req,_paths,func); \
+ } while (0)
+
+#endif /* _MANAGER_H_ */
--- /dev/null
+# $OpenBSD: tests.out,v 1.1 2015/10/09 06:44:13 semarie Exp $
+test(test_nop): pledge=("",NULL) status=0 exit=0
+test(test_inet): pledge=("",NULL) status=9 signal=9 pledged_syscall=97
+test(test_inet): pledge=("abort",NULL) status=134 signal=6 coredump=present pledged_syscall=97
+test(test_inet): pledge=("inet",NULL) status=0 exit=0
+test(test_kill): pledge=("inet",NULL) status=9 signal=9 pledged_syscall=37
+test(test_kill): pledge=("proc",NULL) status=2 signal=2 pledged_syscall=not_found
+test(test_allowed_syscalls): pledge=("malloc",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("rw",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("stdio",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("rpath",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("wpath",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("tmppath",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("inet",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("unix",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("dns",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("getpw",NULL) status=0 exit=0
+test(test_allowed_syscalls): pledge=("cmsg",NULL) status=9 signal=9 pledged_syscall=89
+test(test_allowed_syscalls): pledge=("ioctl",NULL) status=9 signal=9 pledged_syscall=89
+test(test_allowed_syscalls): pledge=("proc",NULL) status=9 signal=9 pledged_syscall=89
+test(test_allowed_syscalls): pledge=("cpath",NULL) status=9 signal=9 pledged_syscall=89
+test(test_allowed_syscalls): pledge=("abort",NULL) status=134 signal=6 coredump=present pledged_syscall=89
+test(test_allowed_syscalls): pledge=("fattr",NULL) status=9 signal=9 pledged_syscall=89
+test(test_rpath): pledge=("rpath",NULL) status=0 exit=0
+test(test_wpath): pledge=("wpath",NULL) status=0 exit=0
+test(test_cpath): pledge=("cpath",NULL) status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",NULL)
+ open_close("/etc/passwd") fd=3 errno=0
+ open_close("generic") fd=3 errno=0
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{NULL})
+ open_close("/etc/passwd") fd=-1 errno=2
+ open_close("generic") fd=-1 errno=2
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"/",NULL})
+ open_close("/etc/passwd") fd=3 errno=0
+ open_close("generic") fd=3 errno=0
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"/etc",NULL})
+ open_close("/etc/passwd") fd=3 errno=0
+ open_close("generic") fd=-1 errno=2
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"/etc/",NULL})
+ open_close("/etc/passwd") fd=3 errno=0
+ open_close("generic") fd=-1 errno=2
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"/etc/passwd",NULL})
+ open_close("/etc/passwd") fd=3 errno=0
+ open_close("generic") fd=-1 errno=2
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"/bin",NULL})
+ open_close("/etc/passwd") fd=-1 errno=2
+ open_close("generic") fd=-1 errno=2
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"generic",NULL})
+ open_close("/etc/passwd") fd=-1 errno=2
+ open_close("generic") fd=3 errno=0
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{"",NULL})
+ open_close("/etc/passwd") fd=-1 errno=2
+ open_close("generic") fd=3 errno=0
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_wpaths): pledge=("stdio rpath",{".",NULL})
+ open_close("/etc/passwd") fd=-1 errno=2
+ open_close("generic") fd=3 errno=0
+ open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
+ open_close("/nonexistent") fd=-1 errno=2
+ status=0 exit=0
+test(test_pledge): pledge=("stdio rpath",NULL) status=0 exit=0
+test(test_pledge): pledge=("malloc rw rpath",NULL) status=0 exit=0
+test(test_pledge): pledge=("stdio rpath wpath",NULL) status=0 exit=0
+test(test_pledge): pledge=("stdio rpath wpath",{"/sbin",NULL}) status=256 exit=1 (errno: "Operation not permitted")
+test(test_pledge): pledge=("stdio rpath wpath",{"/",NULL}) status=256 exit=1 (errno: "Operation not permitted")
+test(test_pledge): pledge=("stdio",NULL) status=256 exit=1 (errno: "Operation not permitted")
+test(test_pledge): pledge=("unix",NULL) status=256 exit=1 (errno: "Operation not permitted")
+test(test_stat): pledge=("stdio rpath",{"/usr/share/man",NULL})
+ stat("/usr/share/man/man8/afterboot.8"): realpath=failed(2) uid=0 gid=7 mode=100444
+ stat("/usr/share/man/man8/"): realpath=failed(2) uid=0 gid=0 mode=40755
+ stat("/usr/share/man"): realpath=failed(2) uid=0 gid=0 mode=40755
+ stat("/usr/share"): realpath=failed(2) errno=2
+ stat("/usr"): realpath="/usr" errno=2
+ stat("/"): realpath="/" errno=2
+ stat("/usr/bin/gzip"): realpath=failed(2) errno=2
+ status=0 exit=0
+test(test_mmap): pledge=("rpath malloc prot_exec",{"/dev/zero",NULL}) status=0 exit=0
+test(test_mmap): pledge=("rpath malloc",{"/dev/zero",NULL}) status=9 signal=9 pledged_syscall=197
--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2015/10/09 06:44:13 semarie Exp $
+PROG= sigabrt
+NOMAN= yes
+
+run-regress-${PROG}: ${PROG}
+ rm -f ./${PROG}.core
+ if ./${PROG}; then false; else true; fi
+ if [ ! -e ./${PROG}.core ]; then echo "No coredump"; false; fi
+ ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/${PROG}.out -
+
+.include <bsd.regress.mk>
--- /dev/null
+/* $OpenBSD: sigabrt.c,v 1.1 2015/10/09 06:44:13 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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+void
+handler(int sigraised)
+{
+ /* this handler shouldn't not be called */
+ printf("forbidden STDIO in SIGABRT handler\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* install SIGABRT handler */
+ signal(SIGABRT, &handler);
+
+ printf("permitted STDIO\n");
+ fflush(stdout);
+
+ if (pledge("abort", NULL) == -1)
+ err(EXIT_FAILURE, "pledge");
+
+ /* this will triggered pledge_fail() */
+ printf("forbidden STDIO 1\n");
+
+ /* shouldn't continue */
+ printf("forbidden STDIO 2\n");
+ return (EXIT_SUCCESS);
+}
--- /dev/null
+$OpenBSD: sigabrt.out,v 1.1 2015/10/09 06:44:13 semarie Exp $
+permitted STDIO
--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2015/10/09 06:44:13 semarie Exp $
+PROG= sigkill
+NOMAN= yes
+
+run-regress-${PROG}: ${PROG}
+ rm -f ./${PROG}.core
+ if ./${PROG}; then false; else true; fi
+ if [ -e ./${PROG}.core ]; then echo "Unexpected coredump"; false; fi
+ ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/${PROG}.out -
+
+.include <bsd.regress.mk>
--- /dev/null
+/* $OpenBSD: sigkill.c,v 1.1 2015/10/09 06:44:13 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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+void
+handler(int sigraised)
+{
+ /* the handler shouldn't not be called */
+ printf("forbidden STDIO in %d handler\n", sigraised);
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* install some handlers */
+ signal(SIGHUP, &handler);
+ signal(SIGABRT, &handler);
+
+ printf("permitted STDIO\n");
+ fflush(stdout);
+
+ if (pledge("", NULL) == -1)
+ err(EXIT_FAILURE, "pledge");
+
+ /* this will triggered pledge_fail() */
+ printf("forbidden STDIO 1\n");
+
+ /* shouldn't continue */
+ printf("forbidden STDIO 2\n");
+ return (EXIT_SUCCESS);
+}
--- /dev/null
+$OpenBSD: sigkill.out,v 1.1 2015/10/09 06:44:13 semarie Exp $
+permitted STDIO
+++ /dev/null
-# $OpenBSD: Makefile,v 1.2 2015/09/10 11:18:34 semarie Exp $
-
-SUBDIR += sigabrt
-SUBDIR += sigkill
-SUBDIR += generic
-
-.include <bsd.subdir.mk>
+++ /dev/null
-# $OpenBSD: Makefile,v 1.3 2015/09/24 06:25:54 semarie Exp $
-PROG= generic
-SRCS+= main.c manager.c
-NOMAN= yes
-
-CFLAGS+= -Wall -Werror
-
-REGRESS_TARGETS+= test_normal test_systrace
-REGRESS_SKIP_TARGETS+= test_systrace
-
-test_normal: ${PROG}
- ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
-
-test_systrace: ${PROG}
- systrace -A ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/tests.out -
-
-regenerate: ${PROG}
- echo '# $$OpenBSD: Makefile,v 1.3 2015/09/24 06:25:54 semarie Exp $$' > ${.CURDIR}/tests.out
- ./${PROG} | tee -a ${.CURDIR}/tests.out
-
-.include <bsd.regress.mk>
+++ /dev/null
-/* $OpenBSD: main.c,v 1.10 2015/10/06 15:45:31 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/mman.h>
-#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 <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "manager.h"
-
-static void
-test_nop()
-{
- /* nop */
-}
-
-static void
-test_inet()
-{
- int fd = socket(AF_INET, SOCK_STREAM, 0);
- int saved_errno = errno;
- close(fd);
- errno = saved_errno ? saved_errno : errno;
-}
-
-static void
-test_kill()
-{
- kill(0, SIGINT);
-}
-
-static void
-test_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(); */
-}
-
-
-static void
-open_close(const char *filename)
-{
- int fd;
- int saved_errno;
-
- errno = 0;
- printf("\n open_close(\"%s\")", filename);
- fd = open(filename, O_RDONLY);
- saved_errno = errno;
- printf(" fd=%d errno=%d", fd, errno);
- if (fd != -1)
- close(fd);
- errno = saved_errno;
-}
-
-static void
-test_wpaths()
-{
- /* absolute file */
- open_close("/etc/passwd");
-
- /* relative */
- open_close("generic");
-
- /* relative */
- open_close("../../../../../../../../../../../../../../../etc/passwd");
-
- /* ENOENT */
- open_close("/nonexistent");
-
- /* calling exit to flush stdout */
- printf("\n");
- exit(EXIT_SUCCESS);
-}
-
-static void
-test_tame()
-{
- const char *wpaths[] = { "/sbin", NULL };
-
- if (tame("stdio rpath", wpaths) != 0)
- _exit(errno);
-}
-
-static void
-do_stat(const char *path)
-{
- char resolved[PATH_MAX];
- struct stat sb;
-
- printf("\n stat(\"%s\"):", path);
-
- /* call realpath(3) */
- errno = 0;
- if (realpath(path, resolved) != NULL)
- printf(" realpath=\"%s\"", resolved);
- else
- printf(" realpath=failed(%d)", errno);
-
- /* call stat(2) */
- errno = 0;
- if (stat(path, &sb) == 0)
- printf(" uid=%d gid=%d mode=%04o", sb.st_uid, sb.st_gid,
- sb.st_mode);
- else
- printf(" errno=%d", errno);
-}
-
-static void
-test_stat()
-{
- /* in whitelisted path */
- do_stat("/usr/share/man/man8/afterboot.8");
- do_stat("/usr/share/man/man8/");
- do_stat("/usr/share/man");
-
- /* parent of whitelisted path */
- do_stat("/usr/share");
- do_stat("/usr");
- do_stat("/");
-
- /* outside whitelisted path */
- do_stat("/usr/bin/gzip");
-
- /* calling exit to flush stdout */
- printf("\n");
- exit(EXIT_SUCCESS);
-}
-
-static void
-test_mmap()
-{
- int fd;
- void * data;
-
- if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
- _exit(errno);
-
- data = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FILE|MAP_SHARED, fd, 0);
-
- if (data == MAP_FAILED)
- _exit(errno);
-
- munmap(data, 4096);
- close(fd);
-}
-
-static void
-test_rpath()
-{
- int fd;
- char data[512];
-
- if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
- _exit(errno);
-
- if (read(fd, data, sizeof(data)) == -1)
- _exit(errno);
-
- close(fd);
-}
-
-static void
-test_wpath()
-{
- int fd;
- char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
-
- if ((fd = open("/dev/null", O_WRONLY, 0)) == -1)
- _exit(errno);
-
- if (write(fd, data, sizeof(data)) == -1)
- _exit(errno);
-
- close(fd);
-}
-
-static void
-test_cpath()
-{
- const char filename[] = "/tmp/generic-test-cpath";
-
- if (mkdir(filename, S_IRWXU) == -1)
- _exit(errno);
-
- if (rmdir(filename) == -1)
- _exit(errno);
-}
-
-int
-main(int argc, char *argv[])
-{
- int ret = EXIT_SUCCESS;
-
- if (argc != 1)
- errx(1, "usage: %s", argv[0]);
-
- /*
- * testsuite
- */
-
- /* _exit is always allowed, and nothing else under flags=0 */
- start_test(&ret, "", NULL, test_nop);
- start_test(&ret, "", NULL, test_inet);
-
- /* test coredump */
- start_test(&ret, "abort", NULL, test_inet);
-
- /* inet under inet is ok */
- start_test(&ret, "inet", NULL, test_inet);
-
- /* kill under inet is forbidden */
- start_test(&ret, "inet", NULL, test_kill);
-
- /* kill under proc is allowed */
- start_test(&ret, "proc", NULL, test_kill);
-
- /* tests TAME_SELF for permitted syscalls */
- start_test(&ret, "malloc", NULL, test_allowed_syscalls);
- start_test(&ret, "rw", NULL, test_allowed_syscalls);
- start_test(&ret, "stdio", NULL, test_allowed_syscalls);
- start_test(&ret, "rpath", NULL, test_allowed_syscalls);
- start_test(&ret, "wpath", NULL, test_allowed_syscalls);
- start_test(&ret, "tmppath", NULL, test_allowed_syscalls);
- start_test(&ret, "inet", NULL, test_allowed_syscalls);
- start_test(&ret, "unix", NULL, test_allowed_syscalls);
- start_test(&ret, "dns", NULL, test_allowed_syscalls);
- start_test(&ret, "getpw", NULL, test_allowed_syscalls);
-
- /* tests req without TAME_SELF for "permitted syscalls" */
- // XXX it is a documentation bug
- start_test(&ret, "cmsg", NULL, test_allowed_syscalls);
- start_test(&ret, "ioctl", NULL, test_allowed_syscalls);
- start_test(&ret, "proc", NULL, test_allowed_syscalls);
- start_test(&ret, "cpath", NULL, test_allowed_syscalls);
- start_test(&ret, "abort", NULL, test_allowed_syscalls);
- start_test(&ret, "fattr", NULL, test_allowed_syscalls);
-
- start_test(&ret, "rpath", NULL, test_rpath);
- start_test(&ret, "wpath", NULL, test_wpath);
- start_test(&ret, "cpath", NULL, test_cpath);
-
- /*
- * test whitelist path
- */
- start_test(&ret, "stdio rpath", NULL, test_wpaths);
- start_test1(&ret, "stdio rpath", NULL, test_wpaths);
- start_test1(&ret, "stdio rpath", "/", test_wpaths);
- start_test1(&ret, "stdio rpath", "/etc", test_wpaths);
- start_test1(&ret, "stdio rpath", "/etc/", test_wpaths);
- start_test1(&ret, "stdio rpath", "/etc/passwd", test_wpaths);
- // XXX start_test1(&ret, "stdio rpath", "/etc/passwd/", test_wpaths);
- start_test1(&ret, "stdio rpath", "/bin", test_wpaths);
- start_test1(&ret, "stdio rpath", "generic", test_wpaths);
- start_test1(&ret, "stdio rpath", "", test_wpaths);
- start_test1(&ret, "stdio rpath", ".", test_wpaths);
-
- /*
- * test tame(2) arguments
- */
- /* same request */
- start_test(&ret, "stdio rpath", NULL, test_tame);
- /* same request (stdio = malloc rw) */
- start_test(&ret, "malloc rw rpath", NULL, test_tame);
- /* reduce request */
- start_test(&ret, "stdio rpath wpath", NULL, test_tame);
- /* reduce request (with same/other wpaths) */
- start_test1(&ret, "stdio rpath wpath", "/sbin", test_tame);
- start_test1(&ret, "stdio rpath wpath", "/", test_tame);
- /* add request */
- start_test(&ret, "stdio", NULL, test_tame);
- /* change request */
- start_test(&ret, "unix", NULL, test_tame);
-
- /* test stat(2) */
- start_test1(&ret, "stdio rpath", "/usr/share/man", test_stat);
-
- /* mmap */
- start_test1(&ret, "rpath malloc prot_exec", "/dev/zero", test_mmap);
- start_test1(&ret, "rpath malloc", "/dev/zero", test_mmap);
-
- return (ret);
-}
+++ /dev/null
-/* $OpenBSD: manager.c,v 1.5 2015/10/08 10:09:09 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/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>
-
-extern char *__progname;
-
-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, const char *test_name)
-{
- int saved_errno = errno;
- int u;
-
- if (((u = unlink(coredump_name())) != 0) && (errno != ENOENT)) {
- warn("test(%s): clear_coredump", test_name);
- *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);
-}
-
-/* mainly stolen from src/bin/cat/cat.c */
-static int
-drainfd(int rfd, int wfd)
-{
- char buf[1024];
- ssize_t nr, nw, off;
-
- while ((nr = read(rfd, buf, sizeof(buf))) != -1 && nr != 0)
- for (off = 0; nr; nr -= nw, off += nw)
- if ((nw = write(wfd, buf + off, (size_t)nr)) == 0 ||
- nw == -1)
- return (-1);
- if (nr < 0)
- return (-1);
-
- return (0);
-}
-
-void
-_start_test(int *ret, const char *test_name, const char *request,
- const char *paths[], void (*test_func)(void))
-{
- int fildes[2];
- pid_t pid;
- int status;
- int i;
-
- /* early print testname */
- printf("test(%s): tame=", test_name);
- if (request) {
- printf("(\"%s\",", request);
- if (paths) {
- printf("{");
- for (i = 0; paths[i] != NULL; i++)
- printf("\"%s\",", paths[i]);
- printf("NULL})");
- } else
- printf("NULL)");
- } else
- printf("not-called");
-
- /* unlink previous coredump (if exists) */
- if (clear_coredump(ret, test_name) == -1)
- return;
-
- /* flush outputs (for STDOUT_FILENO manipulation) */
- if (fflush(NULL) != 0) {
- warn("test(%s) fflush", test_name);
- *ret = EXIT_FAILURE;
- return;
- }
-
- /* make pipe to grab output */
- if (pipe(fildes) != 0) {
- warn("test(%s) pipe", test_name);
- *ret = EXIT_FAILURE;
- return;
- }
-
- /* fork and launch the test */
- switch (pid = fork()) {
- case -1:
- (void)close(fildes[0]);
- (void)close(fildes[1]);
-
- warn("test(%s) fork", test_name);
- *ret = EXIT_FAILURE;
- return;
-
- case 0:
- /* output to pipe */
- (void)close(fildes[0]);
- while (dup2(fildes[1], STDOUT_FILENO) == -1)
- if (errno != EINTR)
- err(errno, "dup2");
-
- /* create a new session (for kill) */
- setsid();
-
- /* set tame policy */
- if (request && tame(request, paths) != 0)
- err(errno, "tame");
-
- /* reset errno and launch test */
- errno = 0;
- test_func();
-
- if (errno != 0)
- _exit(errno);
-
- _exit(EXIT_SUCCESS);
- /* NOTREACHED */
- }
-
- /* copy pipe to output */
- (void)close(fildes[1]);
- if (drainfd(fildes[0], STDOUT_FILENO) != 0) {
- warn("test(%s): drainfd", test_name);
- *ret = EXIT_FAILURE;
- return;
- }
- if (close(fildes[0]) != 0) {
- warn("test(%s): close", test_name);
- *ret = EXIT_FAILURE;
- return;
- }
-
- /* wait for test to terminate */
- while (waitpid(pid, &status, 0) < 0) {
- if (errno == EAGAIN)
- continue;
- warn("test(%s): waitpid", test_name);
- *ret = EXIT_FAILURE;
- return;
- }
-
- /* show status and details */
- printf(" 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(%s): check_coredump", test_name);
- *ret = EXIT_FAILURE;
- return;
-
- case 0: /* found */
- printf(" coredump=present");
- break;
-
- case 1: /* not found */
- printf(" coredump=absent");
- break;
-
- default:
- warnx("test(%s): unknown coredump code %d",
- test_name, 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(%s): grab_syscall pid=%d", test_name,
- 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");
-}
+++ /dev/null
-/* $OpenBSD: manager.h,v 1.1 2015/09/24 06:25:54 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 _MANAGER_H_
-#define _MANAGER_H_
-
-void _start_test(int *ret, const char *test_name, const char *request,
- const char *paths[], void (*test_func)(void));
-
-#define start_test(ret,req,paths,func) \
- _start_test(ret,#func,req,paths,func)
-
-#define start_test1(ret,req,path,func) \
- do { \
- const char *_paths[] = {path, NULL}; \
- start_test(ret,req,_paths,func); \
- } while (0)
-
-#endif /* _MANAGER_H_ */
+++ /dev/null
-# $OpenBSD: tests.out,v 1.9 2015/10/06 15:45:31 semarie Exp $
-test(test_nop): tame=("",NULL) status=0 exit=0
-test(test_inet): tame=("",NULL) status=9 signal=9 tamed_syscall=97
-test(test_inet): tame=("abort",NULL) status=134 signal=6 coredump=present tamed_syscall=97
-test(test_inet): tame=("inet",NULL) status=0 exit=0
-test(test_kill): tame=("inet",NULL) status=9 signal=9 tamed_syscall=37
-test(test_kill): tame=("proc",NULL) status=2 signal=2 tamed_syscall=not_found
-test(test_allowed_syscalls): tame=("malloc",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("rw",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("stdio",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("rpath",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("wpath",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("tmppath",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("inet",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("unix",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("dns",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("getpw",NULL) status=0 exit=0
-test(test_allowed_syscalls): tame=("cmsg",NULL) status=9 signal=9 tamed_syscall=89
-test(test_allowed_syscalls): tame=("ioctl",NULL) status=9 signal=9 tamed_syscall=89
-test(test_allowed_syscalls): tame=("proc",NULL) status=9 signal=9 tamed_syscall=89
-test(test_allowed_syscalls): tame=("cpath",NULL) status=9 signal=9 tamed_syscall=89
-test(test_allowed_syscalls): tame=("abort",NULL) status=134 signal=6 coredump=present tamed_syscall=89
-test(test_allowed_syscalls): tame=("fattr",NULL) status=9 signal=9 tamed_syscall=89
-test(test_rpath): tame=("rpath",NULL) status=0 exit=0
-test(test_wpath): tame=("wpath",NULL) status=0 exit=0
-test(test_cpath): tame=("cpath",NULL) status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",NULL)
- open_close("/etc/passwd") fd=3 errno=0
- open_close("generic") fd=3 errno=0
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{NULL})
- open_close("/etc/passwd") fd=-1 errno=2
- open_close("generic") fd=-1 errno=2
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"/",NULL})
- open_close("/etc/passwd") fd=3 errno=0
- open_close("generic") fd=3 errno=0
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"/etc",NULL})
- open_close("/etc/passwd") fd=3 errno=0
- open_close("generic") fd=-1 errno=2
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"/etc/",NULL})
- open_close("/etc/passwd") fd=3 errno=0
- open_close("generic") fd=-1 errno=2
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"/etc/passwd",NULL})
- open_close("/etc/passwd") fd=3 errno=0
- open_close("generic") fd=-1 errno=2
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=3 errno=0
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"/bin",NULL})
- open_close("/etc/passwd") fd=-1 errno=2
- open_close("generic") fd=-1 errno=2
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"generic",NULL})
- open_close("/etc/passwd") fd=-1 errno=2
- open_close("generic") fd=3 errno=0
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{"",NULL})
- open_close("/etc/passwd") fd=-1 errno=2
- open_close("generic") fd=3 errno=0
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_wpaths): tame=("stdio rpath",{".",NULL})
- open_close("/etc/passwd") fd=-1 errno=2
- open_close("generic") fd=3 errno=0
- open_close("../../../../../../../../../../../../../../../etc/passwd") fd=-1 errno=2
- open_close("/nonexistent") fd=-1 errno=2
- status=0 exit=0
-test(test_tame): tame=("stdio rpath",NULL) status=0 exit=0
-test(test_tame): tame=("malloc rw rpath",NULL) status=0 exit=0
-test(test_tame): tame=("stdio rpath wpath",NULL) status=0 exit=0
-test(test_tame): tame=("stdio rpath wpath",{"/sbin",NULL}) status=256 exit=1 (errno: "Operation not permitted")
-test(test_tame): tame=("stdio rpath wpath",{"/",NULL}) status=256 exit=1 (errno: "Operation not permitted")
-test(test_tame): tame=("stdio",NULL) status=256 exit=1 (errno: "Operation not permitted")
-test(test_tame): tame=("unix",NULL) status=256 exit=1 (errno: "Operation not permitted")
-test(test_stat): tame=("stdio rpath",{"/usr/share/man",NULL})
- stat("/usr/share/man/man8/afterboot.8"): realpath=failed(2) uid=0 gid=7 mode=100444
- stat("/usr/share/man/man8/"): realpath=failed(2) uid=0 gid=0 mode=40755
- stat("/usr/share/man"): realpath=failed(2) uid=0 gid=0 mode=40755
- stat("/usr/share"): realpath=failed(2) errno=2
- stat("/usr"): realpath="/usr" errno=2
- stat("/"): realpath="/" errno=2
- stat("/usr/bin/gzip"): realpath=failed(2) errno=2
- status=0 exit=0
-test(test_mmap): tame=("rpath malloc prot_exec",{"/dev/zero",NULL}) status=0 exit=0
-test(test_mmap): tame=("rpath malloc",{"/dev/zero",NULL}) status=9 signal=9 tamed_syscall=197
+++ /dev/null
-# $OpenBSD: Makefile,v 1.1 2015/07/27 18:03:36 semarie Exp $
-PROG= sigabrt
-NOMAN= yes
-
-run-regress-${PROG}: ${PROG}
- rm -f ./${PROG}.core
- if ./${PROG}; then false; else true; fi
- if [ ! -e ./${PROG}.core ]; then echo "No coredump"; false; fi
- ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/${PROG}.out -
-
-.include <bsd.regress.mk>
+++ /dev/null
-/* $OpenBSD: sigabrt.c,v 1.3 2015/09/10 11:16:08 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 <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-void
-handler(int sigraised)
-{
- /* this handler shouldn't not be called */
- printf("forbidden STDIO in SIGABRT handler\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- /* install SIGABRT handler */
- signal(SIGABRT, &handler);
-
- printf("permitted STDIO\n");
- fflush(stdout);
-
- tame("abort", NULL);
-
- /* this will triggered tame_fail() */
- printf("forbidden STDIO 1\n");
-
- /* shouldn't continue */
- printf("forbidden STDIO 2\n");
- return (EXIT_SUCCESS);
-}
+++ /dev/null
-$OpenBSD: sigabrt.out,v 1.1 2015/07/27 18:03:36 semarie Exp $
-permitted STDIO
+++ /dev/null
-# $OpenBSD: Makefile,v 1.1 2015/07/27 18:03:36 semarie Exp $
-PROG= sigkill
-NOMAN= yes
-
-run-regress-${PROG}: ${PROG}
- rm -f ./${PROG}.core
- if ./${PROG}; then false; else true; fi
- if [ -e ./${PROG}.core ]; then echo "Unexpected coredump"; false; fi
- ./${PROG} | diff -I OpenBSD -u ${.CURDIR}/${PROG}.out -
-
-.include <bsd.regress.mk>
+++ /dev/null
-/* $OpenBSD: sigkill.c,v 1.3 2015/09/10 11:16:08 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 <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-void
-handler(int sigraised)
-{
- /* the handler shouldn't not be called */
- printf("forbidden STDIO in %d handler\n", sigraised);
-}
-
-int
-main(int argc, char *argv[])
-{
- /* install some handlers */
- signal(SIGHUP, &handler);
- signal(SIGABRT, &handler);
-
- printf("permitted STDIO\n");
- fflush(stdout);
-
- tame("", NULL);
-
- /* this will triggered tame_fail() */
- printf("forbidden STDIO 1\n");
-
- /* shouldn't continue */
- printf("forbidden STDIO 2\n");
- return (EXIT_SUCCESS);
-}
+++ /dev/null
-$OpenBSD: sigkill.out,v 1.1 2015/07/27 18:03:36 semarie Exp $
-permitted STDIO