class: center, middle ### Secure Computer Architecture and Systems *** # Software Compartmentalisation: Introduction --- # Systems Software Security Landscape .leftcol[ - Most systems software are seen as a **single monolithic unit of trust** - One vulnerability may allow an attacker to take over an entire application/system - Not a good fit to modern apps integrate **components from various sources with different degrees of trust** - Increased risk of supply chain attacks ] .rightcol[
] --- # Systems Software Security Landscape .leftcol[ - Systems software also integrate components that are **security-critical** - Cannot continue to see modern systems software as monolithic pieces of trust - Need to bring isolation and privilege reduction **within applications** - Achieved with **software compartmentalisation** ] .rightcol[
] --- # Software Compartmentalisation - Software compartmentalisation **decompose software into lesser-privileged components (*compartments*) that only have access to what they need to do their job** - Different from other defences: acknowledge there will be bugs and exploits, try to limit their impact
--- # Software Compartmentalisation - Software compartmentalisation **decompose software into lesser-privileged components (*compartments*) that only have access to what they need to do their job** - Different from other defences: acknowledge there will be bugs and exploits, try to limit their impact
--- ## (Re)designing for Compartmentalisation - Compartmentalisation is not complete isolation: components are still part of a single application/system and **communicate** - Traditional examples: OS kernels, web browser, web servers, SSH software - Niche/specific examples, approach not widespread because it's a lot of work -- - Software can be **designed from scratch** with compartmentalisation in mind - That's the case for most production-ready examples -- - Compartmentalisation can also be **retrofitted into monolithic software** - Desirable objective given the large amount of legacy monolithic system software - Hard to achieve in practice: it's a lot of work too --- # Compartmentalisation: Key Idea - **Restrict control and data flow in the application so that each compartment has only the permissions it requires to do its job** - Application of the principle of least privilege to software - Here *permission* mostly refer to memory (data/code) access but also includes filesystem access, system calls, hardware/software resource usage, etc. -- | | Crypto library (comp. 1) | HTTP parser (comp. 2) | |--------------------|-------------------------|-------------------------| | Crypto keys | read access | no access | | HTTP request data | no access | read access | Lampson's **access control matrix** --- # Compartmentalisation: Trust Models - 3 trust models: - **Sandbox**: part of the program is untrusted, isolated the rest of the program (trusted) from it - **Safebox**: part of the program is security critical, isolated it from the rest of the program (untrusted) - **Mutual distrust**: compartments distrust each others - Stronger generalisation of the other 2 models - All generalise to more than 2 compartments
--- ## Compartmentalisation: Security Properties - **3 security properties considered**: - **Confidentiality**: an attacker cannot read/leak information from outside of a subverted compartment -- - **Integrity**: an attacker cannot write/tamper with data outside of a subverted compartment -- - **Availability**: an attacker cannot disrupt (e.g. crash) code running outside of a subverted compartment - Very hard to achieve when retrofitting without complete redesign of monolithic applications, out of scope for most existing efforts --- # Compartmentalisation in a Nutshell Basic steps for compartmentalisation: .rightsmallcol[
] --- # Compartmentalisation in a Nutshell Basic steps for compartmentalisation: .leftlargecol[ 1. Establish a **compartmentalisation policy**: decide what part of the target software goes into what compartment ] .rightsmallcol[
] --- # Compartmentalisation in a Nutshell Basic steps for compartmentalisation: .leftlargecol[ 1. Establish a **compartmentalisation policy**: decide what part of the target software goes into what compartment 2. Use **compartmentalisation abstractions** to indicate in the code compartments boundaries, private/shared data and resources, to establish communication between compartments, and to secure interfaces ] .rightsmallcol[
] --- # Compartmentalisation in a Nutshell Basic steps for compartmentalisation: .leftlargecol[ 1. Establish a **compartmentalisation policy**: decide what part of the target software goes into what compartment 2. Use **compartmentalisation abstractions** to indicate in the code compartments boundaries, private/shared data and resources, to establish communication between compartments, and to secure interfaces 3. At runtime have an **isolation mechanism** enforce the partitioning between compartments ] .rightsmallcol[
] --- # Enforcing Isolation
--- # Enforcing Isolation
-- - Also need a **privileged monitor** to perform security domain transitions - The OS kernel can play that role - Can also be a special compartment - Monitor needs to be isolated from other untrusted compartments --- # Compartmentalisation: It's in the Air .leftcol[
] .rightcol[
] --- # Example .leftcol[ ```c int global; int library_function(int *parameter) { char *cryptokey = "private"; int ret = *parameter + global + 42; return ret; } int main() { int arg = 100; global = 50; char *password = "secret"; /* ... */ int res = library_function(&arg); /* ... */ return 0; } ``` .codelink[
`22-comp-intro/example-monolithic.c`
] ] -- .rightcol[ - Policy: `library_function` in one compartment, `main` in the other. - Abstractions: use process-based isolation, establish communication with IPCs - Mechanisms: page table for isolation, and for communication use pipes (v1) and shared memory (v2) ] --- # Manual Compartmentalisation v1 - Split the program in two: 1. Main function compartment 2. Library function compartment -- .center[**Let's see first a v1 using pipes for cross-compartment communications**] Common header `comp-example-pipe.h`: ```c #ifndef EXAMPLE_COMP_PIPE_H #define EXAMPLE_COMP_PIPE_H #define PARAM_PIPE_PATH "/tmp/param.pipe" #define RESULT_PIPE_PATH "/tmp/result.pipe" #endif /* EXAMPLE_COMP_PIPE_H */ ``` .codelink[
`22-comp-intro/comp-example-pipe.h`
] --- # Manual Compartmentalisation v1 Main function compartment `comp-example-pipe-main.c`: .leftcol[ ```c #include "comp-example-pipe.h" /* ... */ int global; int main() { int arg = 100, send_fd, recv_fd; global = 50; char *password = "secret"; mkfifo(PARAM_PIPE_PATH, 0666); mkfifo(RESULT_PIPE_PATH, 0666); pid_t pid = fork(); if (pid == 0) { char *args[] = {"./te-comp", NULL}; char *envp[] = {NULL}; execve("./example-comp-pipe-lib", args, envp); return -1; } ``` ] .rightcol[ ```c // open pipe fds send_fd = open(PARAM_PIPE_PATH, O_WRONLY); recv_fd = open(RESULT_PIPE_PATH, O_RDONLY); // send param then global write(send_fd, &arg, sizeof(int)); write(send_fd, &global, sizeof(int)); // read the result int result; read(recv_fd, &result, sizeof(int)); printf("res: %d\n", result); close(send_fd); close(recv_fd); return 0; } ``` .codelink[
`22-comp-intro/comp-example-pipe-main.c`
] ] --- # Manual Compartmentalisation v1 Library function compartment `comp-example-pipe-lib.c`: .leftcol[ ```c #include "example-comp-pipe.h" /* ... */ int global; int library_function(int *parameter) { char *cryptokey = "private"; int ret = *parameter + global + 42; return ret; } int main() { int arg; int recv_fd = open(PARAM_PIPE_PATH, O_RDONLY); int send_fd = open(RESULT_PIPE_PATH, O_WRONLY); ``` ] .rightcol[ ```c read(recv_fd, &arg, sizeof(int)); read(recv_fd, &global, sizeof(int)); int result = library_function(&arg); write(send_fd, &result, sizeof(int)); close(recv_fd); close(send_fd); return 0; } ``` .codelink[
`22-comp-intro/comp-example-pipe-lib.c`
] ] --- # Manual Compartmentalisation v2 .center[**This v2 uses shared memory for cross-compartment communications**] Common header `example-comp-shm.h`: ```c #ifndef EXAMPLE_COMP_SHM_H #define EXAMPLE_COMP_SHM_H #define SHM_NAME "/example.shm" typedef struct { int param; int global; int result; } shm_data_t; #endif /* EXAMPLE_COMP_SHM_H */ ``` --- # Manual Compartmentalisation v2 Main function compartment `example-comp-shm-main.c`: .leftcol[ ```c #include "example-comp-shm.h" /* ... */ int global; int main() { shm_data_t *shared; int arg = 100; global = 50; char *password = "secret"; // Create shm int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666); shared = mmap(NULL, sizeof(shared_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); shared->param = arg; shared->global = global; ``` ] .rightcol[ ```c pid_t pid = fork(); if (pid == 0) { char *args[] = {"./te-comp", NULL}; char *envp[] = {NULL}; execve("./example-comp-pipe-lib", args, envp); return -1; } // give time for tbe lib compartment to run usleep(200); printf("res: %d\n", shared->result); munmap(shared); close(fd); return 0; } ``` .codelink[
`22-comp-intro/comp-example-shm-main.c`
] ] --- # Manual Compartmentalisation v2 Library function compartment `example-comp-shm-lib.c`: ```c #include "example-comp-shm.h" /* ... */ int global; int library_function(int *parameter) { char *cryptokey = "private"; int ret = *parameter + global + 42; return ret; } int main() { shm_data_t *shared; int fd = shm_open(SHM_NAME, O_RDWR, 0666); shared = mmap(NULL, sizeof(shm_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); global = shared->global; shared->result = library_function(&(shared->param)); munmap(shared, sizeof(shm_data_t)); close(fd); return 0; } ``` --- ## Framework-Assisted Compartmentalisation .leftcol[ ```c *int shared global; int library_function(int *parameter) { char *cryptokey = “private“; int ret = *parameter + global + 42; return ret; } int main() { * int shared arg = 100; global = 50; char *password = “secret“; /* ... */ * int res = GATE(library_function, &arg); /* ... */ return 0; } ``` ] .rightcol[ - Policy: `library_function` in one compartment, `main` in the other. - Compartmentalisation: - Add a gate performing security domain switch (mechanism) - Identify shared data and allocate it somewhere accessible from both compartments - Can be achieved with several (mostly research) frameworks ] --- # Summary - Can't continue seeing systems software applications as single unit of trust - Need privilege-reduction efforts within applications - Software compartmentalisation decomposes programs into less-privileged compartments - Can be designed for, or retrofitted - Frameworks can help, but it is generally a lot of work