186 lines
6.5 KiB
Markdown
186 lines
6.5 KiB
Markdown
# 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
|
||
|
||

|
||
|
||
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
|
||
|
||

|
||
|
||
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
|
||
|
||

|
||
|
||
#### 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
|
||
|
||

|
||
|
||
###### Modern Kernels
|
||
|
||
- Intel introduced the `sysenter` and `sysexit` operations with the Pentium II
|
||
- performs with much less overhead
|
||
|
||

|
||
|
||
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**
|
||
|
||

|
||
|
||
## 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
|
||
|
||

|
||
|
||
###### 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*
|
||
|
||

|
||
|
||
- 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
|
||
|
||

|
||
|
||
- 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
|