Computer Laboratory

CTSRD

Temporally Enhanced Security Logic Assertions (TESLA)


TESLA builds on our experiences developing the TrustedBSD MAC Framework and Capsicum: our most critical security properties are frequently safety (temporal) properties rather than static invariants. Current tools for testing temporal properties are largely static, and unable to work effectively on extremely large C-language software bases, such as multi-million lines-of-code operating system kernels and web browsers. TESLA borrows ideas from model checking, applying them in a dynamic context using compiler-assisted instrumentation to continuously validate temporal security assertions during software execution. We have implemented a prototype of TESLA based on clang/LLVM AST transforms, which is able to test both explicit automata against C implementations (such as protocol state machines in the kernel and OpenSSL) and inline assertions checking for missing access control checks in OS logic.

Building TESLA

For the moment, TESLA requires a bit of effort to build: it has a very heavyweight dependency (recent LLVM/Clang). The steps required to build are:

  1. acquire prerequisites
  2. build (a very recent version of) LLVM
  3. build TESLA
  4. exercise TESLA

Prerequisites

Here is a table of dependencies and the names of their ports/packages on various platforms:

Name FreeBSD Mac OS X Linux
HomeBrew MacPorts Ubuntu Fedora
C++ compiler base system XCode (with Command Line Tools) clang gcc-c++
LLVM llvm-devel build from source
Clang clang-devel
libexecinfo libexecinfo included with libc
Git git git-core git
Subversion subversion
Ninja devel/ninja ninja ninja-build from source
CMake cmake cmake --enable-ninja cmake
Protocol Buffers protobuf protobuf-cpp libprotobuf-dev from source

Build a recent LLVM/Clang

You need to download and build a very recent version of LLVM/Clang from source unless you're using FreeBSD, which has a very recent version available from ports (see prerequisites, above).

$ cd somewhere/to/stash/1GB/of/LLVM $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm [...] U llvm Checked out revision 175226. $ cd llvm/tools $ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang [...] A clang/LICENSE.TXT U clang Checked out revision 175226. $ cd ../.. $ mkdir build $ cd build $ cmake -DCMAKE_BUILD_TYPE=Release -G Ninja ../llvm -- The C compiler identification is [...] -- Check for working C compiler using: Ninja -- Check for working C compiler using: Ninja -- works [...] -- Generating done -- Build files have been written to: /home/jonathan/LLVM/build $ cmake -D CMAKE_BUILD_TYPE=Release . # if you feel adventurous $ ninja [1932/1932] Linking CXX executable bin/c-index-test

Build TESLA

Once you have LLVM, make sure that it's at the front of your PATH:

$ export PATH=/path/to/LLVM/build/bin:$PATH $ llvm-config --libdir # test that llvm-config works

Next, we download and configure TESLA:

$ git clone https://github.com/CTSRD-TESLA/TESLA.git tesla Cloning into 'TESLA'... remote: Counting objects: 3138, done. [...] $ cd tesla $ mkdir build $ cd build $ cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .. -- The C compiler identification is Clang 3.3.0 -- Check for working C compiler using: Ninja -- Check for working C compiler using: Ninja -- works -- Detecting C compiler ABI info [...] -- Found PROTOBUF: /usr/local/lib/libprotobuf.so -- Configuring done -- Generating done -- Build files have been written to: /home/jonathan/TESLA/build $ ccmake . # nice UI for further configuration, or else: $ cmake -D USE_LIBCXX=false . # if you have libc++ but didn't link LLVM against it $ cmake -D CMAKE_MODULE_PATH=/<LLVM prefix>/share/llvm/cmake . # if CMake can't find LLVM-Config or AddLLVM $ cmake -D CMAKE_C_FLAGS=-fcolor-diagnostics . # optional but nice $ cmake -D CMAKE_CXX_FLAGS=-fcolor-diagnostics . # optional but nice

Then we can build and test it:

$ ninja [49/49] Testing TESLA

After that, you'll want to be able to actually run TESLA. You can either set some environment variables:

$ export TESLA_BUILD_DIR=/path/to/TESLA/build $ export TESLA_SOURCE_DIR=/path/to/TESLA $ export PATH=$TESLA_SOURCE_DIR/scripts:$PATH

or else you can install the tools somewhere on your PATH:

$ cd build $ cmake -D CMAKE_INSTALL_PREFIX=/some/sensible/path . # or else things go in /usr/local $ ninja install [1/1] Install the project... -- Install configuration: "Debug" -- Up-to-date: /some/sensible/path/lib/libtesla.so -- Installing: /some/sensible/path/bin/tesla-analyse -- Installing: /some/sensible/path/bin/tesla-instrument -- Installing: /some/sensible/path/bin/tesla-graph -- Installing: /some/sensible/path/bin/llvm-triple -- Installing: /some/sensible/path/bin/tesla-read -- Installing: /some/sensible/path/bin/tesla $ export PATH=/some/sensible/path

Having either set variables or installed TESLA, you should now be able to run TESLA commands:

$ tesla graph -help USAGE: tesla-graph [options] <input file> OPTIONS: automata determinism: -u - unlinked NFA -l - linked NFA -d - DFA -help - Display available options (-help-hidden for more) -o=<string> - <output file> -version - Display the version of this program

Exercise TESLA

The 'strawman' directory contains an example of how TESLA assertions can be written in C code. If you run it as-is:

$ cd strawman $ export LD_LIBRARY_PATH=../build/libtesla/src # or 'ninja install' in ../build $ make && ./demo TESLA demo application; version 3454895 (dirty) Calling the 'example_syscall' function... [CALR] example_syscall 0x7fff5b7ab7a8 0 0 [CALE] example_syscall 0x7fff5b7ab7a8 0 0 [RETE] security_check 0x7fff5b7ab7a8 0x104456020 0 0 [RETR] security_check 0x7fff5b7ab7a8 0x104456020 0 0 [RETE] some_helper 0 0 [RETR] some_helper 0 0 [CALR] void_helper 0x104456020 [CALE] void_helper 0x104456020 [RETE] void_helper 0x104456020 [RETR] void_helper 0x104456020 [NOW] automaton 0 71655456 0 [RETE] example_syscall 0x7fff5b7ab7a8 0 0 0 [RETR] example_syscall 0x7fff5b7ab7a8 0 0 0 'example_syscall' returned 0

This just shows that the 'demo' application runs normally. If, however, you comment out line 78 of example.c (which calls the security_check() function):

--- a/strawman/example.c +++ b/strawman/example.c @@ -75,7 +75,7 @@ example_syscall(struct credential *cred, int index, int op) int error; struct object *o = objects + index; - if ((error = security_check(cred, o, op))) return error; +// if ((error = security_check(cred, o, op))) return error; some_helper(op); void_helper(o); perform_operation(op, o);

... you should see an error when you run the 'demo' application:

$ make && ./demo TESLA demo application; version 3454895 (dirty) Calling the 'example_syscall' function... [...] [NOW] automaton 0 245383200 0 demo: tesla_assert_failed: unable to move 'example.c:42#0' 2->3: current state is 1

This shows that, when we reach the assertion site for automaton 0, we detect that a transition (the security_check event) was missed!