# Reference Monitors The reference monitor is an abstract concept > An access control concept that refers to an abstract machine that mediates all access to objects by subjects - Must be tamper-proof - Must *always be invoked* when access to an object is required - Must be small enough to be verifiable / subject to analysis to ensure correctness ##### Placement - Can be placed anywhere within the system - Hardware - dedicated registers for defining privileges - Operating system kernel - virtual machine hypervisor - Operating system - Windows security reference monitor - Services layer - `JVM`, `.NET` - Application layer - Firewalls Reference monitors could be placed in a variety of locations relative to the program being run ![1645471173.png](img/1645471173.png) The last example where the program contains its own reference monitor, as found in Windows XP, is a terrible idea - it leaves permissions down to the developer. ###### Lower is better - Using a reference monitor or other security features at a lower level means: - We can **assure** a higher degree of security - Usually **simple structures** to implement - Reduced performance **overheads** - Has to be extremely quick as many calls will be made - Fewer layer below attack possibilities - However - Access control decisions are far removed from applications #### OS Integrity - The operating system - Arbitrates access requests - Is itself a resource that must be accessed - This is a conflict, we want to use the OS but not mess with it > Users must not be able to modify the operating system - Modes of operation - Defines which actions are permitted in which mode e.g. system calls, machine instructions, I/O - Controlled Invocation - Allows us to execute privileged instructions safely, before returning to user code We must distinguish computations done on behalf of: - The OS - The user A status flag within the CPU allows the OS to operate in different modes ![1645471731.png](img/1645471731.png) In practice, Windows and Unix only use Ring 0&3 to save on overhead ### Controlled Invocation - Many functions are held at kernel level, but are quite reasonably called from within user-level code - Network and File IO - Memory allocation - Halting the CPU (at shutdown only) - We need a mechanism to transfer safely between kernel mode (ring 0) and user mode (ring 3) > We don’t actually perform privileged operations, we asking the operating system to perform them for us - The operating system can refuse to do it ##### Interrupts - Exceptions or Interrupts - In many ways is the hardware equivalent to a software exception - not always bad - Handled by an interrupt handler which resolves the issue and returns to the original code Processing an Interrupt - Given an interrupt, the CPU will switch execution to location given in an interrupt descriptor table ![1645472211.png](img/1645472211.png) #### Descriptors and Selectors - Descriptors hold information on crucial system objects like kernel structure locations - Descriptors are held in descriptor tables - Contain a Descriptor Privilege Level (DPL) - Descriptors are indexed by selectors - Loaded when required (jump calls) - The CPU protects the kernel by checking the Current Privilege Level (CPL) when a Selector is loaded ##### Interrupt Gates - The code segment (CS) register in x86 CPUs has 2-bits reserved for the Current Privilege Level (CPL) - Descriptors that have a privilege level higher than where they point are called gates - Since these descriptors are created by the kernel, they offer a secure means of entry into ring 0 ![1645472444.png](img/1645472444.png) ###### Modern Kernels - Intel introduced the `sysenter` and `sysexit` operations with the Pentium II - performs with much less overhead ![1645472755.png](img/1645472755.png) We go immediately into ring 0 However where we go next is dictated by the `sysenter` pointer, users cannot write to `sysenter` #### Patching the Kernel - If you can run custom PL 0 code, you can insert your own handler - **Rootkit** ![1645473063.png](img/1645473063.png) ## Memory Protection - A process is a program being executed currently - Important unit of control - Exists in its own address space - Communicates with other processes via the OS - Separation for security - A thread is a strand of execution within a process - Share a common address space - Segmentation - divides data into logical units - Good for security - Challenging memory management - Not used much in modern OSs - Modern OSs only have two segments, one for user space, the other for kernel space - Paging - divides memory into pages of equal size - Efficient memory management - Less good for access control - Extremely common in modern OSs ##### Page Tables - All processes see an individual linear address space - Page tables map from a linear address space to the physical address space ![1645473936.png](img/1645473936.png) ###### Meltdown - In most operating systems, the entire kernel is stored in the upper address space - Pages in this area are flagged as supervisor, and cannot be accessed outside ring 0 - Meltdown is an exploit that allows us to read this privileged memory - We do this using a *side-channel* ![1645474135.png](img/1645474135.png) - In Intel CPUs, it’s common to speculatively evaluate code prior to reaching it - E.g. conditionals - **Significant** speed-up - No harm done, changes are just rolled back - But the **cache isn’t rolled back** - This is called side-channelling and cache timing ```java ... w = illegal_instruction; x = memory[data * 4096]; ... ``` - When the CPU runs this code, it will take a significant amount of time to determine that `w` shouldn’t be run, however by that point the speculative code has run `memory[data*4096]`. - We won’t see the result as it’ll be discarded once it is discovered `w` was an illegal instruction, although it will appear in cache ![1645474511.png](img/1645474511.png) - When all the cache is loaded, one page will load significantly quicker than others as it was loaded during speculative running. ###### Attack steps 1. Flush the cache 2. CPU speculatively evaluates our read using *data* 3. Read all pages pointed to by `memory[]` and time it 4. Page 117 was quicker - Meltdown attempts to read a value from kernel memory - Read from kernel - Mask out single bit - Access user memory at that location - If we repeat we can read all memory in kernel space