Capsicum Examples

In this post we take some first steps with the Capsicum capabilities that are present in the kernel we built previously.

I had hoped for this post to be a triumphant celebration, exercising the capability modes of our sweet-ass new kernel. Unfortunately, when I grabbed the capsicum-core project, I hit a number of problems getting libcapsicum to compile. After trying various code changes and doing some static library investigation (using nm -D libfoo.so) I gave up on that route. Instead, we will look at getting the capsicum-test project (from the same maintainers as capsicum-linux).

This project provides a series of user space tests for making sure the syscall interface is doing what it should. If we can get the tests running and passing, we can be sure that the previous work was successful, and hopefully inspect the code for some pointers to using the new capabilities in our own code!

Grab ze codes!!

$ git clone https://github.com/google/capsicum-test

At this point take a look at the codebase we’ve just secured. You’ll likely notice a startling lack of documentation. This seems to be a problem plaguing most of the capsicum work ;-(

Nevertheless, there is a makefile! That’s probably a good place to start digging. The project uses C++98 and the google test framework (which I’m completely unfamiliar with). For some reason I feel lucky though, so I’ll just issue make and see what happens…

$ make
g++ -Wall -g -ansi -Igtest-1.6.0/include -Igtest-1.6.0 -DGTEST_USE_OWN_TR1_TUPLE=1 -DGTEST_HAS_TR1_TUPLE=1   -c -o capsicum-test-main.o capsicum-test-main.cc
... lots more g++ commands ...
g++ -Wall -g -ansi -Igtest-1.6.0/include -Igtest-1.6.0 -DGTEST_USE_OWN_TR1_TUPLE=1 -DGTEST_HAS_TR1_TUPLE=1   -c -o linux.o linux.cc
linux.cc:12:28: fatal error: sys/capability.h: No such file or directory
compilation terminated.
make: *** [linux.o] Error 1

This is a problem I first saw when trying to build libcapsicum from capsicum-core. FreeBSD places include files in slightly different places than Linux. Specifically, a few of the headers located in sys/ are found instead in linux/. I could just change these, but since this project is specifically supposed to work with the linux port, there’s probably another way…

Looking at the specific error, it’s actually a linux.cc file that is causing the error. That’s troubling.

Update the import at line 12 from

#include <sys/capability.h>

to

    #include <linux/capability.h>

With this change, run make again. This time I have the following errors:

linux.cc: In function ‘void Linux_NoNewPrivs_ForkTest()’:
linux.cc:699:5: error: ‘capget’ was not declared in this scope
linux.cc:703:5: error: ‘capset’ was not declared in this scope
linux.cc:713:28: error: expected primary-expression before ‘.’ token
linux.cc:714:28: error: expected primary-expression before ‘.’ token
make: *** [linux.o] Error 1

Grepping through the capsicum-linux codebase for capset yields a lot of hits. Instead, take a look at man 2 capget. This manpage specifies that we should be including sys/capability.h. Hmm…

Looking in /usr/include/x86_64-linux-gnu/sys, I don’t see a capability.h. Fair enough. So where in the system is capability.h?

$ sudo find / -name capability.h
/usr/src/linux-headers-3.5.0-23-generic/include/linux/capability.h
/usr/src/linux-headers-3.5.0-36-generic/include/linux/capability.h
/usr/src/linux-headers-3.5.0-36/include/linux/capability.h
/usr/src/linux-headers-3.13.1-capsicum/include/uapi/linux/capability.h
/usr/src/linux-headers-3.13.1-capsicum/include/linux/capability.h
/usr/src/linux-headers-3.5.0-23/include/linux/capability.h
/usr/include/linux/capability.h
/work/capsicum-linux/debian/hdrtmp/usr/src/linux-headers-3.13.1-capsicum/include/uapi/linux/capability.h
/work/capsicum-linux/debian/hdrtmp/usr/src/linux-headers-3.13.1-capsicum/include/linux/capability.h
/work/capsicum-linux/debian/headertmp/usr/include/linux/capability.h
/work/capsicum-linux/include/uapi/linux/capability.h
/work/capsicum-linux/include/linux/capability.h
/work/capsicum-linux/security/apparmor/include/capability.h
/work/capsicum-linux/usr/include/linux/capability.h

Looking at the output above, I see hits under linux/ and a few hits in the capsicum-linux codebase. Maybe I’ve failed to install something? Hitting the interwebz, I found the following helpful StackOverflow answer. Facepalm

Apparently the capabilities header is only included in the libcap-dev package! I wonder if this was the source of the problem I was having with capsicum-core…

Install the package, revert the change we made to linux.cc, and issue make again:

$ sudo apt-get install libcap-dev
$ git checkout -- linux.cc
$ make clean && make
...
g++ -Wall -g -ansi -Igtest-1.6.0/include -Igtest-1.6.0 -DGTEST_USE_OWN_TR1_TUPLE=1 -DGTEST_HAS_TR1_TUPLE=1   -c -o linux.o linux.cc
linux.cc: In function ‘void Linux_NoNewPrivs_ForkTest()’:
linux.cc:713:28: error: expected primary-expression before ‘.’ token
linux.cc:714:28: error: expected primary-expression before ‘.’ token
make: *** [linux.o] Error 1

Alright, so that is some kind of progress. Now what is this syntax error all about?

$ vim linux.cc +713

Well, I haven’t used C++ professionally for some years, but this doesn’t look like valid syntax:

struct sock_fprog bpf = {.len = (sizeof(filter) / sizeof(filter[0])),
                           .filter = filter};

Maybe this is a C++98 thing? Doing a git blame on the file, I see that this line was last modified in commit 62b536f1. Let’s take a look at that commit…

$ git show 62b536f1

Well, apparently the line was first committed as-is, and hasn’t changed yet. Googling “sock_fprog”, I found some other reference code. In this code, the struct is declared and the filter and len members are set separately.

Change lines 713 and 714 to the following:

    struct sock_fprog bpf; 
    bpf.len = (sizeof(filter) / sizeof(filter[0]));
    bpf.filter = filter;

With this change, make completes successfully!

$ make clean && make

After make completes, there will be a binary named capsicum-test and smoketest. They both run and complete successfully! Hooray for a functional capability-enabled kernel!

With this success in mind, I decided to give capsicum-core a try again. Unfortunately, libcapsicum still won’t build, as it looks for cap_enter, which has not been implemented in the Linux port yet ;-(

Maybe in a future installment we’ll try to get it working under Linux.

In the meantime, I’ve submitted a pull request for this issue.

Update 14Feb2014 10:53:10 - The pull request has been accepted and merged! The linux.cc file will now compile correctly out of the box :-)

Next time, we’ll write some fresh code using Capsicum capabilities!