Skip to content

immunant/IA2-Phase2

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Folders and files

NameName
Last commit message
Last commit date
Aug 4, 2023
Aug 31, 2023
Aug 21, 2023
Aug 22, 2023
Aug 31, 2023
Aug 31, 2023
Mar 6, 2023
Aug 21, 2023
Sep 11, 2023
Sep 12, 2023
Aug 1, 2023
Feb 1, 2023
Jul 27, 2023
Sep 11, 2023
Aug 21, 2023
Jan 18, 2023

Repository files navigation

IA2 Phase 2

This repo provides tools for compartmentalizing an application and its dependencies using Intel's memory protection keys (MPK) for userspace. The repo includes a tool that rewrites headers to create call gate wrappers as well as the runtime to initialize the protection keys for trusted compartments.

Setup

Ubuntu 20.04 is used for testing. Other Linux distributions may or may not work. Adjust the commands below accordingly.

Install the package prerequisites.

sudo apt install -y libusb-1.0-0-dev libclang-dev llvm-dev \
            ninja-build zlib1g-dev python3-pip cmake \
            libavformat-dev libavutil-dev pcregrep patchelf
pip install lit
rustup install nightly

Configure with CMake

Note: Adjust paths to your version of Clang/LLVM

mkdir build && pushd build
cmake ..                                        \
            -DClang_DIR=/usr/lib/cmake/clang-12 \
            -DLLVM_DIR=/usr/lib/llvm-12/cmake   \
            -DLLVM_EXTERNAL_LIT=`which lit`     \
            -G Ninja

Build and run the tests

Note: Pass -v to ninja to see build commands and output from failing tests.

ninja check-ia2

Usage

Defining compartments

First invoke the INIT_RUNTIME macro once in any binary or shared library to define the number of protection keys that need to be allocated. The argument passed to INIT_RUNTIME must be a number between 1 and 15. Then the IA2_COMPARTMENT #define is used to define trusted compartments at the shared object level. This can be the main executable ELF or any dynamically-linked shared libraries. Memory belonging to a trusted compartment is assigned one of the 15 protection keys and can only be accessed by the shared object itself. Objects that don't explicitly define a compartment are treated as untrusted by default.

To assign a protection key to a trusted compartment, insert #define IA2_COMPARTMENT n with an argument between 1-15 specifying the index of the protection key, and include ia2_compartment_init.inc:

#define IA2_COMPARTMENT 1
#include <ia2_compartment_init.inc>

This argument must differ from the other trusted compartments. Trusted compartments must also be aligned and padded properly by using the padding.ld script in libia2/. In CMake this is done automatically for executables built with define_test while libraries built with define_shared_lib must add LINK_OPTS "-Wl,-T${libia2_BINARY_DIR}/padding.ld". To use in manual builds just include -Wl,-T/path/to/padding.ld in the final compilation step. Manual builds also require disabling lazy binding with -Wl,-z,now.

Wrapping calls

Calls between compartments must have call gates to toggle the PKRU permissions at each transition. For direct calls, this is done by rewriting headers to generate the source for a wrapper that provides versions of every function with call gates. These wrappers are specific to both the wrapped library and caller. This means that the generated source must be compiled once per compartment that links against the wrapped library. Each caller's wrapper must define the CALLER_PKEY macro with the appropriate value for the caller.

From CMake

We provide a CMake rule to wrap a library or the main executable. This rule builds a wrapper and provides its dependency information to consumers of its outputs. Specifically, wrapper libs also depend on libia2 and have additional required compilation flags (-fno-omit-frame-pointer) for application code.

Usage from CMake looks like this (wrapping myunsafelib which is used by your existing my_prog target):

+define_ia2_wrapper(
+    WRAPPER my_wrapper_target
+    WRAPPED_LIB myunsafelib-1.0
+    HEADERS myunsafelib.h myunsafelib_config.h
+    CALLER_PKEY 0
+)
+
 add_executable(my_prog main.c)
-target_link_libraries(my_prog PRIVATE myunsafelib-1.0)
+target_link_libraries(my_prog PRIVATE my_wrapper_target)

Wrapped libraries are treated as untrusted by default. If the library being wrapped defined a trusted compartment, COMPARTMENT_PKEY n must be specified in define_ia2_wrapper. Here n is the argument used in IA2_COMPARTMENT to define the compartment. If the caller is an untrusted compartment, set CALLER_PKEY UNTRUSTED. To create a wrapper for the main binary (i.e. if shared libraries call it directly) the WRAP_MAIN option must be specified.

Manual usage

See this doc for notes on manual usage.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published