Design of the Genode OS Architecture: Goals and Challenges
The Genode architecture is designed to accommodate the following types of components in a secure manner concurrently on one machine:
- Device drivers
-
Device drivers translate the facilities of raw physical devices to device-class-specific interfaces to be used by other components. They contain no security policies and provide their services to only one client component per device.
- Services that multiplex resources
-
To make one physical resource (e.g., a device) usable by multiple components at the same time, the physical resource must be translated to multiple virtual resources. For example, a frame buffer provided by a device driver can only be used by one client at the same time. A window system multiplexes this physical resource to make it available to multiple clients. Other examples are an audio mixer or a virtual network hub. In contrast to a device driver, a resource multiplexer deals with multiple clients and therefore, plays a crucial role for maintaining the independence and isolation of its clients from each other.
- Protocol stacks
-
Protocol stacks translate low-level protocols to a higher and more applicable level. For example, a file system translates a block-device protocol to a file abstraction, a TCP/IP stack translates network packets to a socket abstraction, or a widget set maps high-level GUI elements to pixels. Compared to resource multiplexers, protocol stacks are typically an order of magnitude more complex. Protocol stacks may also act as resource multiplexers. In this case however, high complexity puts the independence and isolation of multiple clients at a high risk. Therefore, our design should enable the instantiation of protocol stacks per application. For example, instead of letting a security-sensitive application share one TCP/IP stack with multiple other (untrusted) applications, it could use a dedicated instance of a TCP/IP stack to increase its independence and isolation from the other applications.
- Containers for executing legacy software
-
A legacy container provides an environment for the execution of existing legacy software. This can be achieved by the means of a virtual machine (e.g., a Java VM, a virtual PC), a compatible programming API (e.g., POSIX, Qt), a language environment (e.g., LISP), or a script interpreter. In the majority of cases, we regard legacy software as an untrusted black box. One particular example for legacy software are untrusted legacy device drivers. In this case, the container has to protect the physical hardware from potentially malicious device accesses by the untrusted driver. Legacy software may be extremely complex and resource demanding, for example the Firefox web browser executed on top of the X window system and the Linux kernel inside a virtualized PC. In this case, the legacy container may locally implement sophisticated resource-management techniques such as virtual memory.
- Small custom security-sensitive applications
-
Alongside legacy software, small custom applications implement crucial security-sensitive functionality. In contrast to legacy software, which we mostly regard as untrusted anyway, a low TCB complexity for custom applications is of extreme importance. Given the special liability of such an application, it is very carefully designed to have low complexity and require as little infrastructure as possible. A typical example is a cryptographic component that protects credentials of the user. Such an application does not require swapping (virtual memory), a POSIX API, or a complete C library. Instead, the main objectives of such an application are to avoid as much as possible code from being included in its TCB and to keep its requirements at a minimum.
Our design must be able to create and destroy subsystems that are composed of multiple such components. The isolation requirement as stated in the introduction raises the question of how to organize the locality of name spaces and how to distribute access from components to other components within the system. The independence requirement demands the assignment of physical resources to components such that different applications do not interfere. Instead of managing access control and physical resources from a central place, we desire a distributed way for applying policy for trading and revocating resources and for delegating rights.