Describing and performing tests for a KasperskyOS-based solution security policy

August 2, 2023

ID ssp_descr_psl_syntax_testing

A solution security policy is tested to verify whether or not the policy actually allows what should be allowed and denies what should be denied.

To describe a set of tests for a solution security policy, you need to use the following declaration:

assert "<name of test set>" {

// Constructs in PAL (Policy Assertion Language)

[setup {<initial part of tests>}]

sequence "<test name>" {<main part of test>}

...

[finally {<final part of tests>}]

}

You can describe multiple sets of tests by using several of these declarations.

The test set description can optionally include the initial part of the tests and/or the final part of the tests. The execution of each test from the set begins with whatever is described in the initial part of the test and ends with whatever is described in the final part of the test. This lets you describe the repeated initial and/or final parts of tests in each test.

After completing each test, all modifications in the Kaspersky Security Module related to the execution of this test are rolled back.

Each test includes one or more test cases.

Test cases

A test case associates a security event description and values of interface method parameters with an expected decision of the Kaspersky Security Module. If the actual security module decision matches the expected decision, the test case passes. Otherwise it fails.

When a test is run, the test cases are executed in the same sequence in which they are described. In other words, you can test how the security module handles a sequence of security events.

If all test cases within a test pass, the test passes. If even one test case fails to pass, the test fails. A test is terminated on the first failing test case.

A test case description is created in the PAL language and is comprised of a sequence of values:

[expected decision of security module] ["test example name"] <security event type> <security event selectors> [{interface method parameter values}]

The expected decision of the security module can be indicated as grant ("granted"), deny ("denied") or any ("any decision"). If the expected security module decision is not specified, the "granted" decision is expected. If the any value is specified, the security module decision does not have any influence on whether or not the test case passes. In this case, the test case may fail due to errors that occur when the security module processes an IPC message (for example, when the IPC message has an invalid structure).

For information about the types and selectors of security events, and about the limitations when using selectors, see Binding methods of security models to security events. Selectors must ensure that the security event description corresponds to IPC messages of the same type. (When security model methods are bound to security events, selectors may fail to ensure this.)

In security event descriptions, you need to specify the SID instead of the process class name (and the KasperskyOS kernel). However, this requirement does not apply to execute events for which the SID of the started process (or kernel) is unknown. To save the SID of the process or kernel to a variable, you need to use the <- operator in the test case description in the following format:

<variable name> <- execute dst=<kernel/process class name> ...

The SID value will be assigned to the variable even if startup of the process of the defined class (or kernel) is denied by the tested policy but the "denied" decision is expected.

The PAL language supports abbreviated forms of security event descriptions:

  • security: <Process SID> ! <qualified name of security interface method> corresponds to security src=<process SID> method=<qualified name of security interface method>.
  • request: <client SID> ~> <kernel/server SID> : <qualified name of endpoint.method name> corresponds to request src=<client SID> dst=<kernel/server SID> endpoint=<qualified name of endpoint> method=<method name>.
  • response: <client SID> <~ <kernel/server SID> : <qualified name of endpoint.method name> corresponds to response src=<kernel/server SID> dst=<client SID> endpoint=<qualified name of endpoint> method=<method name>.

If an interface method has parameters, their values are defined by comma-separated constructs:

<parameter name> : <value>

The names and types of parameters must comply with the IDL description. The sequence order of parameters is not important.

Example definition of parameter values

{ param1 : 23, param2 : "bar", param3: { collection : [5,7,12], filehandle : 15 }, param4 : { name : ["foo", "baz" } }

In this example, the number is passed through the param1 parameter. The string buffer is passed through the param2 parameter. A structure consisting of two fields is passed through the param3 parameter. The collection field contains an array or sequence of three numeric elements. The filehandle field contains the SID. A union or structure containing one field is passed through the param4 parameter. The name field contains an array or sequence of two string buffers.

Currently, only an SID can be indicated as the value of a Handle parameter, and there is no capability to indicate the SID together with a handle permissions mask. For this reason, it is not possible to properly test a solution security policy when the permissions masks of handles influence the security module decisions.

Example descriptions of policy tests

See "Example descriptions of tests for KasperskyOS-based solution security policies".

Test procedure

Descriptions of tests are placed into PSL files, including those that contain a solution security policy description (for example, into the security.psl file).

To run tests, you need to use the --tests run parameter when starting the nk-psl-gen-c compiler:

$ nk-psl-gen-c --tests run <other parameters> security.psl

You also need to indicate the following data for the nk-psl-gen-c compiler:

  • Directories that contain auxiliary files from the KasperskyOS SDK (common, sysroot-*-kos/include, toolchain/include). This set of directories is defined by the parameters -I, -include-dir <path to files>.
  • Directories that contain PSL, IDL, CDL, and EDL files related to the solution. This set of directories is defined by the parameters -I, --include-dir <path to files>.
  • Path to the file that will save the source code of the Kaspersky Security Module and tests. This path is defined by the parameter -o, --output <path to file>.

The nk-psl-gen-c compiler generates the source code of the security module and tests in the C language, saves this code to a file, and then runs the compilation of this code using gcc and executes the obtained test program. The test program is run in an environment where the KasperskyOS SDK is installed (on a computer running a Linux operating system). It does not utilize the KasperskyOS kernel, system software or applications of the solution.

To generate the source code of the security module and tests without compiling it, you need to use the --tests generate parameter when starting the nk-psl-gen-c compiler.

Test results are printed to the console. To print the test results to a file, you need to use the --test-output <path to file> parameter when starting the nk-psl-gen-c compiler.

Example test results:

# PAL test run

## Execute (1/2)

* Happy path: FAIL

Step 2/2: ExpectGrant Execute "This should not fail"

component/secure_platform/kss/nk/psl/nk-psl-gen-c/tests/examples/include/router.psl:38:5-40:3

* No rule: PASS

## IPC (2/2)

* Happy path: PASS

* No rule: PASS

## Security (2/2)

* Happy path: PASS

* No rule: PASS

The test results contain information about whether or not each test passed or failed. If a test failed, the results indicate which test case from the specific test did not pass, and provide the location of the description of the failed test case in the PSL file.

Did you find this article helpful?
What can we do better?
Thank you for your feedback! You're helping us improve.
Thank you for your feedback! You're helping us improve.