Alyssa Ross, 2018-2019.
You may distribute this work under the terms of either the CC-BY-SA license (version 4.0 or later), or the GNU Free Documentation License (version 1.2 or later), at your option.
Existing attempts to improve on the security of Unix-like operating systems for everyday personal use have been hampered by complexity, bugs, and security theatre. The concept of isolating applications by giving them what appears to be a dedicated computer to run in is a solid one, because it allows virtually all existing software to run without modification. However, allowing all these isolated computers to persist state leads to large maintenance costs — you now have n stateful computers to maintain, not one.
By minimizing the persistent state these computers are allowed to store to a well-defined absolute minimum required by the software running inside them, not only do we improve maintainability by minimising side effects and even allowing the computers to be regenerated without data loss if required, we also massively reduce the avenues to persisting malware.
Mutable state across the whole system isolated into two locations on the host: a global state store, which is broken down by application instance, and a global configuration file defining all configuration for the host, and the isolated environments for each application instance. Aside from these two locations, the host computer should prevent persistent state as much as possible. This means that it is possible to restore the host computer, along with all the isolated application environments, simply by restoring a copy of the global state store and configuration file. After an audit of the global configuration, a potentially compromised host could be safely restored onto a new computer without risk of the new host inheriting the infection from the old one, since the only mutable data affecting the host is the global configuration file. (Of course, this does not prevent the new host from being compromised shortly afterward through the same methods.)
Qubes OS is a distribution of the Xen hypervisor that isolates IO and user applications inside their own dedicated virtual machines. Many people interested in secure computing are aware of Qubes, however they are often hampered by usability issues:
However, the Qubes developers have created utilities for using compartmentalized environments that could be very useful to other implementations. For example, Qubes allows clipboard data to be safely shared between isolated environments with explicit user action on both ends, and Qubes Split GPG allows one environment to perform operations using a GPG key stored in another environment, with permission granted on a per-operation basis.
Subgraph only provides isolation to the 22 applications they have manually containerized. Any other software is still run as normal. We consider this a major security issue.
The last release of SubgraphOS was an alpha in 2017.
Because of the explosion of interest in compartmentalized computing in recent years, there exists a plethora of existing work that can be harnessed to implement these concepts.
A container is an isolated computing environment created using a variety of features of the Linux kernel. A container can be almost entirely isolated from the host system, and those components that are shared can likely be made inaccessible to isolated applications by denying them root access to their isolated environments. Unlike virtual machines, containers share a kernel with the host operating system, and do not require specially allocated resources (although it is still possible to limit resource use by a container). This makes containers able to deliver good performance with far looser hardware requirements than virtual machines.
In the proof of concept implementation, Docker, a popular implementation of containers, is used. However, there is probably not any tight coupling to Docker-specific features, and so Docker could most likely be easily swapped out for another container implementation, or even for virtual machines.
Containers have mostly been designed for isolating headless server applications. Additional challenges present themselves when applying container-based application isolation to personal computing.
The X11 protocol provides no isolation between applications whatsoever. Any application (including one running on a remote server using SSH X forwarding) can capture windows of other applications, read from them, and even send events to them freely. The solution to this problem is to use a separate X server for each container, and then forward them over another protocol (such as VNC) to the window manager running either on the host or, preferably, in a dedicated container of its own. The pre-existing Xpra software provides this capability. Doing this inevitably gives rise to yet more problems, mostly around performance, although these should be solvable also:
Given the fundamental shortcomings in X, it might seem obvious to use Wayland instead. Unlike X, Wayland was designed with security and isolation between applications in mind. However, existing Wayland implementations have no way of controlling isolation between applications. A single Wayland compositor could provide e.g. clipboard isolation in a similar way to Qubes or Xpra, but this doesn't exist yet. Writing a Wayland compositor is not a simple task, even with a library like wlroots that does a lot of heavy lifting, and it would also couple a user to a single window manager or desktop environment. While Wayland is extremely usable for general-purpose desktop computing at this point, until a solution for these issues is reached, Wayland is not suitable for a compartmentalized operating system.
The proof of concept implementation is built on top of NixOS Linux, an operating system which is itself built on Nix, a purely functional package manager. Nix provides pure packages (meaning packages will be built from identical inputs each time — their outputs will not necessarily be byte-identical). NixOS makes it possible to define an entire GNU/Linux system in this manner.
However, NixOS does not attempt to completely eliminate undeclared state — it even allows for imperative package installation, which makes a Nix package that has not been defined in the global configuration available in the current environment. Responsibility for eliminating this sort of mutable state lies with the Spectrum implementation.
The nixpkgs repository provides functions for generating Docker containers from Nix expressions, using existing Nix package definitions. These containers are not full NixOS installations — in fact, they don't even have Nix or coreutils installed by default. This ensures only the minimum software required for the isolated application to run is available, reducing attack surface.
NixOS provides its own container implementation, based on systemd-nspawn however this is not suitable for security by compartmentalization. Firstly, it is designed to contain full installations of NixOS, rather than single applications. Further, it has apparently proven to be unreliable and suffer breakages, and its focus is not on providing truly isolated computing environments. By contrast, other container implementations (such as, but not exclusively, Docker), have reached a point of relative stability, and had extensive resources put into making them as isolated as possible from the host system.
I have just begun full time work on Spectrum. Source code repositories and discussion channels will be made available as soon, and I will publish regular status updates. The first of these can be found on my blog. to make it as clear as possible that Spectrum is not vapourware, and that progress is rapidly being made.
Update Current status to reflect that full time work can now begin.
Add current status section.
Fix typo: "thins" → "this".