Computer Stone Age

 

Weblog moved to blog.gnoack.org

This weblog moved to https://blog.gnoack.org/. Please redirect your feed readers.

 

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/libc.so.84.2...done.
Loaded symbols for /usr/lib/libc.so.84.2
Reading symbols from /usr/libexec/ld.so...done.
Loaded symbols for /usr/libexec/ld.so
#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
(gdb)

...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.

  • This is probably not safe to do from the signal handler.
  • It's also not a general solution, as it obviously needs to log from the locked-down process, and that needs to make assumptions about the permitted syscalls. (code)
  • The otherwise suggested libseccomp does apparently not implement this either.

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.

 

There are my core dumps!

As noted before, with systemd, your core dumps disappear into one of systemd's log sinks, instead of being stored to the current directory. By now, they are recoverable by normal users again.

TL;DR: Run coredumpctl gdb to invoke gdb with the most recent core dump.

Related bug about disappearing coredumps: https://bugs.freedesktop.org/show_bug.cgi?id=54288

Scenario: A simple program that crashes with a segfault:

~/dumpcore$ cat dumpcore.c
#include <unistd.h>
void dump_core()   { int* boom = NULL; *boom = 2000; }
void its_time_to() { dump_core(); }
int main()         { its_time_to(); }
~/dumpcore$ cc -g -o dumpcore dumpcore.c
~/dumpcore$ ./dumpcore
Segmentation fault (core dumped)

Core dumps get written to systemd's core dumps directory (see man coredumpctl), and can be retrieved with the coredumpctl tool:

~/dumpcore$ coredumpctl list
TIME                            PID   UID   GID SIG PRESENT EXE
...
Sun 2016-10-02 14:44:14 CEST   3857  1000   100  11 * /home/me/dumpcore/dumpcore

By default, coredumpctl seems to use the most recent core dump, so that you can easily inspect the most recent core dump with:

~/dumpcore$ coredumpctl gdb
           PID: 3857 (dumpcore)
           UID: 1000 (me)
           GID: 100 (users)
        Signal: 11 (SEGV)
     Timestamp: Sun 2016-10-02 14:44:14 CEST (1min 3s ago)
  Command Line: ./dumpcore
    Executable: /home/me/dumpcore/dumpcore
 Control Group: /user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service
          Unit: user@1000.service
     User Unit: user@1000.service
         Slice: user-1000.slice
     Owner UID: 1000 (me)
       Boot ID: 73902fbce4e241f5bab007aad96895eb
    Machine ID: 3ff4d30a94914397acd6af26eed15114
      Hostname: limbo
      Coredump: /var/lib/systemd/coredump/core.dumpcore.1000.73902fbce4e241f5bab007aad96895eb.3857.1475412254000000000000.lz4
       Message: Process 3857 (dumpcore) of user 1000 dumped core.

                Stack trace of thread 3857:
                #0  0x00000000004004b6 dump_core (dumpcore)
                #1  0x00000000004004cd its_time_to (dumpcore)
                #2  0x00000000004004de main (dumpcore)
                #3  0x00007f89ba351291 __libc_start_main (libc.so.6)
                #4  0x00000000004003da _start (dumpcore)

GNU gdb (GDB) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/me/dumpcore/dumpcore...done.
[New LWP 3857]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./dumpcore'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004b6 in dump_core () at dumpcore.c:2
2	void dump_core()   { int* boom = NULL; *boom = 2000; }
(gdb) bt
#0  0x00000000004004b6 in dump_core () at dumpcore.c:2
#1  0x00000000004004cd in its_time_to () at dumpcore.c:3
#2  0x00000000004004de in main () at dumpcore.c:4
(gdb)
 

GPG with the CCID Driver

Unless you're using Debian, where people care about this, chances are that setting up GPG Smartcards with your Linux distribution is an adventure. There are two ways to do it, CCID and PCSCLite, the latter of which runs a background service pcscd — as root, at least on Arch, while GnuPG's built-in CCID driver accesses the reader directly through the USB device, but took me a lot longer to figure out how to use.

Problem

You're getting a "card error" when trying to access the card. The same thing works as root.

$ gpg --card-status
gpg: selecting openpgp failed: Card error
gpg: OpenPGP card not available: Card error
$

When trying the same as root, you can access the card.

Solution

Add a udev rule that changes file permissions for you, as documented on https://wiki.archlinux.org/index.php/GnuPG#Smartcard_not_detected

Add your user to a new user group that can read smartcards, and give that group read-write access to the device when it's plugged in, by creating a file /etc/udev/rules.d with the rule:

ACTION=="add", SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="08e6", ENV{ID_MODEL_ID}=="3438", MODE="660", GROUP="scard"

(Figure out the values for the vendor and model ID using lsusb, they are printed separated with a colon.)

Read more