Usability of OpenBSD's pledge() and Linux's seccomp

Let's write a simple pledge program on OpenBSD, which should crash.

#include <stdio.h>
int main() {
  pledge("", NULL);
  printf("Hello, pledge world!\n");

Let's compile and run it:

$ cc -g -o pledgetest pledgetest.c
$ ./pledgetest
Abort trap (core dumped)

Core dumped! Now debug it:

$ gdb pledgetest pledgetest.core
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-unknown-openbsd5.9"...
Core was generated by `pledgetest'.
Program terminated with signal 6, Aborted.
Loaded symbols for /home/me/pledgetest
Reading symbols from /usr/lib/
Loaded symbols for /usr/lib/
Reading symbols from /usr/libexec/
Loaded symbols for /usr/libexec/
#0  0x00001e9fc24090ba in mprotect () at <stdin>:2
2       <stdin>: No such file or directory.
        in <stdin>
(gdb) bt
#0  0x00001e9fc24090ba in mprotect () at <stdin>:2
#1  0x00001e9fc2408b26 in __atexit_register_cleanup (
    func=0x1e9fc24088e0 <_cleanup>) at /usr/src/lib/libc/stdlib/atexit.c:228
#2  0x00001e9fc24088cd in __sinit () at /usr/src/lib/libc/stdio/findfp.c:174
#3  0x00001e9fc2410e3c in __swsetup (fp=0x1e9fc28414b8)
    at /usr/src/lib/libc/stdio/wsetup.c:48
#4  0x00001e9fc2410be9 in __sfvwrite (fp=0x1e9fc28414b8, uio=0x7f7ffffed630)
    at /usr/src/lib/libc/stdio/fvwrite.c:60
#5  0x00001e9fc23d69e3 in *_libc_puts (s=0x1e9d58500be0 "Hello, pledge world!")
    at /usr/src/lib/libc/stdio/puts.c:59
#6  0x00001e9d58400bce in main () at pledgetest.c:4
Current language:  auto; currently asm

...and there is our stack trace; the printf got compiled to a puts, and that ended up calling mprotect, which was not allowed in the (empty) pledge policy.

Straightforward Unix debugging so far.

Now the same with Linux's seccomp

(See below for the solution)

I wrote a seccomp filter that defaults to SECCOMP_RET_KILL. With this, a policy violation results in a "Bad system call":

$ ./main
i am going to open a file bwahaha
Bad system call

This doesn't save a core dump.

There may be kernel auditing support, but that requires to recompile the kernel on most distributions.

The suggested way by Kees Cook (who implemented seccomp in Chromium), is to rewrite the seccomp filter to trigger a SIGSYS signal instead (SECCOMP_RET_TRAP) and register a signal handler that will log the attempted syscall.

Update: I was missing something obvious: When the filter returns SECCOMP_RET_TRAP instead of SECCOMP_RET_KILL, the default behaviour for the process is to dump core, and it can be debugged in the same way as for OpenBSD. No need to reimplement the signal handler.