Components
The architecture introduced in Chapter Architecture clears the way to compose sophisticated systems out of many building blocks. Each building block is represented by an individual component that resides in a dedicated protection domain and interacts with other components in a well-defined manner. Those components do not merely represent applications but all typical operating-system functionalities.
Components can come in a large variety of shape and form. Compared to a monolithic operating-system kernel, a component-based operating system challenges the system designer by enlarging the design space with the decision of the functional scope of each component and thereby the granularity of componentization. This decision depends on several factors:
- Security
-
The smaller a component, the lower the risk for bugs and vulnerabilities. The more rigid a component's interfaces, the smaller its attack surface becomes. Hence, the security of a complex system function can potentially be vastly improved by splitting it into a low-complexity component that encapsulates the security-critical part and a high-complexity component that is uncritical for security.
- Performance
-
The split of functionality into multiple components introduces inter-component communication and thereby context-switch overhead. If a functionality is known to be performance critical, such a split should clearly be motivated by a benefit for security.
- Reusability
-
Componentization can be pursued to improve reusability while sometimes disregarding performance considerations at the same time. However, reusability can also be achieved by moving functionality into libraries that can easily be reused by linking them directly against library-using components. By using a dynamic linker, linking can even happen at run time, which yields the same flexibility as the use of multiple distinct components. Therefore, the split of functionality into multiple components for the sole sake of modularization has to be questioned.
Sections Device drivers, Protocol stacks, Resource multiplexers, and Runtime environments and applications aid the navigation within the componentization design space by discussing the different roles a component can play within a Genode system. This can be the role of a device driver, protocol stack, resource multiplexer, runtime environment, and that of an application. By distinguishing those roles, it becomes possible to assess the possible security implications of each individual component.
The versatility of a component-based system does not come from the existence of many components alone. Even more important is the composability of components. Components can be combined only if their interfaces match. To maximize composability, the number of interfaces throughout the system should be as low as possible, and all interfaces should be largely orthogonal to each other. Section Common session interfaces reviews Genode's common session interfaces.
Components can be used in different ways depending on their configuration and their position within the component tree. Section Component configuration explains how a component obtains and processes its configuration. Section Component composition discusses the most prominent options of composing components.