Distrustful Decomposition pattern
Description
When using a monolithic application, a single process must be granted all the privileges necessary for the application to operate. This issue is resolved by the Distrustful Decomposition
pattern.
The purpose of the Distrustful Decomposition
pattern is to divide application functionality among individual processes that require different levels of privileges, and to control the interaction between these processes instead of creating a monolithic application.
Using the Distrustful Decomposition
pattern reduces the following:
- Attack surface for each process.
- Functionality and data that a hacker will be able to access if one of the processes is compromised.
Alternate names
Privilege Reduction
.
Context
Different functions of an application require different levels of privileges.
Problem
An unsophisticated implementation of an application combines many functions requiring different privileges into one component. This component would need to be run with the maximum level of privileges required for any one of these many functions.
Solution
The Distrustful Decomposition
pattern divides functionality among individual processes and isolates potential vulnerabilities within a small subset of the system. A cybercriminal who conducts a successful attack will be able to use only the functionality and data of a single compromised component instead of the entire application.
Structure
This pattern divides one monolithic application into multiple applications that are run as individual processes that could potentially have different privileges. Each process implements a small, clearly defined set of functions of the application. Processes use interprocess communication mechanism to exchange data.
Operation
- In KasperskyOS, an application is divided into processes.
- Processes can exchange messages via IPC.
- A user or remote system connects to the process that provides the necessary functionality with the level of privileges sufficient to perform the requested functions.
Implementation recommendations
Interaction between processes can be unidirectional or bidirectional. It is recommended to always use unidirectional interaction whenever possible. Otherwise, the potential attack surface of individual components increases, which reduces the overall security of the entire system. If bidirectional IPC is used, processes should not trust bidirectional data exchange. For example, if a file system is used for IPC, file contents cannot be trusted.
Specialized implementation in KasperskyOS
In universal operating systems such as Linux or Windows, this pattern does not use anything except the standard process/privileges model that already exists in these operating systems. Each program is run in its own process space with potentially different privileges of the specific user in each process. However, an attack on the OS kernel would reduce the effectiveness of this pattern.
Use of this pattern when developing for KasperskyOS means that control over processes and IPC is entrusted to the microkernel, which is difficult to successfully attack. The Kaspersky Security Module is used for IPC control.
Use of KasperskyOS mechanisms ensures a high level of reliability of the software system with the same or less effort required from the developer when compared to the use of this pattern in programs running under universal operating systems.
In addition, KasperskyOS provides the capability for flexible configuration of security policies. Moreover, the process of defining and editing security policies is potentially independent of the process of developing the applications.
Linked patterns
Use of the Distrustful Decomposition
pattern involves use of the Defer to Kernel and Policy Decision Point patterns.
Implementation examples
Examples of an implementation of the Distrustful Decomposition
pattern:
Sources of information
The Distrustful Decomposition
pattern is described in detail in the following resources:
- Chad Dougherty, Kirk Sayre, Robert C. Seacord, David Svoboda, Kazuya Togashi (JPCERT/CC), "Secure Design Patterns" (March-October 2009). Software Engineering Institute. https://resources.sei.cmu.edu/asset_files/TechnicalReport/2009_005_001_15110.pdf
- Dangler, Jeremiah Y., "Categorization of Security Design Patterns" (2013). Electronic Theses and Dissertations. Paper 1119. https://dc.etsu.edu/etd/1119
Secure Logger example
The Secure Logger
example demonstrates use of the Distrustful Decomposition pattern for separating event log read/write functionality.
Example architecture
The security goal of the Secure Logger
example is to prevent any possibility of distortion or deletion of information from the event log. This example utilizes the capabilities provided by KasperskyOS to achieve this security goal.
A logging system can be examined by distinguishing the following functional steps:
- Generate information to be written to the log.
- Save information to the log.
- Read entries from the log.
- Provide entries in a convenient format for the consumer.
Accordingly, the logging subsystem can be divided into four processes depending on the required functional capabilities of each process.
For this purpose, the Secure Logger
example contains the following four programs: Application
, Logger
, Reader
and LogViewer
.
- The
Application
program initiates the creation of entries in the event log maintained by theLogger
program. - The
Logger
program creates entries in the log and writes them to the disk. - The
Reader
program reads entries from the disk to send them to theLogViewer
program. - The
LogViewer
program sends entries to the user.
The IPC interface provided by the Logger
program is intended only for writing to storage. The IPC interface of the Reader
program is intended only for reading from storage. The example architecture looks as follows:
- The
Application
program uses the interface of theLogger
program to save log entries. - The
LogViewer
program uses the interface of theReader
program to read the log entries and present them to a user.
The LogViewer
program normally has external channels for interacting with a user (for example, to receive data write commands and to provide data to a user). Naturally, this program is an untrusted component of the system, and therefore could potentially be used to conduct an attack. However, even if a successful attack results in the infiltration of unauthorized executable code into the LogViewer
program, information in the log cannot be distorted through this program. This is because the program can only utilize the data read interface, which cannot actually be used to distort or delete data. Moreover, the LogViewer
program does not have the capability to gain access to other interfaces because this access is controlled by the security module.
A security policy in the Secure Logger
example has the following characteristics:
- The
Application
program has the capability to query theLogger
program to create a new entry in the event log. - The
LogViewer
program has the capability to query theReader
program to read entries from the event log. - The
Application
program does not have the capability to query theReader
program to read entries from the event log. - The
LogViewer
program does not have the capability to query theLogger
program to create a new entry in the event log.
Example files
The code of the example and build scripts are available at the following path:
Building and running example
See Building and running examples section.
Page topSeparate Storage example
The Separate Storage
example demonstrates use of the Distrustful Decomposition pattern to separate data storage for trusted and untrusted applications.
Example architecture
The Separate Storage
example contains two user programs: UserManager
and CertificateManager
.
These programs work with data located in the corresponding files:
- The
UserManager
program works with data from theuserlist.txt
file. - The
CertificateManager
program works with data from thecertificate.cer
file.
Each of these programs uses its own instance of the VFS program to access a separate file system. Each VFS program includes a block device driver linked to an individual logical drive partition. The UserManager
program does not have access to the file system of the CertificateManager
program, and vice versa.
This architecture guarantees that if there is an attack or error in any of the UserManager
or CertificateManager
programs, this program will not be able to access any file that was not intended for the specific program's operations.
A security policy in the Separate Storage
example has the following characteristics:
- The
UserManager
program has access to the file system only through theVfsUser
program. - The
CertificateManager
program has access to the file system only through theVfsCertificate
program.
Example files
The code of the example and build scripts are available at the following path:
Building and running example
To run an example on QEMU, go to the directory containing the example, build the example and run the following commands:
See also Building and running examples section.
Preparing an SD card to run on Raspberry Pi 4 B
To run the Separate Storage
example on Raspberry Pi 4 B, the following additional actions are necessary:
- Create a
/lib
directory in the SD card boot sector unless one already exists. - Copy the contents of the
build/hdd/part1/lib
directory that was generated while building the example to the/lib
directory in the SD card boot sector. - The SD card must contain both a bootable partition with the solution image as well as 2 additional partitions with the
ext2
orext3
file systems. - The first additional partition must contain the
userlist.txt
file from the./resources/files/
directory. - The second additional partition must contain the
certificate.cer
file from the./resources/files/
directory.
To run the Separate Storage
example on Raspberry Pi 4 B, you can use an SD card prepared for running the vfs_extfs
example on Raspberry Pi 4 B after copying the userlist.txt
and certificate.cer
files to the appropriate partitions.