class: big, middle # ECE 7420 / ENGI 9823: Security .title[ .lecture[Lecture 15:] .title[Compartmentalization] ] --- # Recall ### Access control: * DAC (discretionary access control) * MAC (mandatory access control) -- ### Today: sandboxing * below the OS: Jails, VMs and containers * in the OS: capability-based security --- # Sandboxing <img src="https://www.publicdomainpictures.net/pictures/320000/velka/sand-castle-on-the-beach-1580301339hg3.jpg" align="right" width="500"/> ### Concept ??? The term _sandboxing_ comes from the idea of providing a safe, non-permanent place in which to playfully build and destroy things. Sand castles are fun but impermanent: whatever structure you put into them will be washed away by the waves (another example of entropy at work!). In computing, a sandbox is a notional container in which software can do whatever it likes, doing some sort of useful work, but **confined** so that any malicious actions will have **no effect outside of the sandbox**. it's useful to be able to apply such _confinement_ or _isolation_ to suspect software which may be malicious from inception — this means that **we don't have to trust it**. However, it's also helpful for software that **starts well but is compromised by an attacker** – a far more frequent necessity! This does not **prevent attacks**, but it can **limit their damage**. -- ### Reality: * Processes and virtualization ??? You might well think, "wait a minute, **aren't all processes isolated**"? That's certainly the abstraction we've provided thus far. **Virtualization** ensures that processes can't directly affect each other. However, **OS abstractions like files** break this tidy isolation. Furthermore, they are necessary: what would be the point of **a program that can't leave _any_ traces of execution behind**? -- * DAC and MAC ??? Given that OS abstractions are the weak link here, it's not suprising that people have tried to use OS measures to **confine** programs. We've seen DAC and MAC already, and there are DAC and MAC policies that can provide at least some level of sandboxing. -- * Jails, VMs, containers ??? Today we'll also talk about further levels of **virtualization** to implement sandboxing. -- * Capabilities ??? We'l also talk about a very different approach that uses a concept called **capabilities**. --- # DAC-based sandboxing ??? One way to prevent applications from accessing OS resources like **files, sockets, etc.** is using Discretionary Access Control. -- ### Unix * `chroot(2)` and privilege separation* .footnote[ Provos, Friedl and Honeyman, ["Preventing Privilege Escalation"](https://www.usenix.org/legacy/event/sec03/tech/full_papers/provos_et_al/provos_et_al_html), _Proceedings of the 12th USENIX Security Symposium_, 2003. ] ??? Since the early 2000s, many Unix systems have used _privilege separation_ to limit the damage that can be done by a compromised application that runs with superuser privilege. A program that runs with superuser privilege can use the `chroot(2)` system call to **limit itself to a portion of the overall filesystem**. Such a program can then **change user** with `setuid(2)` to a less-privileged user account (historically called `nobody`). In such a state, a program can only access files within its `chroot` area, and it can't do things that only the superuser is allowed to do. This limits the damage that could be done **if an attacker tricker the program into doing something malicious**. -- * Android ??? In Android, each application can be assigned a different **user ID**, allowing that application to prevent other applications from accessing its DAC-controlled resources. -- ### Windows (-ish?) ??? Windows also has a concept of **security IDs (SIDs)** that can applied to subjects (processes) and objects (files, etc.) in order to enforce Discretionary Access Control. If you take away a process' SID, it can't access any labeled objects any more! -- ### Limitations ??? In all of these cases, however, there are important limitations on **what can be expressed with a DAC policy**. For example, a `chroot`-ed process may not be able to access files outside of its `chroot`, but it can still **perform arbitrary network operations**! A Windows process can be prevented from accessing all labeled objects, but when a colleague and I did some Chrome sandboxing work, we found that **external filesystems** and **network devices** didn't have SIDs! So, an attacker who compromised a "sandboxed" process running as me (e.g., a compartmentalized web browser) would be prevented from accessing my hard drive, but not **my USB stick or my VPN**! --- # MAC-based sandboxing ??? One can also use MAC to try and sandbox applications. MAC policies can be more expressive than DAC policies, so in theory this can work. -- <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/AppArmor_logo.svg/240px-AppArmor_logo.svg.png" align="right" width="200"/> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/SELinux_logo.svg/624px-SELinux_logo.svg.png" align="right" width="200"/> ### Unix * SELinux, AppArmor ??? SELinux and, later, AppArmor, brought Mandatory Access Control to Linux. It's possible to write a MAC policy that confines processes quite strictly, e.g., "browser renderer processes can never access the network". MAC is a natural way to express these kinds of **static policies**, but **dynamic policies** that refer to _this_ or _that_ renderer process are much less naturally represented by MAC. SELinux will give one process with the `chrome_sandbox_t` label the same access as another `chrome_sandbox_t`. This is a problem if our goal is to separate my Discord tab, with its complex video handling code, from my Online Banking tab. Also, these policies can be **stunningly complex**. -- * resource namespaces -- <img src="macos-file-open.png" align="right" width="400"/> ### iOS / macOS * MAC framework and "entitlements" ??? iOS and, later, macOS, brought the FreeBSD MAC Framework into a slightly more popular operating system and used it to provide confinement and isolation of applications. -- * Also _powerboxes_ (not quite MAC) ??? In order to solve the dynamic-access-to-stuff problem, it also brought in the concept of a _powerbox_ from a very different access control model: **capability-based access control**. --- # Problems with DAC and MAC ??? DAC and MAC are both very helpful forms of access control within their intended use cases. They are, however, awkward fits for the problem of **compartmentalization** (a more general description of **sandboxing**). In addition to the limitations described above, DAC and MAC have more problems in common when applied to **compartmentalization**. -- ### Dual coding ??? _Dual coding_ refers to the problem of **having to say the same thing twice**: first you write code to say **what your program should do**, then you write a security policy to say **what your program should be allowed to do**. Whenever dual coding occurs, whether it's re-implementations of an algorithm or a code/policy dichotomy, we introduce **the risk of a mismatch**. In security, mismatches typically cause us to **fail open**: people jump up and down when you **fail closed**, but when you **fail open**, the only ones who notice are **the attackers**. -- ### Privilege ??? MAC and DAC also require _privilege_ to use. Only `root` can `chroot(2)` or `setuid(2)` to limit privilege. Only a system administrator can install a MAC policy. Thus, in order to limit privilege, you have to first **have privilege**! This leads to unhelpful situations in which, e.g., a `setuid-root` binary (a huge security risk) is required in order to implement a security mechanism! **This is, by the way, a tension in a lot of security contexts!** -- ### Coherence ??? Finally, DAC and MAC provide primitives that simply **don't fit the problem of sandboxing all that well**. A poorly-fitting abstraction will be a **leaky abstraction**, which can cause new problems while solving existing ones. It also spurs **mechanism-focussed thinking**: "I have a hammer, now find me something that looks like a nail!" --- # Jails and VMs -- ### _Jail:_ group of namespace-restricted processes ??? _Jails_, _zones_ or _containers_ (e.g., Docker) group a collection of processes together with some common resources. One OS kernal can host many such containers of processes. The processes run as usual, but they are much more limited in terms of what OS objects (files, devices, etc.) they are able to interact with. -- * BSD _jails_ * Solaris _zones_ * Linux _containers_ (though a bit _ad hoc_) -- ### _VM_: virtual machine * guest may be _paravirtualized_ or host may employ _emulation_ ??? _Virtual machines_ take this approach even further, virtualizing not just memory and CPU time (like a process) or an OS kernel (like a jail), but a **whole computer**. Thus, multiple operating systems can run on top of one CPU. A _paravirtualized_ OS kernel is in on the game: it knows that it's running as a regular process within a different OS, and when it wants to do privileged things like tweak virtual memory, it makes a **hypercall** to the "host" operating system. If your hardware supports virtualization extensions, however, it can run an **unmodified guest OS**, trapping on privileged instructions and allowing the host OS to emulate hardware actions like adjusting the guest's virtual memory. --- # The sandboxing cycle <img src="https://imgs.xkcd.com/comics/sandboxing_cycle.png" width="450" align="right"/> ### Source: [XKCD 2044](https://xkcd.com/2044) ??? As in so much else, XKCD spotlights an awkward truth for us... -- ### Choose your truth: -- * sharing is easy, isolation is hard -- * isolation is easy, sharing is hard -- #### Need rigorous isolation... -- and _controlled_ sharing --- # Capabilities ### Means of expressing _principle of least authority_ ??? The _principle of least authority_ (sometimes called "principle of least privilege") is the gold standard of confinement, a way of programmatically expressing and enforcing the _ad hoc_ "need to know" notion that we explored earlier in the course. Capabilities are a means that _can_ be used to express this notion, but you have to get the expression right. -- > an unforgeable token of authority -- * not a _permission_ or _entitlement_ -- * not a POSIX.1e "capability" -- * software-level example: Java references -- * system-level example: ??? ??? A system-level example of a capability is (_almost!_ ) is the _file descriptor_. Once you've opened a file, you can interact with **that specific file** and perform **specific actions** on it. However, the analogy is incomplete, because a normal DAC policy will let you do all kinds of things with a file descriptor. For example, you might want to sandbox a program so that it can only read from a file — OK, you can open it in read-only mode. However, normal Unix DAC will also let you **change the file's permissions** even though you aren't allowed to write to it! --- # Capability-based systems -- ### Languages: Java to ECMAScript 5 ??? ### Question Consider a Java object called `HashSet` with methods `add`, `remove` and `contains`. If that object is accessed through a Java interface called `ReadOnlySet`, which only has the `contains` method, will the accessing code be able to modify the set? **It depends: not if policy end-runs like reflection are disabled!** -- ### Web: Crypto URLs to WASI ??? -- ### OSes: Capsicum* to [CloudABI](https://cloudabi.org) and [Fuschsia](https://fuchsia.dev/) .footnote[ * Watson, Anderson, Laurie and Kennaway, ["Capsicum: practical capabilities for UNIX"]( https://www.usenix.org/legacy/events/sec10/tech/#Watson), in _Proceedings of the 19th USENIX Security Symposium_, 2010. ] -- ### Hardware: GE 645 to [CHERI/Morello](https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/cheri-morello.html) --- # Why capabilities? -- ### Universal mechanism -- * vs _ad hoc_ mechanisms ??? Rather than one set of mechanisms for separating processes, another set of mechanisms for separating containers and a complete different set of mechanisms for separating virtual machines, capabilities are _meant_ to provide a common way of describing objects and things you'd like to do with them. In reality, code-level capabilities, OS-level capabilities and network-level capabilities are implemented differently. However, at least they **can be aligned** with one another to express **coherent security policies**. -- * vs privileged mechanisms ??? One key element of capability-based access control is the principle that subjects should always be allowed to **monotonically reduce their privileges** without requiring **system privilege**. That is, if I have read-write access to something, I should always be able to turn that into read-only or write-only access. I shouldn't have to ask permission. -- ### Code alignment ??? Since capabilities are typically embodied in things like language references, you don't have to separately express **what code should do** and **what code should be allowed to do**. -- ### ... but requires more/better thinking ??? Sticking to a capability discipline requires thinking carefully about **what code ought to be able to see and do**. However, that discipline is the same discipline that you already need to design abstractions with good **modularity**, good **dependency management** and good **testability**. --- # Summary ### Sandboxing * DAC and MAC * Jails, VMs and containers * Capabilities ### Beyond sandboxing: compartmentalization --- class: big, middle The End.