KasperskyOS Community Edition 1.1

Overview of KasperskyOS

KasperskyOS is a specialized operating system based on a separation microkernel and security monitor.

See also:

In this Help section

Overview

KasperskyOS architecture

IPC

Resource Access Control

Structure and startup of a KasperskyOS-based solution

Page top
[Topic overview]

Overview

Microkernel

KasperskyOS is a microkernel operating system. The kernel provides minimal functionality, including scheduling of program execution, management of memory and input/output. The code of device drivers, file systems, network protocols and other system software is executed in user mode (outside of the kernel context).

Processes and endpoints

Software managed by KasperskyOS is executed as processes. A process is a running program that has the following distinguishing characteristics:

  • It can provide endpoints to other processes and/or use the endpoints of other processes via the IPC mechanism.
  • It uses core endpoints via the IPC mechanism.
  • It is associated with security rules that regulate the interactions of the process with other processes and with the kernel.

An endpoint is a set of logically related methods available via the IPC mechanism (for example, an endpoint for receiving and transmitting data over the network, or an endpoint for handling interrupts).

Implementation of the MILS and FLASK architectural approaches

When developing a KasperskyOS-based system, software is designed as a set of components (programs) whose interactions are regulated by security mechanisms. In terms of security, the degree of trust in each component may be high or low. In other words, the system software includes trusted and untrusted components. Interactions between different components (and between components and the kernel) are controlled by the kernel (see the figure below), which has a high level of trust. This type of system design is based on the architectural approach known as MILS (Multiple Independent Levels of Security), which is employed when developing critical information systems.

A decision on whether to allow or deny a specific interaction is made by the Kaspersky Security Module. (This decision is referred to as the security module decision.) The security module is a kernel module whose trust level is high like the trust level of the kernel. The kernel executes the security module decision. This type of division of interaction management functions is based on the architectural approach known as FLASK (Flux Advanced Security Kernel), which is used in operating systems for flexible application of security policies.

Microkernel connectivity with applications and drivers

Interaction between different processes and between processes and the kernel in KasperskyOS

KasperskyOS-based solution

A KasperskyOS-based solution (hereinafter also referred to as the solution) consists of system software (including the KasperskyOS kernel and Kaspersky Security Module) and applications integrated to work as part of the software/hardware system. The programs included in a KasperskyOS-based solution are considered to be components of the KasperskyOS-based solution (hereinafter referred to as solution components). Each instance of a solution component is executed in the context of a separate process.

Security policy for a KasperskyOS-based solution

Interactions between the various processes and between processes and the KasperskyOS kernel are allowed or denied according to the KasperskyOS-based solution security policy (hereinafter referred to as the solution security policy or simply the policy). The solution security policy is stored in the Kaspersky Security Module and is used by this module whenever it makes decisions on whether to allow or deny interactions.

The solution security policy can also define the logic for handling queries sent by a process to the security module via the security interface. A process can use the security interface to send some data to the security module (for example, to influence future decisions made by the security module) or to receive a security module decision that is needed by the process to determine its own further actions.

Kaspersky Security System technology

Kaspersky Security System technology lets you implement diverse security policies for solutions. You can also combine multiple security mechanisms and flexibly regulate the interactions between different processes and between processes and the KasperskyOS kernel. A solution security policy is described by a specially developed language known as PSL (Policy Specification Language). A Kaspersky Security Module to be used in a specific solution is created based on the solution security policy description.

Source code generators

Some of the source code of a KasperskyOS-based solution is created by source code generators. Specialized programs generate the source code in C from declarative descriptions. They generate source code of the Kaspersky Security Module, source code of the initializing program (which starts all other programs in the solution and statically defines the topology of interaction between them), and the source code of the methods and types for carrying out IPC (transport code).

Transport code is generated by the nk-gen-c compiler from declarative descriptions in IDL (Interface Definition Language), CDL (Component Definition Language), and EDL (Entity Definition Language), respectively (for details, see Formal specifications of KasperskyOS-based solution components).

Source code of the Kaspersky Security Module is generated by the nk-psl-gen-c compiler from the solution security policy description and the IDL, CDL and EDL descriptions.

Source code of the initializing program is generated by the einit tool from the solution initialization description (in YAML format) and the IDL, CDL and EDL descriptions.

Page top
[Topic overview_general_inf]

KasperskyOS architecture

The KasperskyOS architecture is presented in the figure below:

KasperskyOS architecture

KasperskyOS architecture

In KasperskyOS, applications and drivers interact with each other and with the kernel by using the libkos library, which provides the interfaces for querying core endpoints. (In KasperskyOS, a driver generally operates with the same level of privileges as the application.) The libkos library queries the kernel by executing only three system calls: Call(), Recv() and Reply(). These calls are implemented by the IPC mechanism. Core endpoints are supported by kernel subsystems whose purposes are presented in the table below. Kernel subsystems interact with hardware through the hardware abstraction layer (HAL), which makes it easier to port KasperskyOS to various platforms.

Kernel subsystems and their purpose

Designation

Name

Purpose

HAL

Hardware abstraction subsystem

Basic hardware support: timers, interrupt controllers, memory management unit (MMU). This subsystem includes UART drivers and low-level means for power management.

IO

I/O manager

Registration and deallocation of hardware platform resources required for the operation of drivers, such as Interrupt ReQuest (IRQ), Memory-Mapped Input-Output (MMIO), I/O ports, and DMA buffers. If hardware has an input–output memory management unit (IOMMU), this subsystem is used to more reliably guarantee memory allocation.

MM

Physical memory manager

Allocation and deallocation of physical memory pages, distribution of physically contiguous page areas.

VMM

Virtual memory manager

Management of physical and virtual memory: reserving, locking, and releasing memory. Working with memory page tables for insulating the address spaces of processes.

THREAD

Thread manager

Thread management: creating, terminating, suspending, and resuming threads.

TIME

Real-time clock subsystem

Getting the time and setting the system clock. Using clocks provided by hardware.

SCHED

Scheduler

Support for three classes of scheduling: real-time threads, general-purpose threads, and IDLE – the state when there is no thread ready for execution.

SYNC

Synchronization primitive support subsystem

Implementation of basic synchronization primitives: spinlock, mutex, event. The kernel supports only one primitive – futex. All other primitives are implemented based on a futex in the user space.

IPC

Interprocess communication subsystem

Implementation of a synchronous IPC mechanism based on the rendezvous principle.

KSMS

Security module interaction subsystem

This subsystem is used for working with the security module. It provides all messages relayed via IPC to the security module so that these messages can be checked.

OBJ

Object manager

Management of the general behavior of all KasperskyOS resources: tracking their life cycle and assigning unique security IDs (for details, see "Resource Access Control"). This subsystem is closely linked to the capability-based access control mechanism (OCap).

ROMFS

Immutable file system image startup subsystem

Operations with files from ROMFS: opening and closing, receiving a list of files and their descriptions, and receiving file characteristics (name, size).

TASK

Process management subsystem

Process management: starting, terminating, suspending and resuming. Receiving the characteristics of running processes (for example, names, paths, and priority) and their exit codes.

ELF

Executable file loading subsystem

Loading executable ELF files from ROMFS into RAM, parsing headers of ELF files.

DBG

Debug support subsystem

Debugging mechanism based on GDB (GNU Debugger). The availability of this subsystem in the kernel is optional.

PM

Power manager

Power management: restart and shutdown.

Page top

[Topic overview_architecture][Topic overview_ipc_intro]

IPC mechanism

Exchanging IPC messages

In KasperskyOS, processes interact with each other by exchanging IPC messages (IPC request and IPC response). In an interaction between processes, there are two separate roles: client (the process that initiates the interaction) and server (the process that handles the request). Additionally, a process that acts as a client in one interaction can act as a server in another.

To exchange IPC messages, the client and server use three system calls: Call(), Recv() and Reply() (see the figure below):

  1. The client sends an IPC request to the server. To do so, one of the client's threads makes the Call() system call and is locked until an IPC response is received from the server.
  2. The server thread that has made the Recv() system call waits for IPC requests. When an IPC request is received, this thread is unlocked and handles the request, then sends an IPC response by making the Reply() system call.
  3. When an IPC response is received, the client thread is unlocked and continues execution.

    Exchanging IPC messages between a client and a server

Calling methods of server endpoints

IPC requests are sent to the server when the client calls endpoint methods of the server (hereinafter also referred to as interface methods) (see the figure below). The IPC request contains input parameters for the called method, as well as the endpoint ID (RIID) and the called method ID (MID). Upon receiving a request, the server uses these identifiers to find the method's implementation. The server calls the method's implementation while passing in the input parameters from the IPC request. After handling the request, the server sends the client an IPC response that contains the output parameters of the method.

Calling a server endpoint method

IPC channels

To enable two processes to exchange IPC messages, an IPC channel must be established between them. An IPC channel has a client side and a server side. One process can use multiple IPC channels at the same time. A process may act as a server for some IPC channels while acting as a client for other IPC channels.

KasperskyOS has two mechanisms for creating IPC channels:

  1. The static mechanism involves the creation of IPC channels when the solution is started. IPC channels are created statically by the initializing program.
  2. The dynamic mechanism allows already running processes to establish IPC channels between each other.
Page top
[Topic overview_ipc_details]

IPC control

The Kaspersky Security Module is integrated into the IPC implementation mechanism. The security module is aware of the contents of IPC messages for all possible interactions because IDL, CDL and EDL descriptions are used to generate the source code of this module. This enables the security module to verify that the interactions between processes comply with the solution security policy.

The KasperskyOS kernel queries the security module each time a process sends an IPC message to another process. The security module operating scenario includes the following steps:

  1. The security module verifies that the IPC message complies with the called method of the endpoint (the size of the IPC message is verified along with the size and location of certain structural elements).
  2. If the IPC message is incorrect, the security module makes the "deny" decision and the next step of the scenario is not carried out. If the IPC message is correct, the next step of the scenario is carried out.
  3. The security module checks whether the security rules allow the requested action. If allowed, the security module makes the "granted" decision. Otherwise it makes the "denied" decision.

The kernel executes the security module decision. In other words, it either delivers the IPC message to the recipient process or rejects its delivery. If delivery of an IPC message is rejected, the sender process receives an error code via the return code of the Call() or Reply() system call.

The security module checks IPC requests as well as IPC responses. The figure below depicts the controlled exchange of IPC messages between a client and a server.

Controlled exchange of IPC messages between a client and a server

Page top
[Topic overview_ipc_control]

Transport code for IPC

Implementation of interaction between processes requires transport code, which is responsible for properly creating, packing, sending, and unpacking IPC messages. However, developers of KasperskyOS-based solutions do not have to write their own transport code. Instead, you can use special tools and libraries included in the KasperskyOS SDK.

Transport code for developed components of a solution

A developer of a KasperskyOS-based solution component can generate transport code based on IDL, CDL and EDL descriptions related to this component. The KasperskyOS SDK includes the nk-gen-c compiler for this purpose. The nk-gen-c compiler lets you generate transport methods and types for use by both a client and a server.

Transport code for supplied components of a solution

Most components included in the KasperskyOS SDK may be used in a solution both locally (through static linking with other components) as well as via IPC.

To use a supplied component via IPC, the KasperskyOS SDK provides the following transport libraries:

  • Solution component's client library, which converts local calls into IPC requests.
  • Solution component's server library, which converts IPC requests into local calls.

The client library is linked to the client code (the component code that will use the supplied component). The server library is linked to the implementation of the supplied component (see the figure below).

Using a supplied solution component via IPC

Page top
[Topic overview_ipc_transport]

IPC between a process and the kernel

The IPC mechanism is used for interaction between processes and the KasperskyOS kernel. In other words, processes exchange IPC messages with the kernel. The kernel provides endpoints, and processes use those endpoints. Processes query core endpoints by calling functions of the libkos library (directly or via other libraries). The client transport code for interaction between a process and the kernel is included in this library.

A solution developer is not required to create IPC channels between processes and the kernel because these channels are created automatically when processes are created. (To set up interaction between processes, the solution developer has to create IPC channels between them.)

The Kaspersky Security Module makes decisions regarding interaction between processes and the kernel the same way it makes decisions regarding interaction between a process and other processes. (The KasperskyOS SDK has IDL, CDL and EDL descriptions for the kernel that are used to generate source code of the security module.)

Page top
[Topic overview_ipc_kernel]

Resource Access Control

Types of resources

KasperskyOS has two types of resources:

  • System resources, which are managed by the kernel. Some examples of these include processes, memory regions, and interrupts.
  • User resources, which are managed by processes. Examples of user resources: files, input-output devices, data storage.

Handles

Both system resources and user resources are identified by handles. Processes (and the KasperskyOS kernel) can transfer handles to other processes. By receiving a handle, a process obtains access to the resource that is identified by this handle. In other words, the process that receives a handle can request operations to be performed on a resource by specifying its received handle in the request. The same resource can be identified by multiple handles used by different processes.

Security identifiers (SID)

The KasperskyOS kernel assigns security identifiers to system resources and user resources. A security identifier (SID) is a global unique ID of a resource (in other words, a resource can have only one SID but can have multiple handles). The Kaspersky Security Module identifies resources based on their SID.

When transmitting an IPC message containing handles, the kernel modifies the message so that it contains SID values instead of handles when the message is checked by the security module. When the IPC message is delivered to its recipient, it will contain the handles.

The kernel also has an SID like other resources.

Security context

Kaspersky Security System technology lets you employ security mechanisms that receive SID values as inputs. When employing these mechanisms, the Kaspersky Security Module distinguishes resources (and the KasperskyOS kernel) and binds security contexts to them. A security context consists of data that is associated with an SID and used by the security module to make decisions.

The contents of a security context depend on the security mechanisms being used. For example, a security context may contain the state of a resource and the levels of integrity of access subjects and/or access objects. If a security context stores the state of a resource, this lets you allow certain operations to be performed on a resource only if the resource is in a specific state, for example.

The security module can modify a security context when it makes a decision. For example, it can modify information about the state of a resource (the security module used the security context to verify that a file is in the "not in use" state and allowed the file to be opened for write access and wrote a new state called "opened for write access" into the security context of this file).

Resource access control by the KasperskyOS kernel

The KasperskyOS kernel controls access to resources by using two mutually complementary methods at the same time: executing the decisions of the Kaspersky Security Module and implementing a security mechanism based on object capabilities (OCap).

Each handle is associated with access rights to the resource identified by this handle, which means it is a capability in OCap terms. By receiving a handle, a process obtains the access rights to the resource that is identified by this handle. For example, these access rights may consist of read permissions, write permissions, and/or permissions to allow another process to perform operations on the resource (handle transfer permission).

Processes that use the resources provided by the kernel or other processes are referred to as resource consumers. When a resource consumer opens a system resource, the kernel sends the consumer the handle associated with the access rights to this resource. These access rights are assigned by the kernel. Before an operation is performed on a system resource requested by a consumer, the kernel verifies that the consumer has sufficient rights. If the consumer does not have sufficient rights, the kernel rejects the request of the consumer.

In an IPC message, a handle is sent together with its permissions mask. The handle permissions mask is a value whose bits are interpreted as access rights to the resource identified by the handle. A resource consumer can find out their access rights to a system resource from the handle permissions mask of this resource. The kernel uses the handle permissions mask to verify that the consumer is allowed to request the operations to be performed on the system resource.

The security module can verify the permissions masks of handles and use these verifications to either allow or deny interactions between different processes and between processes and the kernel when such interactions are related to resource access.

The kernel prohibits the expansion of access rights when handles are transferred among processes (when a handle is transferred, access rights can only be restricted).

Resource access control by resource providers

Processes that control user resources and access to those resources for other processes are referred to as resource providers. For example, drivers are resource providers. Resource providers control access to resources by using two mutually complementary methods: executing the decisions of the Kaspersky Security Module and using the OCap mechanism that is provided by the KasperskyOS kernel.

If a resource is queried by its name (for example, to open it), the security module cannot be used to control access to the resource without the involvement of the resource provider. This is because the security module identifies a resource by its SID, not by its name. In such cases, the resource provider finds the resource handle based on the resource name and forwards this handle (together with other data, such as the required state of the resource) to the security module via the security interface (the security module receives the SID corresponding to the transferred handle). The security module makes a decision and returns it to the resource provider. The resource provider implements the decision of the security module.

When a resource consumer opens a user resource, the resource provider sends the consumer the handle associated with the access rights to this resource. In addition, the resource provider decides which specific rights for accessing the resource will be granted to the resource consumer. Before an operation is performed on a user resource as requested by a consumer, the resource provider verifies that the consumer has sufficient rights. If the consumer does not have sufficient rights, the resource provider rejects the request of the consumer.

A resource consumer can find out their access rights to a user resource from the permissions mask of the handle of this resource. The resource provider uses the handle permissions mask to verify that the consumer is allowed to request the operations to be performed on the user resource.

Handle permissions mask structure

A handle permissions mask has a size of 32 bits and consists of a general part and a specialized part. The general part describes the general rights that are not specific to any particular resource (the flags of these rights are defined in the services/ocap.h header file). For example, the general part contains the OCAP_HANDLE_TRANSFER flag, which defines the permission to transfer the handle. The specialized part describes the rights that are specific to the particular user resource or system resource. The flags of the specialized part's permissions for system resources are defined in the services/ocap.h header file. The structure of the specialized part for user resources is defined by the resource provider by using the OCAP_HANDLE_SPEC() macro that is defined in the services/ocap.h header file. The resource provider must export the public header files describing the structure of the specialized part.

When the handle of a system resource is created, the permissions mask is defined by the KasperskyOS kernel, which applies permissions masks from the services/ocap.h header file. It applies permissions masks with names such as OCAP_*_FULL (for example, OCAP_IOPORT_FULL, OCAP_TASK_FULL, OCAP_FILE_FULL) and OCAP_IPC_* (for example, OCAP_IPC_SERVER, OCAP_IPC_LISTENER, OCAP_IPC_CLIENT).

When the handle of a user resource is created, the permissions mask is defined by the user.

When a handle is transferred, the permissions mask is defined by the user but the transferred access rights cannot be elevated above the access rights of the process.

Page top
[Topic overview_resource_acces_control]

Structure and startup of a KasperskyOS-based solution

Structure of a solution

The image of the KasperskyOS-based solution loaded into hardware contains the following files:

  • Image of the KasperskyOS kernel
  • File containing the executable code of the Kaspersky Security Module
  • Executable file of the initializing program
  • Executable files of all other solution components (for example, applications and drivers)
  • Files used by programs (for example, files containing settings, fonts, graphical and audio data)

The ROMFS file system is used to save files in the solution image.

Starting a solution

A KasperskyOS-based solution is started as follows:

  1. The bootloader starts the KasperskyOS kernel.
  2. The kernel finds and loads the security module (as a kernel module).
  3. The kernel starts the initializing program.
  4. The initializing program starts all other programs that are part of the solution.
Page top
[Topic overview_solution_image]