July 31, 2017

July 2017 – Siva’s Capsicum Test Suite Project

As a co-op student at the FreeBSD Foundation, I have the unique opportunity of being encouraged to contribute to other open source projects that help make progress on FreeBSD and its components. One such project that I worked on in July is an analysis of the Capsicum test suite. This test suite targets the Capsicum capability and sandbox framework, which is included in FreeBSD since version 10.0. As described on the University of Cambridge Computer Laboratory website, “Capsicum extends the POSIX API, providing several new OS primitives to support object-capability security on UNIX-like operating systems”. Furthermore, the test suite was initially created by David Drysdale at Google while porting FreeBSD’s reference implementation of the Capsicum framework to Linux.

For this project, I was first assigned to investigate a test case for pdfork(2) that had been failing for some time. However, upon running the test suite on a FreeBSD 12 CURRENT machine, I noticed that there were several test cases failing with non-trivial error messages and status codes. I discussed these results with Ed Maste, my supervisor, and we determined that the following test results were of interest:

  • OpenatTest.WithCapability: Open files using pathnames that are relative to a directory with restricted capabilities and contain “..”. The test was failing due to an assertion that every call to openat() with a pathname containing “..” is invalid. Based on changes made to FreeBSD after the test was written, the assertion should instead be that calling openat(base_fd, path, ...) with a path containing “..” should be forbidden only if path points to a file outside of the base directory represented by base_fd.

  • WithFiles.DisallowedFileSyscalls: Execute the mknod(2) syscall in capability mode with invalid arguments. This test case expected the syscall to return with ECAPMODE; however, the FreeBSD implementation of the syscall first ran validations against the given arguments before checking for capability. Since the arguments were invalid, it returned with EINVAL. The POSIX specification confirms that this behavior is permissible, so we decided that the test case must be changed[1].

  • Pdfork.OtherUser: Kill a process with pdkill(2) after changing the current process’s user identifier (UID). This test is currently failing because the kernel disallows sending signals to processes that are not of the same UID as the current process. After a short discussion, we determined that this behavior is desired, and we decided that the test case should be modified to remove the call to pdkill() after changing the current process’s UID.

  • Pdfork.Simple (related tests omitted): Test basic operations using process descriptors on processes created with the pdfork(2) syscall. These tests were failing because of checks to determine if a certain process is a zombie. These tests used the ps(1) tool, but upon further inspection, I noticed that ps -p <zombie-pid> does not report zombie processes. The call to ps(1) was modified in the test suite to ensure that the Pdfork.* test cases pass, but the kernel’s behavior, with respect to reporting zombie processes, remains the same until further discussion.

  • PosixMqueue.CapMode: Test basic operations using kmq_*() syscalls on POSIX message queues in capability mode. In order to run this test case, I needed to dynamically load the mqueuefs(5) kernel module. After doing this, I noticed that the newly-loaded syscalls returned ECAPMODE while in capability mode. Remote debugging these syscalls with GDB showed that their respective syscall entries (sysents) were not being initialized with the correct flags, so I submitted a kernel patch (which has now been committed to FreeBSD) and the tests now pass.

  • PipePdfork.Close: Test the behavior of a closed process descriptor. This test is currently failing because of a waitpid(2) call to a process that had its last process descriptor closed. I noticed that the kernel reparents a process to the init process after the last close(2) on its process descriptor. Ed and I decided that this behavior should be further discussed at the biweekly Capsicum conference call, and the verdict was that the kernel’s behavior is appropriate. The test case must be changed to reflect this behavior.

To run the Capsicum test suite, follow these steps on a FreeBSD machine:

  1. Clone the Capsicum test suite git repository and navigate into the directory
    $ git clone https://github.com/google/capsicum-test.git && cd capsicum-test

  2. Build the test suite
    $ make

  3. Run all tests that do not require you to be root
    $ ./capsicum-test

  4. Run all tests that require root
    $ sudo ./capsicum-test

  5. Run a specific test case with verbose log messages
    $ ./capsicum-test -v --gtest_filter="Pdfork.Simple"

For more help on how to use the test suite, run $ ./capsicum-test --help.

[1] Full discussion can be found here

– Contributed by Siva Mahadevan