class: center, middle ### Secure Computer Architecture and Systems *** # Software Compartmentalisation Mechanisms ??? - Hi everyone, welcome to this last video on software compartmentalisation - Here we are going to cover the mechanisms that enforce the isolation between different compartments --- # Compartmentalisation Mechanisms .leftcol[ - A **compartmentalisation mechanism** enforces at runtime the separation defined by policies and implemented through abstractions - All mechanisms suitable for compartmentalisation must allow: ] ??? - A compartmentalisation mechanism enforces at runtime the isolation between compartments, as defined by policies and implemented through abstractions - All the mechanisms one wishes to use for compartmentalisation must allow the following --- # Compartmentalisation Mechanisms .leftcol[ - A **compartmentalisation mechanism** enforces at runtime the separation defined by policies and implemented through abstractions - All mechanisms suitable for compartmentalisation must allow: - Isolated **protection domains** ] .rightcol[
] ??? - First compartments represent different protection domains that isolated and the mechanism should prevent a compartment from reading, writing, or executing data and code in the memory of another compartment --- # Compartmentalisation Mechanisms .leftcol[ - A **compartmentalisation mechanism** enforces at runtime the separation defined by policies and implemented through abstractions - All mechanisms suitable for compartmentalisation must allow: - Isolated **protection domains** - Controlled **communications** between domains ] .rightcol[
] ??? - Second, the mechanism should allow safe and controlled communications between compartments that need to communicate - In other words the CALL and RETURN abstractions we previously mentioned should be implementable with the considered mechanism - The mechanism should also ensure a form of cross compartment control flow integrity: the communications should allow a compartment A to invoke a compartment B only through well defined interface and not at arbitrary points in B's code - ideally, the data exchanged between compartments should also be limited to the data required for communication: anything more than that would be oversharing, which decreases the level of security --- # Examples of Mechanisms - **Hardware**: - **Page tables**: compartment are processes - **CPU Privilege levels**: compartmentalise user and kernel space, e.g. in a micro-kernel - **Memory protection keys**: compartmentalise threads within a single address space - **Trusted Execution Environments**: enclaves, confidential VMs, world separation ??? - Let me give you a few examples of isolation mechanisms - Many mechanisms are provided by the hardware - I have mentioned several times process-based compartmentalisation, where each compartment runs within its own process - In that case the mechanism used to isolated compartment is the page tables - Another mechanism that isolates something like the kernel from the user space is done through the privilege levels on the CPU - Memory protection keys is another mechanism that allows to create multiple compartments within a single address space - We also mentioned in the past trusted execution environments, that provide strong isolation even in the presence of malicious privileged layers such as the OS -- - **Software**: - **Software fault isolation** - **Memory safe languages** - **Bounds-checking software** ??? - The isolation mechanism can also be implemented in software - Software Fault Isolation is a compiler-level technique, in which the code of compartments is generated in such a way that it cannot escape a sandbox - Control transitions such as jump or calls are also generated in such a way that they can only target legitimate code locations, enforcing control flow integrity. - Memory safe language can be seen as a form of isolation mechanism that prevent the memory safety issues we covered previously, that could allow a compartment to access memory it is not supposed to - Finally, bounds checking software such as FAT pointer augment the pointers with information about the bounds of the objects they point to. - When these pointers are dereferenced, these bounds are checked before the access can be done, which gives more guarantees that a compartment won't be able to access memory it is not supposed to read or write --- # Cross-Compartment Communications - In addition to `CALL`/`RETURN`, mechanism must support some form of **data exchange** - E.g. to pass parameters and return a value to/from a cross-compartment call ??? - Regarding communications between compartment, mechanism must support some form of CALL and return primitives to transition between compartments - In addition to that, the mechanisms should also support a way to exchange data between compartments upon such transitions - For example to pass parameters or return value when there is a cross compartment call - But also to handle the data pointed by reference parameters exchanged across compartments -- - 2 methods: - **Message passing**: data is sent and received over a communication channel, generally involving one or more copies - E.g. IPCs such as pipes or sockets - Slow but secure - **Shared memory**: compartments share an address space or part of it, exchange references (pointers) - Faster but less secure: TOCTTOU possible if compartments run concurrently ??? - To achieve data exchange there are 2 main methods - The first one is message passing: the data is sent and receive between compartments over some form of communication channel, generally involving one or more data copies - This is the case with IPCs such as pipes or sockets - This is slow, because of the copies and potentially the need to put the data into a format suitable for communications - However it is also very secure, as data is never accessible from more than one compartment at a time - The second method for data exchange is shared memory - Compartment can establish a portion of shared memory, so they can share part or even their entire address space - Doing so, they don't need to send and receive data, they simply need to send and receive reference to that data, which are much smaller - Hence shared memory is much faster than message passing - However it is also less secure: if not managed properly, because 2 communicating compartments can access the shared memory at the same time, there is a risk for race conditions and time-to-check-to-time-to-use attacks --- # Trust Models - Mechanisms are **designed with a trust model in mind**, e.g.: - CPU privilege levels in the page table targets single distrust - the page tables themselves isolate processes for mutual distrust ??? - Each mechanism is designed with a specific trust model in mind - For example CPU privilege levels targets single distrust: the kernel distrust the application, which itself trusts the kernel - Other mechanisms target mutual distrust, such as the page table establishing different address spaces for different processes, or trusted execution environments -- - Mechanisms influence the content of the **TCB**: - In general TCB comprises (part of) the workload, compiler, loader, system software, firmware, CPU package, and physical environment - TEE mechanisms allow some reduction of the TCB ??? - Mechanisms will also influence the content of the trusted computing base - In general, from the point of view of a compartment, the trusted computing base will contain at least the compartment's code, the system's loader, the motherboard firmware, BIOS, the OS and hypervisor and their boot processes, as well as the machine's physical environment - Some mechanisms, like trusted execution environments, allow reducing that TCB, by removing the OS and hypervisor --- # Hardware vs. Software Mechanisms - Most approaches employ **hardware mechanisms** - For **speed, and application compatibility** reasons, but must have proper hardware - Examples: page tables, memory protection keys, memory virtualisation extensions, TEE enclaves/confidential VMs, bound-checking hardware, hardware capabilities ??? - As we saw mechanisms can be implemented either in hardware or in software - Hardware mechanisms are able to provides isolation that is both strong, and also relatively fast - Several hardware mechanisms will also be compatible with many types of software, independently of the language it's written in - Obviously the downside is that you need to have access to the hardware in question - You have a few examples of hardware mechanisms here -- - There also exists **software mechanisms** - **Slower and less compatible**, but available independently of the hardware - Examples: memory safe languages, software fault isolation, software capabilities ??? - Mechanisms can also be implemented in software - They are generally slower, and less compatible, some being for example only compatible with a particular programming language - But the good thing is that you don't need to get access to specific hardware to use them - You have a few examples of these on the slide --- # More Mechanisms Aspects - **Permissions enforced**: combination of **read**, **write**, **execute** and **address** (create a pointer to) - Not all mechanisms support all permissions ??? - A few more aspects regarding mechanisms that are worth discussing - Mechanisms will enforce different permissions, generally a combination of read/write/execute, but also address -- in the sense of the ability for a compartment to create a reference to a resource or an area of memory - Not all mechanisms support all permissions, for example Intel's implementation of memory protection keys support only enforcing read/write access, read-only access, or no read/write access at all, and there is no support for preventing execution -- - **Enforcement granularity**: most either target the page (4KB) or byte granularity - May have implication on memory consumption or oversharing ??? - The enforcement granularity varies depending on the mechanisms - Some like the page table will allow or deny memory accesses at the granularity of a 4KB memory pages - While others, such as bound checking software, will provide byte level memory protection - These considerations have implications in terms of memory consumption and oversharing compartmentalised applications using these mechanisms -- - **Number of domains**: may be limited with certain mechanisms - E.g. MPK has 16 domains max, can be increased through virtualisation (performance hit) - Overall increasing the number of domains may lead to scalability issues ??? - Certain mechanism also support a limited number of domains, for example 16 only with Intel Memory Protection keys - With MPK this number can be increased with some forms of virtualisation, at the cost of a non negligible performance slowdown - More generally, the more compartments you have, the more scalability issue with arise --- # Performance Considerations - **Mechanisms impact performance in many ways:** - Compartment switching latency, domain-crossing sanitisation costs - Compartment creation/destruction delays - Cost of setting/updating permissions - Memory fragmentation, access locality and cache effects - Scalability to compartment size/number ??? - Speaking about performance, the mechanism chosen will have a huge impact on a compartmentalised application's speed - It will be impacted by the domains switching, and the costs to sanitise data crossing domain boundaries - Creating and destructing compartments may be costly, so is setting up and updating compartments permissions - The way memory needs to be organised to ensure the shared or private nature of data will impact performance due to memory fragmentation, access locality and its impact on the caches - Finally, as mentioned previously scalability issue may arise due to too many compartments, or compartments that are too large -- - **Dominating factor is often the domain switching latency** - Variable among mechanisms, but modern exception-free approaches tend to be much faster ??? - Still today the dominating factor is the domain switching latency - For that reason, the most up-to-date compartmentalisation approaches rely on mechanisms that work within a single address space to avoid context switches, and that can also perform security domain switches without relying on an exception contrary to something like system calls --- # Summary - **Compartmentalisation mechanism**: - Technology that enforces the isolation between compartments at runtime - And allows them to communicate in a controlled way - Can be implemented in hardware or software - Enforce various trust models and enable different communications method - Overall, **picking a mechanism means choosing a trade-off between security, performance, engineering effort** ??? - To sum up, we talked about compartmentalisation mechanisms, the technology that enforce the isolation between compartments at runtime, and allows them to communicate securely - These mechanisms can be implemented either in hardware, or in software - They enforce various trust models and enabled different communication methods - Overall, when you pick a mechanism to compartmentalise an application, this will have an important impact on the security, performance, and engineering effort