KasperskyOS Community Edition 1.0

PSL language syntax

Basic rules

  1. Declarations can be listed in any sequence in a file.
  2. One declaration can be written to one or multiple lines. The second and subsequent lines of the declaration must be written with indentations relative to the first line. The closing brace that completes the declaration can be written on the top line.
  3. A multi-line declaration utilizes different-sized indentations to reflect the nesting of constructs comprising this declaration. Lines of a multi-line construct enclosed in braces and the opening brace must be written with an indentation relative to the first line of this construct. The closing brace of a multi-line construct can be written with an indentation or on the first line of the construct.
  4. Single-line comments and multi-line comments are supported:

    /* This is a comment

    And this, too */

    // Another comment

Types of declarations

The PSL language has the following types of declarations:

  • Describing the global parameters of a solution security policy
  • Including PSL files
  • Including EDL files
  • Creating objects of security models
  • Binding methods of security models to security events
  • Describing security audit profiles

In this section

Describing the global parameters of a solution security policy

Including PSL files

Including EDL files

Creating objects of security models

Binding methods of security models to security events

Describing security audit profiles

PSL data types

Example of a basic solution security policy

Page top
[Topic ssp_descr_psl_syntax_intro]

Describing the global parameters of a solution security policy

Global parameters include the following parameters of a solution security policy:

  • Execute interface used by the KasperskyOS kernel when querying the Kaspersky Security Module to notify it about kernel startup or about initiating the startup of entities by the kernel or other entities. To assign this interface, use the following declaration:

    execute: kl.core.Execute

    KasperskyOS currently supports only one Execute interface defined in the file named kl/core/Execute.idl. (This interface consists of one main method, which has no parameters and does not perform any actions. The main method is reserved for potential future use.)

  • [Optional] Global security audit profile and initial security audit level. To define these parameters, use the following declaration:

    audit default = <security audit profile name> <security audit level>

    Example:

    audit default = global 0

    The default global profile is the empty security audit profile described in the file named toolchain/include/nk/base.psl from the KasperskyOS SDK, and the default security audit level is 0.

Page top
[Topic ssp_descr_psl_syntax_global_params]

Including PSL files

To include a PSL file, use the following declaration:

use <link to PSL file._>

The link to the PSL file is the file path (without the extension and dot before it) relative to the directory that is included in the set of directories where the nk-psl-gen-c compiler searches for PSL-, IDL-, CDL-, and EDL files. (This set of directories is defined by parameters of the makekss script in the format "-I <path to files>".) A dot is used as a separator in a path description. A declaration is ended by the ._ character sequence.

Example:

use policy_parts.flow_part._

This declaration includes the flow_part.psl file, which is located in the policy_parts directory. The policy_parts directory must reside in one of the directories where the nk-psl-gen-c compiler searches for PSL-, IDL-, CDL-, and EDL files. For example, the policy_parts directory may reside in the same directory as the PSL file containing this declaration.

Including a PSL file containing a formal representation of a security model

To use the methods of a required security model, include a PSL file containing a formal representation of this model. PSL files containing formal representations of security models are located in the <KOS_KASPERSKY> SDK at the following path:

toolchain/include/nk

Example:

/* Include the base.psl file containing a formal representation of the

* Base security model */

use nk.base._

/* Include the flow.psl file containing a formal representation of the

* Flow security model */

use nk.flow._

/* The nk-psl-gen-c compiler must be configured to search for

* PSL-, IDL-, CDL-, and EDL files in the toolchain/include directory. */

Page top
[Topic ssp_descr_psl_syntax_include_psl]

Including EDL files

To include an EDL file for the KasperskyOS kernel, use the following declaration:

use EDL kl.core.Core

To include an EDL file for an application or system program (or for a driver), use the following declaration:

use EDL <link to EDL file>

The link to the EDL file is the file path (without the extension and dot before it) relative to the directory that is included in the set of directories where the nk-psl-gen-c compiler searches for PSL-, IDL-, CDL-, and EDL files. (This set of directories is defined by parameters of the makekss script in the format "-I <path to files>".) A dot is used as a separator in a path description.

Example:

/* Include the UART.edl file, which is located

* in the KasperskyOS SDK at the path sysroot-*-kos/include/kl/drivers. */

use EDL kl.drivers.UART

/* The nk-psl-gen-c compiler must be configured to search for

* PSL-, IDL-, CDL-, and EDL files in the sysroot-*-kos/include directory. */

The nk-psl-gen-c compiler finds IDL- and CDL files via EDL files because EDL files contain links to the corresponding CDL files, and the CDL files contain links to the corresponding CDL- and IDL files.

Page top
[Topic ssp_descr_psl_syntax_include_edl]

Creating objects of security models

To call the methods of a required security model, create an object for this security model.

To create a security model object, use the following declaration:

policy object <security model object name : security model name> {

[security model object parameters]

}

The parameters of a security model object are specific to the security model. A description of parameters and examples of creating objects of various security models are provided in the "Security models" section.

Page top
[Topic ssp_descr_psl_syntax_create_objects]

Binding methods of security models to security events

To bind methods of security models to a security event, use the following declaration:

<security event type> [security event selectors] {

[security audit profile]

<called security model rules>

}

Security event type

The following specifiers are used to define the security event type:

  • request – sending IPC requests.
  • response –sending IPC responses.
  • error – sending IPC responses containing information about errors.
  • security – entities attempting to query the Kaspersky Security Module via the security interface.
  • execute – initializing the startups of entities or the startup of the KasperskyOS kernel.

When entities interact with the security module, they use a mechanism that is different from IPC. However, when developing a solution security policy, queries sent by entities to the security module can be viewed as the transfer of IPC messages because entities actually transmit messages to the security module (the recipient is not indicated in these messages).

The IPC mechanism is not used to start entities. However, when the startup of an entity is initiated, the kernel queries the security module and provides information about the initiator of the startup and the started entity. For this reason, the author of a solution security policy can consider the startup of an entity to be analogous to sending an IPC message from the startup initiator to the started entity. When the kernel is started, this is analogous to the kernel sending an IPC message to itself.

Security event selectors

Security event selectors let you clarify the description of the defined type of security event. The following selectors are used:

  • src=<kernel/entity class name> – entities of the defined class or the KasperskyOS kernel are the sources of IPC messages.
  • dst=<kernel/entity class name> – entities of the defined class or the kernel are the recipients of IPC messages.
  • interface=<interface name> – describes the following security events:
    • Clients attempt to query servers or the kernel via the interface with the defined name.
    • Entities query the Kaspersky Security Module via the security interface with the defined name.
    • The kernel or servers send clients the results from processing queries via the interface with the defined name.
  • endpoint=<qualified service name> – describes the following security events:
    • Clients attempt to use the service of servers or the kernel with the defined name.
    • The kernel or servers send clients the results from using the service with the defined name.
  • method=<method name> – describes the following security events:
    • Clients attempt to query servers or the kernel by calling the method of the service with the defined name.
    • Entities query the security module by calling the method of the security interface with the defined name.
    • The kernel or servers send clients the results from calling the method of the service with the defined name.
    • The kernel notifies the security module about its startup by calling the method of the execute interface with the defined name.
    • The kernel initiates the startup of entities by calling the method of the execute interface with the defined name.
    • Entities initiate the startup of other entities, which results in the kernel calling the method of the execute interface with the defined name.

The qualified name of the service has the format <path to service.service name>. The path to the service is a sequence of component instance names (from the formal specification of the solution component) separated by dots. Among these component instances, each subsequent component instance is embedded into the previous one, and the last one provides the service with the defined name.

Entity classes, interfaces, services, and methods must be named the same as they are in the IDL, CDL, and EDL descriptions. The kernel must be named kl.core.Core.

If selectors are not specified, the participants of a security event are considered to be all events and the kernel (except security events in which the kernel is not involved).

You can use combinations of selectors. Selectors can be separated by commas.

There are restrictions on the use of selectors. The interface and endpoint selectors cannot be used for security events of the execute type. The dst and endpoint selectors cannot be used for security events of the security type.

There are also restrictions on combinations of selectors. For security events of the request, response and error types, the method selector can only be used together with one or both of the endpoint and interface selectors. (The method, endpoint and interface selectors must be consistent, which means that the method must correspond to the service or interface, and the service must correspond to the interface.) For security events of the request type, the endpoint selector can be used only together with the dst selector. For security events of the response and error types, the endpoint selector can be used only together with the src selector.

Security audit profile

A security audit profile is defined by the construct audit <security audit profile name>. If a security audit profile is not defined, the global security audit profile is used.

Called rules of security models

Called rules of security models are defined by a list from the following type of constructs:

[security model object name.]<security model rule name> <parameter>

Input data for security model rules may be values returned by expressions of security models. The following construct is used to call a security model expression:

[security model object name.]<security model expression name> <parameter>

Parameters of interface methods can also be used as input data for methods of security models (rules and expressions). (For details about obtaining access to parameters of interface methods, see "Struct security model"). In addition, input data for methods of security models can also be the SID values of entities and the KasperskyOS kernel that are defined by the src_sid and dst_sid reserved words. The first reserved word refers to the SID of the entity (or kernel) that is the source of the IPC message. The second reserved word refers to the SID of the entity (or kernel) that is the recipient of the IPC message (dst_sid cannot be used for queries to the Kaspersky Security Module).

You do not have to indicate the security model object name or use operators for calls of some rules and expressions of security models. For details about the methods of security models, see "Security models".

Embedded constructs for binding methods of security models to security events

In one declaration, you can bind methods of security models to different security events of the same type. To do so, use the match sections that consist of the following types of constructs:

match <security event selectors> {

[security audit profile]

<called security model rules>

}

Match sections can be embedded into another match section. A match section simultaneously uses its own security event selectors and the security event selectors at the level of the declaration and all match sections in which this match section is "wrapped". By default, a match section applies the security audit profile of its own container (match section of the preceding level or the declaration level), but you can define a separate security audit profile for the match section.

In one declaration, you can define different variants for processing a security event depending on the conditions in which this event occurred (for example, depending on the state of the finite-state machine associated with the resource). To do so, use the conditional sections that are elements of the following construct:

choice <call of the security model expression that verifies fulfillment of conditions> {

"<condition 1>" : [{] // Conditional section 1

[security audit profile]

<called security model rules>

[}]

"<condition 2>" : ... // Conditional section 2

...

_ : ... // Conditional section, if no condition is fulfilled.

}

The choice construct can be used within a match section. A conditional section uses the security event selectors and security audit profile of its own container, but you can define a separate security audit profile for a conditional section.

If multiple conditions described in the choice construct are simultaneously fulfilled when a security event is processed, only the one conditional section corresponding to the first matching condition on the list is triggered.

You can verify the fulfillment of conditions in the choice construct only by using the expressions that are specially intended for this purpose. Some security models contain these expressions (for more details, see "Security models").

Page top

[Topic ssp_descr_psl_syntax_binding]

Describing security audit profiles

To perform a security audit, you need to associate objects of security models with a security audit profile(s). A security audit profile (hereinafter also referred to as an audit profile) combines security audit configurations (hereinafter also referred to as audit configurations), each of which defines the objects of security models covered by the audit, and the audit completion conditions. You can define a global audit profile (for more details, see "Describing the global parameters of a solution security policy") and/or assign an audit profile(s) at the level of declarations for binding security model methods to security events, and/or assign an audit profile(s) at the level of match sections or choice sections (for more details, see "Binding methods of security models to security events").

Regardless of whether or not audit profiles are being used, audit data contains information about "denied" decisions that were made by the Kaspersky Security Module when IPC messages were invalid and when processing security events that are not associated with any security model rule.

To describe a security audit profile, use the following declaration:

audit profile <security audit profile name> =

{ <security audit level>:

// Description of the security audit configuration

{ <security model object name>:

{ kss: <security audit completion conditions linked to the results

from calls of security model rules>

[, security audit completion conditions specific to the security model]

}

[,]...

...

}

[,]...

...

}

Security audit level

The security audit level (hereinafter referred to as the audit level) is a global parameter of a solution security policy and consists of an unsigned integer that defines the active security audit configuration. (The word "level" here refers to the configuration variant and does not necessarily involve a hierarchy.) The audit level can be changed during operation of the Kaspersky Security Module. This is done by using a specialized method of the Base security model that is called when entities query the security module via the security interface (for more details, see "Base security model"). The initial audit level is assigned together with the global audit profile (for more details, see "Describing the global parameters of a solution security policy"). An empty audit profile can be explicitly assigned as the global audit profile.

You can define multiple audit configurations in an audit profile. In different configurations, different security model objects can be covered by the audit and different audit completion conditions can be applied. Audit configurations in a profile correspond to different audit levels. If a profile does not have an audit configuration corresponding to the current audit level, the security module will activate the configuration that corresponds to the next-lowest audit level. If a profile does not have an audit configuration for an audit level equal to or less than the current level, the security module will not use this profile (in other words, an audit will not be performed for this profile).

Audit levels can be used to regulate the level of detail of an audit, for example. The higher the audit level, the higher the level of detail. The higher the level of detail, the more security model objects are covered by the audit and/or the less restrictions are applied in the audit completion conditions.

Another example of applying audit levels is the capability to shift the audit from one subsystem to another subsystem (for example, shift an audit related to drivers to an audit related to applications, or shift an audit related to the network subsystem to an audit related to the graphic subsystem).

Name of the security model object

The security model object name is indicated so that the methods provided by this object can be covered by the audit. These methods will be covered by the audit whenever they are called, provided that the audit completion conditions are observed.

Information about the decisions of the Kaspersky Security Module contained in audit data includes the overall decision of the security module as well as the results from calling individual methods of security modules covered by the audit. To ensure that information about a security module decision is included in audit data, at least one method called during security event processing must be covered by the audit.

The names of security model objects and the names of methods provided by these objects are included in the audit data.

Security audit completion conditions

Security audit completion conditions are defined separately for each object of a security model.

To define audit completion conditions related to the results from calling rules of security models, use the following constructs:

  • ["granted"] – the audit is performed if the called rule returned the "granted" result.
  • ["denied"] – the audit is performed if the called rule returned the "denied" result.
  • ["granted", "denied"] – the audit is performed if the called rule returned the "granted" or "denied" result.
  • [] – the audit is not performed, regardless of the result returned by the called rule.

Audit completion conditions related to results from calling rules are not applied to expressions. These conditions must be defined (with any possible construct) even if the security model contains only expressions because this is required by the PSL language syntax.

Audit completion conditions specific to security models are defined by constructs specific to these models. These conditions are applied to rules and to expressions. For example, one of these conditions can be the state of a finite-state machine.

Security audit profile for a security audit route

A security audit route includes the kernel and the Klog and KlogStorage entities, which are connected by IPC channels based on the "kernel – Klog – KlogStorage" scenario. Security model methods that are associated with transmission of audit data via this route must not be covered by the audit. Otherwise, this will lead to an avalanche of audit data because any data transmission will give rise to new data.

To "suppress" an audit that was defined by a profile with a wider scope (for example, by a global profile or a profile at the level of a declaration for binding security model methods to security events), assign an empty audit profile at the level of the declaration for binding security model methods to security events or at the level of the match section or choice section.

Page top

[Topic ssp_descr_psl_syntax_audit]

PSL data types

The data types supported in the PSL language are presented in the table below.

PSL data types

Designations of types

Description of types

UInt8, UInt16, UInt32, UInt64

Unsigned integer

SInt8, SInt16, SInt32, SInt64

Signed integer

Boolean

Boolean type

The Boolean type includes two values: true and false.

Text

Text type

()

Unit type

The Unit type includes one immutable value. It is used as a stub value in cases when the PSL language syntax requires a specific data formulation but this data is not actually required. For example, the Unit type can be used to declare a method that does not have any parameters (similar to how the void type is used in C/C++).

"<type>"

Text literal

A text literal includes one immutable text value.

Example definitions of text literals:

""

"granted"

<type>

Integer literal

An integer literal includes one immutable integer value.

Example definitions of integer literals:

12

-5

0xFFFF

<type 1 | type 2> [|]...

Variant type

A variant type combines two or more types and may perform the role of either of them.

Examples of definitions of variant types:

Boolean | ()

UInt8 | UInt16 | UInt32 | UInt64

"granted" | "denied"

{ [field name : field type]

[,] ...

...

}

Dictionary

A dictionary consists of one or more types of fields. A dictionary cannot be blank.

Examples of dictionary definitions:

{}

{ handle : Handle

, rights : UInt32

}

[[type] [,] ...]

Tuple

A tuple consists of fields of one or more types in the order in which the types are listed. A tuple cannot be blank.

Examples of tuple definitions:

[]

["granted"]

[Boolean, Boolean]

Set<<type of elements>>

Set

A set includes zero or more unique elements of the same type.

Examples of set definitions:

Set<"granted" | "denied">

Set<Text>

List<<type of elements>>

List

A list includes zero or more elements of the same type.

Examples of list definitions:

List<Boolean>

List<Text | ()>

Map<<key type, value type>>

Associative array

An associative array includes zero or more entries of the "key-value" type with unique keys.

Example of defining an associative array:

Map<UInt32, UInt32>

Array<<type of elements, number of elements>>

Array

An array includes a defined number of elements of the same type.

Example of defining an array:

Array<UInt8, 42>

Sequence<<type of elements, number of elements>>

Sequence

A sequence includes from zero to the defined number of elements of the same type.

Example of defining a sequence:

Sequence<SInt64, 58>

Aliases of certain PSL types

The nk/base.psl file from the KasperskyOS SDK defines the data types that are used as the types of parameters (or structural elements of parameters) and returned values for methods of various security models. Aliases and definitions of these types are presented in the table below.

Aliases and definitions of certain data types in PSL

Type alias

Type definition

Unsigned

Unsigned integer

UInt8 | UInt16 | UInt32 | UInt64

Signed

Signed integer

SInt8 | SInt16 | SInt32 | SInt64

Number

Integer

Unsigned | Signed

ScalarLiteral

Scalar literal

() | Boolean | Number

Literal

Literal

ScalarLiteral | Text

Sid

Type of security identifier (SID)

UInt32

Handle

Type of security identifier (SID)

Sid

HandleDesc

Dictionary containing fields for the SID and handle permissions mask

{ handle : Handle

, rights : UInt32

}

Cases

Type of data received by expressions of security models called in the choice construct for verifying fulfillment of conditions

List<Text | ()>

KSSAudit

Type of data defining the security audit completion conditions

Set<"granted" | "denied">

Mapping IDL types to PSL types

Data types of the IDL language are used to describe the parameters of interface methods. The input data for security model methods have types from the PSL language. The set of data types in the IDL language differs from the set of data types in the PSL language. Parameters of interface methods transmitted in IPC messages can be used as input data for methods of security models, so the author of a solution security policy needs to understand which IDL types are mapped to PSL types.

Integer types of IDL are mapped to integer types of PSL and to variant types of PSL that combine these integer types (including with other types). For example, signed integer types of IDL are mapped to the Signed type in PSL, and integer types of IDL are mapped to the ScalarLiteral type in PSL.

The Handle type in IDL is mapped to the HandleDesc type in PSL.

Unions and structures of IDL are mapped to PSL dictionaries.

Arrays and sequences of IDL are mapped to arrays and sequences of PSL, respectively.

String buffers in IDL are mapped to the text type in PSL.

Byte buffers in IDL are not currently mapped to PSL types, so the data contained in byte buffers cannot be used as inputs for security model methods.

Page top
[Topic ssp_descr_psl_syntax_data_types]

Example of a basic solution security policy

Below is a basic solution security policy in which "everything is allowed" for a solution consisting of Client and Server user entities, an Einit entity, and the KasperskyOS kernel provided by the kl.core.Core entity.

This policy allows the following:

  • All interactions between entities (sending any requests and responses)
  • Startup of all entities

Use of this security policy is unacceptable in real solutions. A more complex solution security policy is shown in the ping example.

security.psl

execute: kl.core.Execute

use nk.base._

use EDL Einit

use EDL kl.core.Core

use EDL Client

use EDL Server

/* Startup of entities is allowed */

execute {

grant ()

}

/* Sending and receiving requests, responses and errors is allowed.

This means that any entity can call the methods of other entities and the kernel. */

request {

grant ()

}

response {

grant ()

}

error {

grant ()

}

/* Whenever the Kaspersky Security Module is queried,

* the "allowed" decision will always be received. */

security {

grant ()

}

Page top
[Topic security_configuration_basic_example]