KasperskyOS Community Edition 1.3

Building a KasperskyOS-based solution

This section contains the following information:

  • Description of the KasperskyOS-based solution build process.
  • Descriptions of the scripts, libraries and build templates provided in KasperskyOS Community Edition.
  • Information on how to use dynamic libraries in a KasperskyOS-based solution.

In this section

Building a solution image

Build process overview

Using CMake from the contents of KasperskyOS Community Edition

CMake libraries in KasperskyOS Community Edition

Building without CMake

Using dynamic libraries

Page top
[Topic cmake_build_solution]

Building a solution image

A KasperskyOS-based solution consists of system software (including the KasperskyOS kernel and Kaspersky Security Module) and application software integrated for operation within a software/hardware system.

For more details, refer to Structure and startup of a KasperskyOS-based solution.

System programs and application software

Programs are divided into two types according to their purpose:

  • System programs create the infrastructure for application software. For example, they facilitate hardware operations, support the IPC mechanism, and implement file systems and network protocols. System programs are included in KasperskyOS Community Edition. If necessary, you can develop your own system programs.
  • Application software is designed for interaction with a solution user and for performing user tasks. Application software is not included in KasperskyOS Community Edition.

Building programs during the solution build process

During a solution build, programs are divided into the following two types:

  • System programs provided as executable files in KasperskyOS Community Edition.
  • System programs or application software that requires linking to an executable file.

Programs that require linking are divided into the following types:

  • System programs that implement an IPC interface whose ready-to-use transport libraries are provided in KasperskyOS Community Edition.
  • Application software that implements its own IPC interface. To build this software, transport methods and types need to be generated by using the NK compiler.
  • Client programs that do not provide endpoints.

Building a solution image

KasperskyOS Community Edition provides an image of the KasperskyOS kernel and the executable files of some system programs and driver applications that are ready to use in a solution.

A specialized Einit program intended for starting all other programs, and a Kaspersky Security Module are built for each specific solution and are therefore not already provided in KasperskyOS Community Edition. Instead, the toolchain provided in KasperskyOS Community Edition includes the tools for building these resources.

The general step-by-step build scenario is described in the article titled Build process overview. A solution image can be built as follows:

  • [Recommended] Using scripts of the CMake build system, which is provided in KasperskyOS Community Edition.
  • [Without CMake] Using other automated build systems or manually with scripts and compilers provided in KasperskyOS Community Edition.
Page top
[Topic cmake_solution_image]

Build process overview

To build a solution image, the following is required:

  1. Prepare EDL, CDL and IDL descriptions of applications, an init description file (init.yaml by default), and files containing a description of the solution security policy (security.psl by default).

    When building with CMake, an EDL description can be generated by using the generate_edl_file() command.

  2. Generate *.edl.h files for all programs except the system programs provided in KasperskyOS Community Edition.
  3. For programs that implement their own IPC interface, generate code of the transport methods and types that are used for generating, sending, receiving and processing IPC messages.
  4. Build all programs that are part of the solution, and link them to the transport libraries of system programs or applications if necessary. To build applications that implement their own IPC interface, you will need the code containing transport methods and types that was generated at step 3.
    • When building with CMake, standard build commands are used for this purpose. The necessary cross-compilation configuration is done automatically.
    • When building without CMake, the cross compilers included in KasperskyOS Community Edition must be manually used for this purpose.
  5. Build the Einit initializing program.
    • When building with CMake, the Einit program is built during the solution image build process using the build_kos_qemu_image() and build_kos_hw_image() commands.
    • When building without CMake, the einit tool must be used to generate the code of the Einit program. Then the Einit application must be built using the cross compiler that is provided in KasperskyOS Community Edition.
  6. Build the Kaspersky Security Module.
  7. Create the solution image.

Example 1

For the basic hello example included in KasperskyOS Community Edition that contains one application that does not provide any services, the build scenario looks as follows:

Example 2

The echo example included in KasperskyOS Community Edition describes a basic case of interaction between two programs via an IPC mechanism. To set up this interaction, you will need to implement an interface with the Ping method on a server and put the Ping service into a new component (for example, Responder), and an instance of this component needs to be put into the EDL description of the Server program.

If a solution contains programs that utilize an IPC mechanism, the build scenario looks as follows:

Page top
[Topic cmake_common_build_scheme]

Using CMake from the contents of KasperskyOS Community Edition

To automate the process of preparing the solution image, you need to configure the CMake build system. You can base this system on the build system parameters used in the examples from KasperskyOS Community Edition.

CMakeLists.txt files use the standard CMake syntax, and commands and macros from libraries provided in KasperskyOS Community Edition.

Recommended structure of project directories

When creating a KasperskyOS-based solution, it is recommended to use the following directory structure in a project:

Example structure of project directories

example$ tree . ├── CMakeLists.txt ├── hello │ ├── CMakeLists.txt │ ├── src │ │ ├── hello.c ├── einit │ ├── CMakeLists.txt │ ├── src │ │ ├── init.yaml.in │ │ ├── security.psl.in ├── resources │ ├── Hello.idl │ ├── Hello.cdl │ ├── Hello.edl

Building a solution image

To build a solution image, you must use the cmake tool (the toolchain/bin/cmake executable file from KasperskyOS Community Edition).

Build script example:

build.sh

#!/bin/bash # Script to be run in the project root. # You can get information about the cmake tool run parameters # via the shell command cmake --help, and from # the official CMake documentation. export SDK_PREFIX="/opt/KasperskyOS-Community-Edition-<version>" export TARGET="aarch64-kos" export BOARD="RPI4_BCM2711" export CMAKE="$SDK_PREFIX/toolchain/bin/cmake" export BUILD="build" # Initialize the build system $CMAKE \ -G "Unix Makefiles" \ -D CMAKE_BUILD_TYPE:STRING=Release \ -D CMAKE_TOOLCHAIN_FILE=$SDK_PREFIX/toolchain/share/toolchain-$TARGET-clang.cmake \ -D BOARD="$BOARD" \ -S . \ -B $BUILD # Build # To build a solution image for QEMU, you must specify the target defined in the # NAME parameter of the CMake command build_kos_qemu_image() in the CMakeLists.txt file # for building the Einit program. # To build a solution image for the hardware platform, you must specify the target # defined in the NAME parameter of the CMake command build_kos_hw_image() in the # CMakeLists.txt file for building the Einit program. # To build an SD card image for the hardware platform, you must specify the target # defined in the IMAGE_NAME parameter of the CMake command build_sd_image() in the # CMakeLists.txt file for building the Einit program. # To build a solution image for QEMU and start QEMU with this image, you must # specify the sim target. $CMAKE --build $BUILD --target sim

In this section

CMakeLists.txt root file

CMakeLists.txt files for building applications

CMakeLists.txt file for building the Einit program

init.yaml.in template

security.psl.in template

Page top
[Topic cmake_using_sdk_cmake]

CMakeLists.txt root file

The CMakeLists.txt root file contains general build instructions for the entire solution.

The CMakeLists.txt root file must contain the following commands:

  • cmake_minimum_required (VERSION 3.25) indicates the minimum supported version of CMake.

    For a KasperskyOS-based solution build, CMake version 3.25 or later is required.

    The required version of CMake is provided in KasperskyOS Community Edition and is used by default.

  • include (platform) connects the platform library of CMake.
  • initialize_platform() initializes the platform library.
  • project_header_default("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") sets the flags of the compiler and linker.
  • [Optional] Connect and configure packages for the provided system programs and drivers that need to be included in the solution:
    • A package is connected by using the find_package() command.
    • After connecting a package, you must add the package-related directories to the list of search directories by using the include_directories() command.
    • For some packages, you must also set the values of properties by using the set_target_properties() command.

    CMake descriptions of system programs and drivers provided in KasperskyOS Community Edition, and descriptions of their exported variables and properties are located in the corresponding files at /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/lib/cmake/<program name>/<program name>-config.cmake

  • The Einit initializing program must be built using the add_subdirectory(einit) command.
  • All applications to be built must be added by using the add_subdirectory(<program directory name>) command.

Example CMakeLists.txt root file

CMakeLists.txt

cmake_minimum_required(VERSION 3.25) project (example) # Initializes the CMake library for the KasperskyOS SDK. include (platform) initialize_platform () # Set the linker and compiler flags. project_header_default ("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") # Add package importing components for working with Virtual File System. # Components are imported from the following file: /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/lib/cmake/vfs/vfs-config.cmake find_package (vfs REQUIRED COMPONENTS ENTITY CLIENT_LIB) include_directories (${vfs_INCLUDE}) # Build the Hello application. add_subdirectory (hello) # Build the Einit initializing program. add_subdirectory (einit)
Page top
[Topic cmake_lists_root]

CMakeLists.txt files for building applications

The CMakeLists.txt file for building an application must contain the following commands:

  • include (platform/nk) connects the CMake library for working with the NK compiler.
  • project_header_default ("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") sets the flags of the compiler and linker.
  • An EDL description of a process class for a program can be generated by using the generate_edl_file() command.
  • If the program provides endpoints using an IPC mechanism, the following transport code must be generated:
    1. idl.h files are generated by the nk_build_idl_files() command
    2. cdl.h files are generated by the nk_build_cdl_files() command
    3. edl.h files are generated by the nk_build_edl_files() command
  • add_executable (<program name> "<path to the file containing the program source code>") adds the program build target.
  • add_dependencies (<program name> <name of the edl.h file build target>) adds a program build dependency on edl.h file generation.
  • target_link_libraries (<program name> <list of libraries>) determines the libraries that need to be linked with the program during the build.

    For example, if the program uses file I/O or network I/O, it must be linked with the vfs::client transport library.

    CMake descriptions of system programs and drivers provided in KasperskyOS Community Edition, and descriptions of their exported variables and properties are located in the corresponding files at /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/lib/cmake/<program name>/<program name>-config.cmake

  • To automatically add descriptions of IPC channels to the init.yaml file when building a solution, you must define the EXTRA_CONNECTIONS property and assign it a value with descriptions of the relevant IPC channels.

    Please note the indentations at the beginning of strings in the EXTRA_CONNECTIONS property. These indentations are necessary to correctly insert values into the init.yaml file and must comply with its syntax requirements.

    Example of creating an IPC channel between a Client process and a Server process:

    set_target_properties (Client PROPERTIES EXTRA_CONNECTIONS " - target: Server id: server_connection")

    When building this solution, the description of this IPC channel will be automatically added to the init.yaml file when processing macros of the init.yaml.in template.

  • To automatically add a list of arguments for the main() function and a dictionary of environment variables to the init.yaml file when building a solution, you must define the EXTRA_ARGS and EXTRA_ENV properties and assign the appropriate values to them.

    Note the indentations at the beginning of strings in the EXTRA_ARGS and EXTRA_ENV properties. These indentations are necessary to correctly insert values into the init.yaml file and must comply with its syntax requirements.

    Example of sending the Client program the "-v" argument of the main() function and the environment variable VAR1 set to VALUE1:

    set_target_properties (Client PROPERTIES EXTRA_ARGS " - \"-v\"" EXTRA_ENV " VAR1: VALUE1")

    When building this solution, the description of the main() function argument and the environment variable value will be automatically added to the init.yaml file when processing macros of the init.yaml.in template.

Example CMakeLists.txt file for building a simple application

CMakeLists.txt

project (hello) # Include the CMake library named nk for working with the NK compiler (nk-gen-c). include (platform/nk) # Set the linker and compiler flags. project_header_default ("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") # Define the name of the project that includes the program. set (LOCAL_MODULE_NAME "example") # Define the program name. set (TASK_NAME "Hello") # Please note the contents of the init.yaml.in and security.psl.in templates # They define program names as ${LOCAL_MODULE_NAME}.${TASK_NAME} # Define the targets that will be used to create the generated files of the program. set (TASK_IDL_TARGET ${TASK_NAME}_idl) set (TASK_CDL_TARGET ${TASK_NAME}_cdl) set (TASK_EDL_TARGET ${TASK_NAME}_edl) # Add the idl.h file build target. nk_build_idl_files (${TASK_IDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} IDL "../resources/Hello.idl" ) # Add the cdl.h file build target. nk_build_cdl_files (${TASK_CDL_TARGET} IDL_TARGET ${TASK_IDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} CDL "../resources/Hello.cdl" ) # Add the EDL file build target.The EDL_FILE variable is exported # and contains the path to the generated EDL file. generate_edl_file (${TASK_NAME} PREFIX ${LOCAL_MODULE_NAME} ) # Add the edl.h file build target. nk_build_edl_files (${TASK_EDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} EDL ${EDL_FILE} ) # Define the target for the program build. add_executable (${TASK_NAME} "src/hello.c") # Libraries that are linked to the program during the build. target_link_libraries (${TASK_NAME} PUBLIC vfs::client # The program uses file I/O # and must be connected as a client to VFS ) # Add a dependency on the Hello_edl target to the Hello target. # The edl.h file must be generated before the Hello target is built. add_dependencies (${TASK_NAME} ${TASK_EDL_TARGET})
Page top
[Topic cmake_lists_applied]

CMakeLists.txt file for building the Einit program

The CMakeLists.txt file for building the Einit initializing program must contain the following commands:

  • include (platform/image) connects the CMake library that contains the solution image build scripts.
  • project_header_default ("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") sets the flags of the compiler and linker.
  • Configure the packages of system programs and drivers that need to be included in the solution.
    • A package is connected by using the find_package () command.
    • For some packages, you must also set the values of properties by using the set_target_properties () command.

    CMake descriptions of system programs and drivers provided in KasperskyOS Community Edition, and descriptions of their exported variables and properties are located in the corresponding files at /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/lib/cmake/<program name>/<program name>-config.cmake

  • To automatically add descriptions of IPC channels between processes of system programs to the init.yaml file when building a solution, you must add these channels to the EXTRA_CONNECTIONS property for the corresponding programs.

    Please note the indentations at the beginning of strings in the EXTRA_CONNECTIONS property. These indentations are necessary to correctly insert values into the init.yaml file and must comply with its syntax requirements.

    For example, the VFS program does not have a channel for connecting to the Env program by default. To automatically add a description of this channel to the init.yaml file during a solution build, you must add the following call to the CMakeLists.txt file for building the Einit program:

    set_target_properties (vfs_entity::entity PROPERTIES EXTRA_CONNECTIONS " - target: env.Env id: {var: ENV_SERVICE_NAME, include: env/env.h}"

    When building this solution, the description of this IPC channel will be automatically added to the init.yaml file when processing macros of the init.yaml.in template.

  • To automatically add a list of arguments for the main() function and a dictionary of environment variables to the init.yaml file when building a solution, you must define the EXTRA_ARGS and EXTRA_ENV properties and assign the appropriate values to them.

    Note the indentations at the beginning of strings in the EXTRA_ARGS and EXTRA_ENV properties. These indentations are necessary to correctly insert values into the init.yaml file and must comply with its syntax requirements.

    Example of sending the VfsEntity program the "-f fstab" argument of the main() function and the environment variable ROOTFS set to ramdisk0,0 / ext2 0:

    set_target_properties (vfs_entity::entity PROPERTIES EXTRA_ARGS " - \"-f\" - \"fstab\"" EXTRA_ENV " ROOTFS: ramdisk0,0 / ext2 0")

    When building this solution, the description of the main() function argument and the environment variable value will be automatically added to the init.yaml file when processing macros of the init.yaml.in template.

  • set(ENTITIES <full list of programs included in the solution>) defines the ENTITIES variable containing a list of executable files of all programs included in the solution.
  • One or more commands for building the solution image:
    • build_kos_hw_image() creates the target for building a solution image for the hardware platform.
    • build_sd_image() – creates the target for building an SD card image for running a solution on the hardware platform.
    • build_kos_qemu_image() creates the target for building a solution image for QEMU.

Example CMakeLists.txt file for building the Einit program

CMakeLists.txt

project (einit) # Connect the library containing solution image build scripts. include (platform/image) include (${KL_SDK_ROOT_PATH}/common/build-sd-image.cmake) # Set the linker and compiler flags. project_header_default ("STANDARD_GNU_17:YES" "STRICT_WARNINGS:NO") # Define the CONNECTIONS_CFG_FILE variable containing the path to the init.yaml.in template. set (CONNECTIONS_CFG_FILE "src/init.yaml.in") # Define the SECURITY_PSL variable containing the path to the security.psl.in template. set (SECURITY_PSL "src/security.psl.in") # Configure the VFS program. # By default, the VFS program is not mapped to a program implementing a block device. # If you need to use a block device, such as ata from the ata component, # you must define this device in the blkdev::entity_REPLACEMENT variable # For more information about exported variables and properties of the VFS program, # see /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/lib/cmake/vfs/vfs-config.cmake # find_package(ata) # set_target_properties (vfs_entity::entity PROPERTIES blkdev::entity_REPLACEMENT ata::entity) # In the simplest case, you do not need to interact with a drive. # For this reason, we set the value of the blkdev::entity_REPLACEMENT variable equal to an empty string set_target_properties (vfs_entity::entity PROPERTIES blkdev::entity_REPLACEMENT "") # Define the ENTITIES variable with a list of executable files of programs. # It is important to include all programs that are part of the project, except the Einit program. # Please note that the name of the executable file of a program must # match the name of the target indicated in add_executable() in the CMakeLists.txt file for building this program. set(ENTITIES vfs_entity::entity Hello ) # Create the build target named kos-image, which is a solution image for the hardware platform. build_kos_hw_image (kos-image EINIT_ENTITY EinitHw CONNECTIONS_CFG ${CONNECTIONS_CFG_FILE} SECURITY_PSL ${SECURITY_PSL} IMAGE_FILES ${ENTITIES} ) # Create a build target named sd-image that can be used to create an SD-card image # for running a solution on the hardware platform. build_sd_image (sd-image KOS_IMAGE_TARGET kos-image ) # Create the build target named kos-qemu-image, which is a solution image for QEMU. build_kos_qemu_image (kos-qemu-image EINIT_ENTITY EinitQemu CONNECTIONS_CFG ${CONNECTIONS_CFG_FILE} SECURITY_PSL ${SECURITY_PSL} IMAGE_FILES ${ENTITIES} )
Page top
[Topic cmake_lists_einit]

init.yaml.in template

The init.yaml.in template is used to automatically generate a part of the init.yaml file prior to building the Einit program using CMake tools.

When using the init.yaml.in template, you do not have to manually add descriptions of system programs and the IPC channels for connecting to them to the init.yaml file.

The init.yaml.in template must contain the following data:

  • Root entities key.
  • List of all applications included in the solution.
  • For applications that use an IPC mechanism, you must specify a list of IPC channels that connect this application to other applications.

    The IPC channels that connect this application to other applications are either indicated manually or specified in the CMakeLists.txt file for this application using the EXTRA_CONNECTIONS property.

    To specify a list of IPC channels that connect this application to system programs that are included in KasperskyOS Community Edition, the following macros are used:

    • @INIT_<program name>_ENTITY_CONNECTIONS@ – during the build, this is replaced with the list of IPC channels containing all system programs that are linked to the application. The target and id fields are filled according to the connect.yaml files from KasperskyOS Community Edition located in /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/<system program name>).

      This macro needs to be used if the application does not have connections to other applications but instead connects only to system programs. This macro adds the root connections key.

    • @INIT_<program name>_ENTITY_CONNECTIONS+@ – during the build, the list of IPC channels containing all system programs that are linked to the application is added to the manually defined list of IPC channels. This macro does not add the root connections key.

      This macro needs to be used if the application has connections to other applications that were manually indicated in the init.yaml.in template.

  • The @INIT_<program name>_ENTITY_CONNECTIONS@ and @INIT_<program name>_ENTITY_CONNECTIONS+@ macros also add the list of connections for each program defined in the EXTRA_CONNECTIONS property when building this program.
  • If you need to pass main() function arguments defined in the EXTRA_ARGS property to a program when building this program, you need to use the following macros:
    • @INIT_<program name>_ENTITY_ARGS@ – during the build, this is replaced with the list of arguments of the main() function defined in the EXTRA_ARGS property. This macro adds the root args key.
    • @INIT_<program name>_ENTITY_ARGS+@ – during the build, this macro adds the list of main() function arguments defined in the EXTRA_ARGS property to the list of manually defined arguments. This macro does not add the root args key.
  • If you need to pass the values of environment variables defined in the EXTRA_ENV property to a program when building this program, you need to use the following macros:
    • @INIT_<program name>_ENTITY_ENV@ – during the build, this is replaced with the dictionary of environment variables and their values defined in the EXTRA_ENV property. This macro adds the root env key.
    • @INIT_<program name>_ENTITY_ENV+@ – during the build, this macro adds the dictionary of environment variables and their values defined in the EXTRA_ENV property to the manually defined variables. This macro does not add the root env key.
  • @INIT_EXTERNAL_ENTITIES@ – during the build, this macro is replaced with the list of system programs linked to the application and their IPC channels, main() function arguments, and values of environment variables.

Example init.yaml.in template

init.yaml.in

entities: - name: ping.Client connections: # The "Client" program can query the "Server" - target: ping.Server id: server_connection @INIT_Client_ENTITY_CONNECTIONS+@ @INIT_Client_ENTITY_ARGS@ @INIT_Client_ENTITY_ENV@ - name: ping.Server @INIT_Server_ENTITY_CONNECTIONS@ @INIT_EXTERNAL_ENTITIES@

When building the Einit program from this template, the following init.yaml file will be generated:

init.yaml

entities: - name: ping.Client connections: # The "Client" program can query the "Server" - target: ping.Server id: server_connection - target: kl.VfsEntity id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h} args: - "-v" env: VAR1: VALUE1 - name: ping.Server connections: - target: kl.VfsEntity id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h} - name: kl.VfsEntity path: VFS args: - "-f" - "fstab" env: ROOTFS: ramdisk0,0 / ext2
Page top
[Topic cmake_yaml_templates]

security.psl.in template

The security.psl.in template is used to automatically generate a part of the security.psl file prior to building the Einit program using CMake tools.

The security.psl file contains part of the solution security policy description.

When using the security.psl.in template, you do not have to manually add EDL descriptions of system programs to the security.psl file.

The security.psl.in template must contain a manually created solution security policy description, including the following declarations:

  • Set the global parameters of a solution security policy
  • Include PSL files in a solution security policy description
  • Include EDL files of application software in a solution security policy description
  • Create security model objects
  • Bind methods of security models to security events
  • Create security audit profiles

To automatically include system programs, the @INIT_EXTERNAL_ENTITIES@ macro must be used.

Example security.psl.in template

security.psl.in

execute: kl.core.Execute use nk.base._ use EDL Einit use EDL kl.core.Core use EDL Client use EDL Server @INIT_EXTERNAL_ENTITIES@ /* Startup of programs is allowed */ execute { grant () } /* Sending and receiving requests, responses and errors is allowed. */ request { grant () } response { grant () } error { grant () } /* Queries via the security interface are ignored. */ security { grant () }
Page top
[Topic cmake_psl_templates]

CMake libraries in KasperskyOS Community Edition

This section contains a description of the libraries that are provided in KasperskyOS Community Edition for automatically building a KasperskyOS-based solution.

In this section

platform library

nk library

image library

build_sd_image library

kpa library

Page top
[Topic cmake_libs]

platform library

The platform library contains the following commands:

  • initialize_platform() is the command for initializing the platform library.

    The initialize_platform() command can be called with the FORCE_STATIC parameter, which enables forced static linking of executable files:

    • By default, if the toolchain in the KasperskyOS SDK supports dynamic linking, the initialize_platform() command causes the -rdynamic flag to be used automatically for building all executable files defined via CMake add_executable() commands.
    • When calling initialize_platform (FORCE_STATIC) in the CMakeLists.txt root file, the toolchain supporting dynamic linking performs static linking of executable files.

    The initialize_platform() command can be called with the NO_NEW_VERSION_CHECK parameter, which disables the check for SDK updates and transmission of the SDK version to the Kaspersky server.

    To disable the check for SDK updates and transmission of SDK version data to the Kaspersky server, use the following call during the solution build: initialize_platform(NO_NEW_VERSION_CHECK). For more details about the data provision policy, see Data provision.

  • project_static_executable_header_default() is the command for enabling forced static linking of executable files defined via subsequent CMake add_executable() commands in one CMakeLists.txt file. The toolchain that supports dynamic linking performs static linking of these executable files.
  • platform_target_force_static() is the command for enabling forced static linking of an executable file defined via the CMake add_executable() command. The toolchain that supports dynamic linking performs static linking of this executable file. For example, if the CMake commands add_executable(client "src/client.c") and platform_target_force_static(client) are called, static linking is performed for the client program.
  • project_header_default() is the command for setting compile flags.

    Command parameters are defined in pairs consisting of a compile flag and its value: "FLAG_1:VALUE_1" "FLAG_2:VALUE_2" ... "FLAG_N:VALUE_N". The CMake platform library converts these pairs into compiler parameters.

When using the initialize_platform(FORCE_STATIC), project_static_executable_header_default() and platform_target_force_static() commands, you may encounter linking errors if the static variants of the required libraries are missing (for example, if they were not built or are not included in the KasperskyOS SDK). Even if the static variants of the required libraries are available, these errors may still occur because the build system searches for the dynamic variants of required libraries by default instead of the expected static variants when using the initialize_platform(FORCE_STATIC), project_static_executable_header_default() and platform_target_force_static() commands. To avoid errors, first make sure that the static variants are available. Then configure the build system to search for static libraries (although this capability may not be available for some libraries), or explicitly define linking with static libraries.

Examples of configuring the build system to search for static libraries:

set (fmt_USE_STATIC ON) find_package (fmt REQUIRED) set (fdn_USE_STATIC ON) find_package (fdn REQUIRED) set (sqlite_wrapper_USE_STATIC ON) find_package (sqlite_wrapper REQUIRED)

Example that explicitly defines linking with a static library:

target_link_libraries(${PROJECT_NAME} PUBLIC logger::logger-static)

For more details about using dynamic libraries, see Using dynamic libraries.

These commands are used in CMakeLists.txt files for the Einit program and application software.

Page top
[Topic cmake_platform_lib]

nk library

This section contains a description of the commands and macros of the CMake library for working with the NK compiler.

In this section

generate_edl_file()

nk_build_idl_files()

nk_build_cdl_files()

nk_build_edl_files()

Generating transport code for development in C++

Page top
[Topic cmake_nk_lib]

generate_edl_file()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

generate_edl_file(NAME ...)

This command generates an EDL file containing a description of the process class.

Parameters:

  • NAME – name of the EDL file being created. Required parameter.
  • PREFIX – parameter in which you need to specify the name of the process class, excluding the name of the EDL file. For example, if the name of the process class for which the EDL file is being created is defined as kl.core.NameServer, the PREFIX parameter must pass the value kl.core.
  • EDL_COMPONENTS – name of the component and its instance that will be included in the EDL file. For example: EDL_COMPONENTS "env: kl.Env". To include multiple components, you need to use multiple EDL_COMPONENTS parameters.
  • SECURITY – qualified name of the security interface method that will be included in the EDL file.
  • OUTPUT_DIR – directory in which the EDL file will be created. The default directory is ${CMAKE_CURRENT_BINARY_DIR}.

As a result of this command, the EDL_FILE variable is exported and contains the path to the generated EDL file.

Example call:

generate_edl_file(${ENTITY_NAME} EDL_COMPONENTS "env: kl.Env")

For an example of using this command, see the article titled CMakeLists.txt files for building application software.

Page top
[Topic cmake_generate_edl]

nk_build_idl_files()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_idl_files(NAME ...)

This command creates a CMake target for generating .idl.h files for one or more defined IDL files using the NK compiler.

Parameters:

  • NAME – name of the CMake target for building .idl.h files. If a target has not yet been created, it will be created by using add_library() with the specified name. Required parameter.
  • NOINSTALL – if this option is specified, files will only be generated in the working directory and will not be installed in global directories: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • NK_MODULE – parameter in which you need to specify the package name, excluding the name of the IDL file. For example, if the package name in the IDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • WORKING_DIRECTORY – working directory for calling the NK compiler, which is ${CMAKE_CURRENT_BINARY_DIR} by default.
  • DEPENDS – additional build targets on which the IDL file depends.

    To add multiple targets, you need to use multiple DEPENDS parameters.

  • IDL – path to the IDL file for which the idl.h file is being generated. Required parameter.

    To add multiple IDL files, you need to use multiple IDL parameters.

    If one IDL file imports another IDL file, idl.h files need to be generated in the order necessary for compliance with dependencies (with the most deeply nested first).

  • NK_FLAGS – additional flags for the NK compiler.

Example call:

nk_build_idl_files (echo_idl_files NK_MODULE "echo" IDL "resources/Ping.idl" NK_FLAGS "--extended-errors" "--trace-client-ipc=headers")

For an example of using this command, see the article titled CMakeLists.txt files for building application software.

Page top
[Topic cmake_build_idl]

nk_build_cdl_files()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_cdl_files(NAME ...)

This command creates a CMake target for generating .cdl.h files for one or more defined CDL files using the NK compiler.

Parameters:

  • NAME – name of the CMake target for building .cdl.h files. If a target has not yet been created, it will be created by using add_library() with the specified name. Required parameter.
  • NOINSTALL – if this option is specified, files will only be generated in the working directory and are not installed in global directories: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • IDL_TARGET – target when building .idl.h files for IDL files containing descriptions of endpoints provided by components described in CDL files.
  • NK_MODULE – parameter in which you need to specify the component name, excluding the name of the CDL file. For example, if the component name in the CDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • WORKING_DIRECTORY – working directory for calling the NK compiler, which is ${CMAKE_CURRENT_BINARY_DIR} by default.
  • DEPENDS – additional build targets on which the CDL file depends.

    To add multiple targets, you need to use multiple DEPENDS parameters.

  • CDL – path to the CDL file for which the .cdl.h file is being generated. Required parameter.

    To add multiple CDL files, you need to use multiple CDL parameters.

  • NK_FLAGS – additional flags for the NK compiler.

Example call:

nk_build_cdl_files (echo_cdl_files IDL_TARGET echo_idl_files NK_MODULE "echo" CDL "resources/Ping.cdl")

For an example of using this command, see the article titled CMakeLists.txt files for building application software.

Page top
[Topic cmake_build_cdl]

nk_build_edl_files()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_edl_files(NAME ...)

This command creates a CMake target for generating an .edl.h file for one defined EDL file using the NK compiler.

Parameters:

  • NAME – name of the CMake target for building an .edl.h file. If a target has not yet been created, it will be created by using add_library() with the specified name. Required parameter.
  • NOINSTALL – if this option is specified, files will only be generated in the working directory and are not installed in global directories: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • CDL_TARGET – target when building .cdl.h files for CDL files containing descriptions of components of the EDL file for which the build is being performed.
  • IDL_TARGET – target when building .idl.h files for IDL files containing descriptions of interfaces of the EDL file for which the build is being performed.
  • NK_MODULE – parameter in which you need to specify the name of the process class, excluding the name of the EDL file. For example, if the process class name in the EDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • WORKING_DIRECTORY – working directory for calling the NK compiler, which is ${CMAKE_CURRENT_BINARY_DIR} by default.
  • DEPENDS – additional build targets on which the EDL file depends.

    To add multiple targets, you need to use multiple DEPENDS parameters.

  • EDL – path to the EDL file for which the edl.h file is being generated. Required parameter.
  • NK_FLAGS – additional flags for the NK compiler.

Example calls:

nk_build_edl_files (echo_server_edl_files CDL_TARGET echo_cdl_files NK_MODULE "echo" EDL "resources/Server.edl") nk_build_edl_files (echo_client_edl_files NK_MODULE "echo" EDL "resources/Client.edl" NK_FLAGS "--extended-errors")

For an example of using this command, see the article titled CMakeLists.txt files for building application software.

Page top
[Topic cmake_build_edl]

Generating transport code for development in C++

The CMake commands add_nk_idl(), add_nk_cdl() and add_nk_edl() are used to generate transport proxy objects and stubs using the nkppmeta compiler when building a solution.

In this section

add_nk_idl()

add_nk_cdl()

add_nk_edl()

Page top
[Topic cmake_cpp]

add_nk_idl()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_idl(NAME IDL_FILE ...)

This command creates a CMake target for generating a *.idl.cpp.h header file for a defined IDL file using the nkppmeta compiler. The command also creates a library containing the transport code for the defined interface. To link to this library, use the bind_nk_targets() command.

The generated header files contain a C++ representation for the interface and data types described in the IDL file, and the methods required for use of proxy objects and stubs.

Parameters:

  • NAME – name of the CMake target. Required parameter.
  • IDL_FILE – path to the IDL file. Required parameter.
  • NK_MODULE – parameter in which you need to specify the package name, excluding the name of the IDL file. For example, if the package name in the IDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • LANG – parameter in which you need to specify the CXX value.

Example call:

add_nk_idl (ANIMAL_IDL "${CMAKE_SOURCE_DIR}/resources/Animal.idl" NK_MODULE "example" LANG "CXX")
Page top
[Topic add_nk_idl]

add_nk_cdl()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_cdl(NAME CDL_FILE ...)

This command creates a CMake target for generating a *.cdl.cpp.h file for a defined CDL file using the nkppmeta compiler. The command also creates a library containing the transport code for the defined component. To link to this library, use the bind_nk_targets() command.

The *.cdl.cpp.h file contains the tree of embedded components and endpoints provided by the component described in the CDL file.

Parameters:

  • NAME – name of the CMake target. Required parameter.
  • CDL_FILE – path to the CDL file. Required parameter.
  • NK_MODULE – parameter in which you need to specify the component name, excluding the name of the CDL file. For example, if the component name in the CDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • LANG – parameter in which you need to specify the CXX value.

Example call:

add_nk_cdl (CAT_CDL "${CMAKE_SOURCE_DIR}/resources/Cat.cdl" NK_MODULE "example" LANG "CXX")
Page top
[Topic add_nk_cdl]

add_nk_edl()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_edl(NAME EDL_FILE ...)

This command creates a CMake target for generating a *.edl.cpp.h file for a defined EDL file using the nkppmeta compiler. The command also creates a library containing the transport code for the server or client program. To link to this library, use the bind_nk_targets() command.

The *.edl.cpp.h file contains the tree of embedded components and endpoints provided by the process class described in the EDL file.

Parameters:

  • NAME – name of the CMake target. Required parameter.
  • EDL_FILE – path to the EDL file. Required parameter.
  • NK_MODULE – parameter in which you need to specify the name of the process class, excluding the name of the EDL file. For example, if the process class name in the EDL description is defined as kl.core.NameServer, the kl.core value must be passed in the NK_MODULE parameter.
  • LANG – parameter in which you need to specify the CXX value.

Example call:

add_nk_edl (SERVER_EDL "${CMAKE_SOURCE_DIR}/resources/Server.edl" NK_MODULE "example" LANG "CXX")
Page top
[Topic add_nk_edl]

image library

This section contains a description of the commands and macros of the CMake library named image that is included in KasperskyOS Community Edition and contains solution image build scripts.

In this section

build_kos_qemu_image()

build_kos_hw_image()

Page top
[Topic cmake_image_lib]

build_kos_qemu_image()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/image.cmake.

build_kos_qemu_image(NAME ...)

The command creates a CMake target for building a solution image for QEMU.

Parameters:

  • NAME – name of the CMake target for building a solution image. Required parameter.
  • PERFCNT_KERNEL – use the kernel with performance counters if it is available in KasperskyOS Community Edition.
  • EINIT_ENTITY – name of the executable file that will be used to start the Einit program.
  • EXTRA_XDL_DIR – additional directories to include when building the Einit program.
  • CONNECTIONS_CFG – path to the init.yaml file or init.yaml.in template.
  • SECURITY_PSL – path to the security.psl file or security.psl.in template.
  • KLOG_ENTITY – target for building the Klog system program, which is responsible for the security audit. If the target is not specified, the audit is not performed.
  • QEMU_FLAGS – additional flags for running QEMU.
  • IMAGE_BINARY_DIR_BIN – directory for the final image and other artifacts. It matches CMAKE_CURRENT_BINARY_DIR by default.
  • NO_AUTO_BLOB_CONTAINER – solution image will not include the BlobContainer program that is required for working with dynamic libraries in shared memory. For more details, refer to Including the BlobContainer system program in a KasperskyOS-based solution.
  • PACK_DEPS, PACK_DEPS_COPY_ONLY, PACK_DEPS_LIBS_PATH, and PACK_DEPS_COPY_TARGET – parameters that define the method used to add dynamic libraries to the solution image.
  • GINGER_ENABLE – enable (GINGER_ENABLE TRUE) or disable (GINGER_ENABLE FALSE) the Ginger template engine.
  • GINGER_DEFINITIONS – set of variables used when expanding Ginger PSL templates. For example, GINGER_DEFINITIONS "foo=bar baz=quux USE_DYNLD" sets the foo variable to bar, sets the baz variable to quux, and sets the USE_DYNLD variable to TRUE. The USE_DYNLD variable is set to TRUE because variables used when expanding Ginger PSL templates are set to TRUE by default.
  • GINGER_DUMP_DIR – path to the directory where PSL files received from Ginger PSL templates will be stored. These PSL files are needed only to verify what was obtained as a result of expanding Ginger PSL templates, and are not used to generate source code of the Kaspersky Security Module. (When source code of the security module is generated, Ginger PSL templates are expanded in memory irrespective of whether or not the GINGER_DUMP_DIR parameter is being used.) The names of PSL files are generated based on the absolute paths to Ginger PSL templates. For example, the PSL file named foo!bar!baz.psl corresponds to the Ginger PSL template located at the path /foo/bar/baz.psl.
  • IMAGE_FILES – executable files of applications and system programs (except the Einit program) and any other files to be added to the ROMFS image.

    To add multiple applications or files, you can use multiple IMAGE_FILES parameters.

  • <path to files> – free parameters like IMAGE_FILES.

Example call:

build_kos_qemu_image ( kos-qemu-image EINIT_ENTITY EinitQemu CONNECTIONS_CFG "src/init.yaml.in" SECURITY_CFG "src/security.cfg.in" IMAGE_FILES ${ENTITIES})

For an example of using this command, see the article titled CMakeLists.txt files for building the Einit program.

Page top
[Topic cmake_build_qemu]

build_kos_hw_image()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/image.cmake.

build_kos_hw_image(NAME ...)

The command creates a CMake target for building a solution image for the hardware platform.

Parameters:

  • NAME – name of the CMake target for building a solution image. Required parameter.
  • PERFCNT_KERNEL – use the kernel with performance counters if it is available in KasperskyOS Community Edition.
  • EINIT_ENTITY – name of the executable file that will be used to start the Einit program.
  • EXTRA_XDL_DIR – additional directories to include when building the Einit program.
  • CONNECTIONS_CFG – path to the init.yaml file or init.yaml.in template.
  • SECURITY_PSL – path to the security.psl file or security.psl.in template.
  • KLOG_ENTITY – target for building the Klog system program, which is responsible for the security audit. If the target is not specified, the audit is not performed.
  • IMAGE_BINARY_DIR_BIN – directory for the final image and other artifacts. The default directory is CMAKE_CURRENT_BINARY_DIR.
  • NO_AUTO_BLOB_CONTAINER – solution image will not include the BlobContainer program that is required for working with dynamic libraries in shared memory. For more details, refer to Including the BlobContainer system program in a KasperskyOS-based solution.
  • PACK_DEPS, PACK_DEPS_COPY_ONLY, PACK_DEPS_LIBS_PATH, and PACK_DEPS_COPY_TARGET – parameters that define the method used to add dynamic libraries to the solution image.
  • GINGER_ENABLE – enable (GINGER_ENABLE TRUE) or disable (GINGER_ENABLE FALSE) the Ginger template engine.
  • GINGER_DEFINITIONS – set of variables used when expanding Ginger PSL templates. For example, GINGER_DEFINITIONS "foo=bar baz=quux USE_DYNLD" sets the foo variable to bar, sets the baz variable to quux, and sets the USE_DYNLD variable to TRUE. The USE_DYNLD variable is set to TRUE because variables used when expanding Ginger PSL templates are set to TRUE by default.
  • GINGER_DUMP_DIR – path to the directory where PSL files received from Ginger PSL templates will be stored. These PSL files are needed only to verify what was obtained as a result of expanding Ginger PSL templates, and are not used to generate source code of the Kaspersky Security Module. (When source code of the security module is generated, Ginger PSL templates are expanded in memory irrespective of whether or not the GINGER_DUMP_DIR parameter is being used.) The names of PSL files are generated based on the absolute paths to Ginger PSL templates. For example, the PSL file named foo!bar!baz.psl corresponds to the Ginger PSL template located at the path /foo/bar/baz.psl.
  • IMAGE_FILES – executable files of applications and system programs (except the Einit program) and any other files to be added to the ROMFS image.

    To add multiple applications or files, you can use multiple IMAGE_FILES parameters.

  • <path to files> – free parameters like IMAGE_FILES.

Example call:

build_kos_hw_image ( kos-image EINIT_ENTITY EinitHw CONNECTIONS_CFG "src/init.yaml.in" SECURITY_CFG "src/security.cfg.in" IMAGE_FILES ${ENTITIES})

For an example of using this command, see the article titled CMakeLists.txt files for building the Einit program.

Page top
[Topic cmake_build_hw]

build_sd_image library

The build_sd_image library is included in the KasperskyOS SDK and contains the build_sd_image() command. This command is declared in the file named /opt/KasperskyOS-Community-Edition-<version>/common/build-sd-image.cmake.

build_sd_image(IMAGE_NAME ...)

The command creates a CMake target for building an SD card image for running a solution on the hardware platform.

Parameters:

  • IMAGE_NAME – name of the CMake target for building an SD card image for running the solution on the hardware platform. Required parameter.
  • KOS_IMAGE_TARGET – name of the CMake target for building a solution image for the hardware platform that will be added to the SD card image.
  • KOS_COPY_PATH – path to the directory where the solution image for the hardware platform will be copied before it is added to the SD card image.
  • IMAGE_FS – path to the root directory of the file system that will be used for the SD card image. Default value: ${CMAKE_BINARY_DIR}/hdd.
  • OUTPUT_IMAGE_NAME – name of the SD card image.
  • DISK_SIZE – size of the created SD card image in megabytes. Default value: 1024 MB.
  • PARTITION_CMD – set of parameters that will be used to create and configure partitions in the SD card image. Separate the parameters with a space.

Example call:

include (${KL_SDK_ROOT_PATH}/common/build-sd-image.cmake) set (IMAGE_FS "${CMAKE_BINARY_DIR}/hdd") set (IMAGE_PART1_FS "${IMAGE_FS}/part1") set (IMAGE_PART2_FS "${IMAGE_FS}/part2") set (DISK_IMAGE hdd.img) build_sd_image (sd-image KOS_IMAGE_TARGET kos-image KOS_COPY_PATH ${IMAGE_PART1_FS} IMAGE_FS ${IMAGE_FS} DISK_SIZE 512 OUTPUT_IMAGE_NAME ${DISK_IMAGE} PARTITION_CMD -p1 ${IMAGE_PART1_FS} -%1 50 -f1 fat32 -p2 ${IMAGE_PART2_FS} -%2 50 -f2 ext4)
Page top
[Topic cmake_build_sd]

kpa library

This section contains a description of commands of the CMake library kpa, which is intended for building KPA packages.

In this section

add_kpa_package()

add_kpa_component()

Page top
[Topic cmake_kpa_lib]

add_kpa_package()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/kpa.cmake.

add_kpa_package(KPA_TARGET_NAME ...)

The command creates a CMake target for building the KPA package. When building this target, the build process automatically creates the KPA package manifest and the KPA package, which includes all components that were added to this target using the CMake command add_kpa_component().

Parameters:

  • KPA_TARGET_NAME – name of the CMake target. Required parameter.
  • MANIFEST_V – version of the KPA package manifest. Required parameter. It must be set to 2.
  • VERSION – version of the KPA package. The default value is PROJECT_VERSION.
  • ID – ID of the KPA package. The default value is KPA_TARGET_NAME.
  • DEVELOPER_ID – identifier of the developer. The default value is "unspecified".
  • DONT_VERIFY—if this parameter is defined, verification of the presence of all KPA package components specified in its manifest and the absence of unspecified components, and calculation of the checksums of KPA package components and their comparison with those specified in the KPA package manifest will not be performed.

Properties of the created CMake target:

  • KPA_OUTPUT_DIR – directory in which the KPA package will be put.
  • KPA_OUTPUT_NAME – name of the KPA file without the file extension. The default value is ${DEVELOPER_ID}.${ID}.

Example call:

include (platform/kpa) add_kpa_package (Hello.kpa ALL ID "hello" DEVELOPER_ID test_dev MANIFEST_V "2") set_target_properties(Hello.kpa PROPERTIES KPA_OUTPUT_NAME "hello")
Page top
[Topic cmake_kpa_package]

add_kpa_component()

This command is declared in the file /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/kpa.cmake.

add_kpa_component(PACKAGE_NAME MODE ...)

The command adds the component to the specified CMake target for building the KPA package. This command can be called multiple times for the same KPA package build target. A KPA package build target is created by the add_kpa_package() command.

Parameters:

  • PACKAGE_NAME – name of the CMake target for building the KPA package. Required parameter.
  • MODE – type of component. Required parameter. The following values are possible:
    • LIBRARY – the component is a dynamic library. You must specify the full path to the file or the name of the CMake target. It is put into the directory /<package_name>/lib when the KPA package is installed.
    • FILES – the component is a file. You must specify the full path to the file. When a KPA package is installed, it is put into the /<package_name>/res directory.
    • DIRECTORY – the component is a directory containing files. You must specify the full path to the directory. When a KPA package is installed, it is put into the /<package_name>/res directory.
    • RUN_CONFIGURATION – the component is a program run configuration. You must specify the following parameters:
      • ID – startup configuration ID that is unique within the KPA package. Required parameter.
      • NAME – startup configuration name. Required parameter.
      • TYPE – type of run configuration: "gui" – process with a graphical user interface or "service" – endpoint process. Required parameter.
      • PATH – full path to the executable file of the component after KPA package installation relative to the /<package_name> directory.
      • EIID – security class of the program. Required parameter.
      • PRIMARY – indicates whether the startup configuration is the primary one during program startup.
      • AUTORUN – indicates whether this configuration is started automatically.
      • ARGS – list of command-line arguments in the form of a string array for starting the program.
      • ENV – list of environment variables for starting the program.
    • RESOURCE – used for adding arbitrary data to the KPA package. You must specify the following parameters:
      • Full path to the file or directory containing the data. Required parameter.
      • In the TYPE parameter, specify the data type: "res", "bin", "lib" or "manifestLocale". Required parameter. For more details, refer to List of "components" objects.
      • (Optional) In the DIRECTORY_PATH parameter, specify the path to the directory where the data will be put after KPA package installation; the specified path should be relative to the /<package_name>/res directory.

Example calls:

include (platform/kpa) # Add the program executable file add_kpa_component(Hello.kpa RESOURCE ".build/aarch64-kos-debug/hello/Hello" TYPE "bin" DIRECTORY_PATH "bin/") Adding program startup configuration add_kpa_component(Hello.kpa RUN_CONFIGURATION "app" NAME "Hello app" TYPE "service" EIID "hello.Hello" PATH "bin/Hello")
Page top
[Topic cmake_kpa_component]

Building without CMake

This section contains a description of the scripts, tools, compilers and build templates provided in KasperskyOS Community Edition.

These tools can be used:

  • In other build systems.
  • To perform individual steps of the build.
  • To analyze the build specifications and write a custom build system.

The general scenario for building a solution image is described in the article titled Build process overview.

In this section

Tools for building a solution

Page top
[Topic cmake_no_cmake_build]

Tools for building a solution

This section contains a description of the scripts, tools, compilers and build templates provided in KasperskyOS Community Edition.

In this section

Build scripts and tools

Cross compilers

Page top
[Topic solution_build_tools]

Build scripts and tools

KasperskyOS Community Edition includes the following build scripts and tools:

  • nk-gen-c

    The NK compiler (nk-gen-c) generates transport code based on the IDL, CDL, and EDL descriptions. Transport code is needed for generating, sending, receiving, and processing IPC messages.

  • nk-psl-gen-c

    The nk-psl-gen-c compiler generates the C-language source code of the Kaspersky Security Module based on the solution security policy description and the IDL, CDL, and EDL descriptions. The nk-psl-gen-c compiler also generates the C-language source code of solution security policy tests based on solution security policy tests in PAL.

  • einit

    The einit tool automates the creation of code for the Einit initializing program. This program is the first to start when KasperskyOS is loaded. Then it starts all other programs and creates IPC channels between them.

  • makekss

    The makekss script creates the Kaspersky Security Module.

  • makeimg

    The makeimg script creates the final boot image of the KasperskyOS-based solution with all programs to be started and the Kaspersky Security Module.

Page top
[Topic build_utilities_and_scripts]

nk-gen-c

The NK compiler (nk-gen-c) generates transport code based on the IDL, CDL, and EDL descriptions.

The nk-gen-c compiler receives the IDL, CDL or EDL file and creates the following files:

  • A *.*dl.h file containing the transport code.
  • A *.*dl.nk.d file that lists the created *.*dl.h file's dependencies on the IDL and CDL files. The *.*dl.nk.d file is created for the build system.

Syntax of the shell command for starting the nk-gen-c compiler:

nk-gen-c -I <SYSROOT_INCLUDE_PATH> [-I <PATH>]... [-o <PATH>] [--types] [--interface] [--endpoints] [--client] [--server] [--extended-errors] [(--deprecated-no-extended-errors)] [--trace-client-ipc {headers|dump}] [--trace-server-ipc {headers|dump}] [--ipc-trace-method-filter <METHOD 1>[,<METHOD 2>]...] [-h|--help] [--version] <FILE>

Basic parameters:

  • FILE

    Path to the IDL, CDL, or EDL file for which you need to generate transport code.

  • -I <SYSROOT_INCLUDE_PATH>

    Path to the sysroot-*-kos/include directory from the KasperskyOS SDK.

  • -I <PATH>

    These parameters must be used to define the paths to directories containing IDL and CDL files that are referenced by the file defined via the FILE parameter.

  • -o <PATH>

    Path to an existing directory where the created files will be placed. If this parameter is not specified, the created files will be put into the current directory.

  • -h|--help

    Prints the Help text.

  • --version

    Prints the version of the nk-gen-c compiler.

  • --extended-errors

    This parameter provides the capability to use interface methods with one or more error parameters of user-defined IDL types. (The client works with error parameters like it works with output parameters.)

    If the --extended-errors parameter is not specified, you can use interface methods only with one status error parameter of the IDL type UInt16 whose value is received by the client via return code of the interface method. This mechanism for sending error parameters is obsolete and will no longer be supported in the future, so you are advised to always specify the --extended-errors parameter.

  • --deprecated-no-extended-errors

    This parameter is the default parameter and provides the capability to use interface methods only with one status error parameter of the IDL type UInt16 whose value is received by the client via return code of the interface method. If the --deprecated-no-extended-errors parameter is not specified and the --extended-errors parameter is also not specified, you can also use this mechanism to send error parameters. However, in this case there will be no warning about the need to specify the --extended-errors parameter or the --deprecated-no-extended-errors parameter. (You need to specify one of these parameters because the --deprecated-no-extended-errors parameter will eventually cease to be the default parameter in the future, and the nk-gen-c compiler will end with an error if you don't explicitly define the mechanism for sending error parameters.)

Selective generation of transport code

To reduce the volume of generated transport code, you can use flags for selective generation of transport code. For example, you can use the --server flag for programs that implement endpoints, and use the --client flag for programs that utilize the endpoints.

If no selective generation flag for transport code is specified, the nk-gen-c compiler generates transport code with all possible methods and types for the defined IDL, CDL, or EDL file.

Flags for selective generation of transport code for an IDL file:

  • --types

    The transport code includes the types corresponding to the IDL types from the defined IDL file, and the types corresponding to this file's imported IDL types that are used in IDL types of the defined IDL file. However, the types corresponding to imported IDL constants and to the aliases of imported IDL types are not included in the *.idl.h file. To use the types corresponding to imported IDL constants and to the aliases of imported IDL types, you must separately generate the transport code for the IDL files from which you are importing.

  • --interface

    The transport code corresponds to the --types flag, and includes the types of structures of the constant part of IPC requests and IPC responses for interface methods whose signatures are specified in the defined IDL file. In addition, the transport code contains constants indicating the sizes of IPC message arenas.

  • --client

    The transport code corresponds to the --interface flag, and includes the proxy object type, proxy object initialization method, and the interface methods specified in the defined IDL file.

  • --server

    The transport code corresponds to the --interface flag, and includes the types and dispatcher (dispatch method) used to process IPC requests corresponding to the interface methods specified in the defined IDL file.

Flags for selective generation of transport code for a CDL or EDL file:

  • --types

    The transport code includes the types corresponding to the IDL types that are used in the method parameters of endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file).

  • --endpoints

    The transport code corresponds to the --types flag, and includes the types of structures of the constant part of IPC requests and IPC responses for the methods of endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file). In addition, the transport code contains constants indicating the sizes of IPC message arenas.

  • --client

    The transport code corresponds to the --types flag, and includes the types of structures of the constant part of IPC requests and IPC responses for the methods of endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file). In addition, the transport code contains constants indicating the sizes of IPC message arenas, and the proxy object types, proxy object initialization methods, and methods of endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file).

  • --server

    The transport code corresponds to the --types flag, and includes the types and dispatchers (dispatch methods) used to process IPC requests corresponding to the endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file). In addition, the transport code contains constants indicating the sizes of IPC message arenas, and the stub types, stub initialization methods, and the types of structures of the constant part of IPC requests and IPC responses for the methods of endpoints provided by the component (for the defined CDL file) or process class (for the defined EDL file).

Printing diagnostic information about sending and receiving IPC messages

Transport code can generate diagnostic information about sending and receiving IPC messages and print this data via standard error. To generate transport code with these capabilities, use the following parameters:

  • --trace-client-ipc {headers|dump}

    The code for printing diagnostic information is executed directly before the Call() system call is executed and immediately after it is executed. If the headers value is specified, the diagnostic information includes the endpoint method ID (MID), the Runtime Implementation Identifier (RIID), the size of the constant part of the IPC message (in bytes), the contents of the IPC message arena handle, the size of the IPC message arena (in bytes), and the size of the utilized part of the IPC message arena (in bytes). If the dump value is specified, the diagnostic information additionally includes the contents of the constant part and arena of the IPC message in hexadecimal format.

    When using this parameter, you must either specify the selective generation flag for transport code --client or refrain from specifying a selective generation flag for transport code.

  • --trace-server-ipc {headers|dump}

    The code for printing diagnostic information is executed directly before calling the function that implements the interface method, and immediately after the completion of this function. In other words, it is executed when the dispatcher (dispatch method) is called in the interval between execution of the Recv() and Reply() system calls. If the headers value is specified, the diagnostic information includes the endpoint method ID (MID), the Runtime Implementation Identifier (RIID), the size of the constant part of the IPC message (in bytes), the contents of the IPC message arena handle, the size of the IPC message arena (in bytes), and the size of the utilized part of the IPC message arena (in bytes). If the dump value is specified, the diagnostic information additionally includes the contents of the constant part and arena of the IPC message in hexadecimal format.

    When using this parameter, you must either specify the selective generation flag for transport code --server or refrain from specifying a selective generation flag for transport code.

  • --ipc-trace-method-filter <METHOD 1>[,<METHOD 2>]...

    Diagnostic information is printed if only the defined interface methods are called. For the METHOD value, you can use the interface method name or the construct <package name>:<interface method name>. The package name and interface method name are specified in the IDL file.

    If this parameter is not specified, diagnostic information is printed when any interface method is called.

    This parameter can be specified multiple times. For example, you can specify all required interface methods in one parameter or specify each required interface method in a separate parameter.

Page top
[Topic nkgenc]

nk-psl-gen-c

The nk-psl-gen-c compiler generates the C-language source code of the Kaspersky Security Module based on the solution security policy description and the IDL, CDL, and EDL descriptions. This code is used by the makekss script.

The nk-psl-gen-c compiler can also generate the C-language source code of solution security policy tests based on solution security policy tests in PAL.

Syntax of the shell command for starting the nk-psl-gen-c compiler:

nk-psl-gen-c {-I|--include-dir} <SYSROOT_INCLUDE_DIR> [{-I|--include-dir} <DIR>]... [{-o|--output} <FILE>] [--out-tests <FILE>] [{-t|--tests} <ARG>] [{-a|--audit} <FILE>] [--enable-preprocessor] [--preprocessor-definition=<VAR_NAME>[=<VAR_VALUE>]]... [--preprocessor-dump-dir <DIR>] [-h|--help] [--version] <INPUT>

Parameters:

  • INPUT

    Path to the top-level file of the solution security policy description. This is normally the security.psl file.

  • {-I|--include-dir} <SYSROOT_INCLUDE_DIR>

    Path to the sysroot-*-kos/include directory from the KasperskyOS SDK.

  • {-I|--include-dir} <DIR>

    These parameters must be used to define the paths to directories containing IDL, CDL, and EDL files pertaining to the solution, and the paths to directories containing auxiliary files from the KasperskyOS SDK (common, toolchain/include).

  • {-o|--output} <FILE>

    Path to the file that will save the source code of the Kaspersky Security Module and (optionally) the source code of solution security policy tests. The path must include existing directories.

  • --out-tests <FILE>

    Path to the file that will save the source code of the solution security policy tests.

  • {-t|--tests} <ARG>

    Defines whether the source code of solution security policy tests must be generated. ARG can take the following values:

    • skip – source code of tests is not generated. This value is used by default if the {-t|--tests} <ARG> parameter is not specified.
    • generate – source code of tests is generated. If the source code of tests is generated, you are advised to use the --out-tests <FILE> parameter. Otherwise, the source code of tests will be saved in the same file containing the source code of the Kaspersky Security Module, which may lead to errors during the build.
  • {-a|--audit} <FILE>

    Path to the file that will save the C-language source code of the audit decoder.

  • --enable-preprocessor

    Enables the Ginger template engine.

  • --preprocessor-definition=<VAR_NAME>[=<VAR_VALUE>]

    These parameters must be used to define the variables that are utilized when expanding Ginger PSL templates. For example, --preprocessor-definition=foo=bar sets the foo variable to bar, and --preprocessor-definition=USE_DYNLD sets the USE_DYNLD variable to TRUE. The USE_DYNLD variable is set to TRUE because variables used when expanding Ginger PSL templates are set to TRUE by default.

  • --preprocessor-dump-dir <DIR>

    Path to the directory where PSL files received from Ginger PSL templates will be stored. These PSL files are needed only to verify what was obtained as a result of expanding Ginger PSL templates, and are not used to generate source code of the Kaspersky Security Module. (When source code of the security module is generated, Ginger PSL templates are expanded in memory irrespective of whether or not the --preprocessor-dump-dir <DIR> parameter is being used.) The names of PSL files are generated based on the absolute paths to Ginger PSL templates. For example, the PSL file named foo!bar!baz.psl corresponds to the Ginger PSL template located at the path /foo/bar/baz.psl.

  • -h|--help

    Prints the Help text.

  • --version

    Prints the version of the nk-psl-gen-c compiler.

Page top
[Topic nkpslgenc]

einit

The einit tool automates the creation of code for the Einit initializing program.

The einit tool receives the solution initialization description (the init.yaml file by default) and EDL, CDL and IDL descriptions, and creates a file containing the source code of the Einit initializing program. Then the Einit program must be built using the C-language cross compiler that is provided in KasperskyOS Community Edition.

Syntax for using the einit tool:

einit -I PATH -o PATH [--help] FILE

Parameters:

  • FILE

    Path to the init.yaml file.

  • -I PATH

    Path to the directory containing the auxiliary files (including EDL, CDL and IDL descriptions) required for generating the initializing program. By default, these files are located in the directory /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include.

  • -o, --out-file PATH

    Path to the created .c file containing the code of the initializing program.

  • -h, --help

    Displays the Help text.

Page top
[Topic einit_tool]

makekss

The makekss script creates the Kaspersky Security Module.

The script calls the nk-psl-gen-c compiler to generate the source code of the security module, then compiles the resulting code by calling the C compiler that is provided in KasperskyOS Community Edition.

The script creates the security module from the solution security policy description.

Syntax for using the makekss script:

makekss --target=ARCH --module=PATH --with-nk="PATH" --with-nktype="TYPE" --with-nkflags="FLAGS" [--output="PATH"][--help][--with-cc="PATH"][--with-cflags="FLAGS"] FILE

Parameters:

  • FILE

    Path to the top-level file of the solution security policy description.

  • --target=ARCH

    Processor architecture for which the build is intended.

  • --module=-lPATH

    Path to the ksm_kss library. This key is passed to the C compiler for linking to this library.

  • --with-nk=PATH

    Path to the nk-psl-gen-c compiler that will be used to generate the source code of the security module. By default, the compiler is located in /opt/KasperskyOS-Community-Edition-<version>/toolchain/bin/nk-psl-gen-c.

  • --with-nktype="TYPE"

    Indicates the type of NK compiler that will be used. To use the nk-psl-gen-c compiler, indicate the psl type.

  • --with-nkflags="FLAGS"

    Parameters used when calling the nk-psl-gen-c compiler.

    The nk-psl-gen-c compiler will require access to all EDL, CDL and IDL descriptions. To enable the nk-psl-gen-c compiler to find these descriptions, you need to pass the paths to these descriptions in the --with-nkflags parameter by using the -I switch of the nk-psl-gen-c compiler.

  • --output=PATH

    Path to the created security module file.

  • --with-cc=PATH

    Path to the C compiler that will be used to build the security module. The compiler provided in KasperskyOS Community Edition is used by default.

  • --with-cflags=FLAGS

    Parameters used when calling the C compiler.

  • -h, --help

    Displays the Help text.

Page top
[Topic makekss]

makeimg

The makeimg script creates the final boot image of the KasperskyOS-based solution with all executable files of programs and the Kaspersky Security Module.

The script receives a list of files, including the executable files of all applications that need to be added to ROMFS of the loaded image, and creates the following files:

  • Solution image
  • Solution image without character tables (.stripped)
  • Solution image with debug character tables (.dbg.syms)

Syntax for using the makeimg script:

makeimg --target=ARCH --sys-root=PATH --with-toolchain=PATH --ldscript=PATH --img-src=PATH --img-dst=PATH --with-init=PATH [--with-extra-asflags=FLAGS][--with-extra-ldflags=FLAGS][--help] FILES

Parameters:

  • FILES

    List of paths to files, including the executable files of all applications that need to be added to ROMFS.

    The security module (ksm.module) must be explicitly specified, or else it will not be included in the solution image. The Einit application does not need to be indicated because it will be automatically included in the solution image.

  • --target=ARCH

    Architecture for which the build is intended.

  • --sys-root=PATH

    Path to the root directory sysroot. By default, this directory is located in /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/.

  • --with-toolchain=PATH

    Path to the set of auxiliary tools required for the solution build. By default, these tools are located in /opt/KasperskyOS-Community-Edition-<version>/toolchain/.

  • --ldscript=PATH

    Path to the linker script required for the solution build. By default, this script is located in /opt/KasperskyOS-Community-Edition-<version>/libexec/aarch64-kos/.

  • --img-src=PATH

    Path to the precompiled KasperskyOS kernel. By default, the kernel is located in /opt/KasperskyOS-Community-Edition-<version>/libexec/aarch64-kos/.

  • --img-dst=PATH

    Path to the created image file.

  • --with-init=PATH

    Path to the executable file of the Einit initializing program.

  • --with-extra-asflags=FLAGS

    Additional flags for the AS Assembler.

  • --with-extra-ldflags=FLAGS

    Additional flags for the LD Linker.

  • -h, --help

    Displays the Help text.

Page top
[Topic makeimg]

Cross compilers

The toolchain provided in the KasperskyOS SDK includes one or more Clang compilers and a rustc compiler. The toolchain/bin directory contains the following files:

  • Executable files of compilers (for example, clang-17 or rustc)
  • Executable files of linkers (for example, aarch64-kos-ld)
  • Executable files of assemblers (for example, aarch64-kos-as)
  • Bash scripts for the Clang compiler (for example, aarch64-kos-clang, aarch64-kos-clang++)

Linker operation specifics

When building the executable file of an application, by default the linker links the following libraries in the specified order:

  1. libc is the standard C library.
  2. libm is the library that implements the mathematical functions of the standard C language library.
  3. libvfs_stubs is the library that contains stubs of I/O functions (for example, open, socket, read, write).
  4. libkos is the library for accessing the KasperskyOS core endpoints.
  5. libenv is the library of the subsystem for configuring the environment of applications (environment variables, arguments of the main function, and custom configurations).
  6. libsrvtransport-u is the library that supports IPC between processes and the kernel.
Page top
[Topic crosscompliers]

Using dynamic libraries

Dynamic libraries (*.so files) can be used in a KasperskyOS-based solution. Compared to static libraries (*.a files), dynamic libraries provide the following advantages:

  • Efficient use of RAM.

    Multiple processes can use the same instance of a dynamic library. Also, an executable file and dynamic libraries in one process can use the same instance of a dynamic library.

    Dynamic libraries can be loaded into memory and unloaded from memory on the initiative of the programs that use them.

  • Convenient software updates.

    A dynamic library update is applied to all executable files and dynamic libraries dependent on this dynamic library without having to rebuild them.

  • Capability to implement a mechanism for plug-ins.

    Plug-ins for solution components consist of dynamic libraries.

  • Shared use of code and data.

    One instance of a dynamic library can be concurrently used by multiple processes, and by an executable file and dynamic libraries in one process. This enables centralized management of multi-access to resources or storage of shared data, for example.

Dynamic libraries are provided in KasperskyOS Community Edition, and can also be created by a KasperskyOS-based solution developer. Normal operation of third-party dynamic libraries cannot be guaranteed.

Due to current technical limitations, libc.so and libpthread.so cannot be used in a KasperskyOS-based solution.

In this section

Prerequisites for using dynamic libraries

Life cycle of a dynamic library

Including the BlobContainer system program in a KasperskyOS-based solution

Building dynamic libraries

Adding dynamic libraries to a KasperskyOS-based solution

Page top
[Topic shared_libraries]

Prerequisites for using dynamic libraries

To use dynamic libraries in a KasperskyOS-based solution, the following conditions must be met:

  1. Processes that use dynamic libraries must have access to the file systems in which the files of the dynamic libraries are stored. Access to file systems is provided by VFS, which is a separate process. The dynamic libraries must not be used by VFS or other software that is used by VFS to work with storage (such as a storage driver).
  2. The system program BlobContainer must be included in the solution.
  3. Executable files that use dynamic libraries must be built with the -rdynamic flag (with dynamic linking).

    The CMake initialize_platform() command causes this flag to be used automatically for building all executable files defined via CMake add_executable() commands.

If the CMake command initialize_platform(FORCE_STATIC) is specified in the CMakeLists.txt root file, the toolchain performs static linking of executable files.

The CMake project_static_executable_header_default() command affects the build of executable files defined via subsequent CMake add_executable() commands in one CMakeLists.txt file. The toolchain performs static linking of these executable files.

The CMake platform_target_force_static() command affects the build of one executable file defined via the CMake add_executable() command. The toolchain performs static linking of this executable file.

The executable file that is built with the -rdynamic flag is linked to a static library if a dynamic library is not found. For example, if the CMake target_link_libraries(client -lm) command is being used, the executable file of the client program is linked to the static library libm.a if the dynamic library libm.so is not found.

Page top
[Topic shared_libraries_use_conditions]

Life cycle of a dynamic library

The life cycle of a dynamic library includes the following phases:

  1. Loading into memory.

    A dynamic library linked to an executable file is loaded into shared memory upon startup of the process that was created based on this executable file. A process can also load a dynamic library into shared memory by calling the dlopen() function of the POSIX interface. A dynamic library may be linked to other dynamic libraries, so an executable file depends not only on the dynamic library directly linked to it, but also depends on the entire dependency graph of this library. A dynamic library is loaded into shared memory together with all of the dynamic libraries that it depends on.

    One instance of a dynamic library is loaded into shared memory regardless of how many processes are using this library. (More specifically, only the part of the dynamic library that includes code and read-only data is loaded into shared memory. The other part of the dynamic library is loaded into the memory of each process that uses this library.) A dynamic library on which several other dynamic libraries depend is loaded into shared memory in a single instance.

    If a list of dynamic libraries is defined through the LD_PRELOAD environment variable, these dynamic libraries will be loaded into shared memory even if the executable file is not dependent on them. (List items must be absolute or relative paths to dynamic libraries separated by a colon, for example: LD_PRELOAD=libmalloc.so:libfree.so:/usr/somepath/lib/libfoo.so.) The functions that are exported by the dynamic libraries specified in LD_PRELOAD replace the identically named functions that are exported by other dynamic libraries. This can be used for debugging purposes if you need to replace functions imported from dynamic libraries.

    The dynamic library loader searches for dynamic libraries in the following order:

    1. Absolute paths defined through the LD_LIBRARY_PATH environment variable.

      Paths must be separated by a colon, for example: LD_LIBRARY_PATH=/usr/lib:/home/user/lib.

    2. Absolute paths defined in the DT_RUNPATH or DT_RPATH field of the .dynamic section of executable files and dynamic libraries.

      Linking of executable files and dynamic libraries may include defined paths that the dynamic library loader will search. (For example, this can be done through the INSTALL_RPATH property in the CMake command set_target_properties().) Paths used to search for dynamic libraries are stored in the DT_RUNPATH or DT_RPATH field of the .dynamic section. This field may be in executable files linked to dynamic libraries and in dynamic libraries linked to other dynamic libraries.

    3. Path /lib.

    The dynamic library loader searches in this same order if a relative path to a dynamic library is specified in the filename parameter of the dlopen() function or in the LD_PRELOAD environment variable. If the absolute path is specified, the loader puts the dynamic library into shared memory without performing a search.

  2. Use by a process (or processes).
  3. Unloading from memory.

    A dynamic library is unloaded from shared memory when all processes using this library have terminated or called the dlclose() function of the POSIX interface. A dynamic library linked to an executable file cannot be unloaded from shared memory until termination of the process that was created based on this executable file. A dynamic library that is linked to other dynamic libraries is unloaded from shared memory after all libraries that depend on it are unloaded.

Page top
[Topic shared_libraries_lifecycle]

Including the BlobContainer system program in a KasperskyOS-based solution

If a solution uses dynamic libraries, the system program BlobContainer must be included in this solution (this system program is provided by the executable file sysroot-aarch64-kos/bin/BlobContainer from KasperskyOS Community Edition).

The BlobContainer program can be included in a solution either automatically or manually. This program is automatically included in a solution by running the CMake commands build_kos_qemu_image() and build_kos_hw_image() if at least one executable file in the solution is linked to a dynamic library. (To disable automatic inclusion of the BlobContainer program in a solution, you need to add the NO_AUTO_BLOB_CONTAINER value to the parameters of the CMake commands build_kos_qemu_image() and build_kos_hw_image().) If programs in a solution work with dynamic libraries using only a POSIX interface (the dlopen(), dlsym(), dlerror(), and dlclose() functions), the BlobContainer program needs to be manually included in the solution.

The VFS working with files of dynamic libraries must be a separate process. You need to create an IPC channel from the process of the BlobContainer program to the VFS process.

You must create IPC channels from the processes using dynamic libraries to the process of the BlobContainer program. These IPC channels can be created statically or dynamically. If a statically created IPC channel is not available, the client and server parts of the BlobContainer program attempt to dynamically create an IPC channel using the name server.

If the BlobContainer program is automatically included in a solution, the @INIT_EXTERNAL_ENTITIES@, @INIT_<program name>_ENTITY_CONNECTIONS@ and @INIT_<program name>_ENTITY_CONNECTIONS+@ macros used in the init.yaml.in file automatically create within the init description dictionaries of IPC channels that enable static creation of IPC channels from processes created based on executable files linked to dynamic libraries to the process of the BlobContainer program. (The process of the BlobContainer program receives the name kl.bc.BlobContainer, while the IPC channels receive the name kl.BlobContainer.) However, dictionaries of IPC channels to the BlobContainer program process are not automatically created for processes that work with dynamic libraries using only a POSIX interface. To ensure that the required IPC channels are statically created, these dictionaries must be manually created (these IPC channels must have the name kl.BlobContainer).

If the BlobContainer program is manually included in the solution and you need to statically create IPC channels from processes using dynamic libraries to the BlobContainer program process, you must manually create dictionaries of the required IPC channels in the init description. By default, the IPC channel to the BlobContainer program process has the name kl.BlobContainer. However, this name can be changed through the environment variable _BLOB_CONTAINER_BACKEND. This variable must be defined for the BlobContainer process and for processes using dynamic libraries.

The environment variable _BLOB_CONTAINER_BACKEND defines not only the name of statically created IPC channels to the BlobContainer program process, but also defines the endpoint name that is published on the name server and used to dynamically create IPC channels to the BlobContainer program process. This is convenient when multiple processes of the BlobContainer program are running simultaneously (for example, to isolate its own dynamic libraries from external ones), and when different processes using dynamic libraries must interact over IPC with different processes of the BlobContainer program. In this case, you need to define different values for the environment variable _BLOB_CONTAINER_BACKEND for different processes of the BlobContainer program, and then use these values for the environment variable _BLOB_CONTAINER_BACKEND for processes using dynamic libraries. The specific value must be selected depending on the specific process of the BlobContainer program that requires the dynamically created IPC channel.

Example use of the environment variable _BLOB_CONTAINER_BACKEND in the init.yaml.in file:

entities: - name: example.BlobContainer path: example_blob_container args: - "-v" env: _BLOB_CONTAINER_BACKEND: kl.custombc @INIT_example_blob_container_ENTITY_CONNECTIONS@ - name: client.Client path: client env: _BLOB_CONTAINER_BACKEND: kl.custombc @INIT_client_ENTITY_CONNECTIONS@ @INIT_EXTERNAL_ENTITIES@

Example use of the environment variable _BLOB_CONTAINER_BACKEND in CMake commands:

set_target_properties (ExecMgrEntity PROPERTIES EXTRA_ENV " _BLOB_CONTAINER_BACKEND: kl.custombc") set_target_properties (dump_collector::entity PROPERTIES EXTRA_ENV " _BLOB_CONTAINER_BACKEND: kl.custombc")
Page top
[Topic shared_libraries_blobcontainer]

Building dynamic libraries

To build a dynamic library, you need to use the following CMake command:

add_library(<build target name> SHARED <path to a file of the library source code>…)

You can also build a dynamic library by using the following CMake command:

add_library(<build target name> <path to a file of the library source code>…)

The cmake shell command must be called with the -D BUILD_SHARED_LIBS=YES parameter. (If the cmake shell command is called without the -D BUILD_SHARED_LIBS=YES parameter, a static library will be built.)

Example:

#!/bin/bash … cmake -G "Unix Makefiles" \ -D CMAKE_BUILD_TYPE:STRING=Debug \ -D CMAKE_TOOLCHAIN_FILE=$SDK_PREFIX/toolchain/share/toolchain-$TARGET.cmake \ -D BUILD_SHARED_LIBS=YES \ -B build \ && cmake --build build --target kos-image

By default, the library file name matches the name of the build target defined via the parameter of the CMake add_library() command. The library file name can be changed by using the CMake set_target_properties() command. This can be done to make the library file name identical for its dynamic and static variants.

Example:

# Build the static library add_library(somelib_static STATIC src/somesrc.cpp) set_target_properties(somelib_static PROPERTIES OUTPUT_NAME "somelib") # Build the dynamic library add_library(somelib_shared SHARED src/somesrc.cpp) set_target_properties(somelib_shared PROPERTIES OUTPUT_NAME "somelib")

A dynamic library can be linked to other static and dynamic libraries by using the CMake target_link_libraries() command. In this case, static libraries must be built with the -fPIC flag. This flag is applied when building a static library if the following CMake command is used:

set_property(TARGET <build target name>… PROPERTY POSITION_INDEPENDENT_CODE ON)
Page top
[Topic shared_libraries_building]

Adding dynamic libraries to a KasperskyOS-based solution

There are two ways to add dynamic libraries to a KasperskyOS-based solution: by either automatic or manual search for the dynamic libraries required by the solution programs.

Automatic search for dynamic libraries

Use the PACK_DEPS_COPY_ONLY ON, PACK_DEPS_LIBS_PATH, and PACK_DEPS_COPY_TARGET parameters in the CMake commands build_kos_qemu_image() and build_kos_hw_image().

Dynamic libraries that are loaded into memory by calling the dlopen() function of the POSIX interface will not be found by an automatic search.

Example 1:

# This example creates a solution image for the hardware platform. # This solution image must include the storage drive image containing the dynamic # libraries. # Setting values of variables set (IMAGE_FS ${CMAKE_BINARY_DIR}/hdd) set (LIBS_PATH "${IMAGE_FS}/lib") set (DISK_IMG ramdisk0.img) if (blob_container_ENTITY_FOUND) # Configure the BlobContainer program set_target_properties (${blob_container_ENTITY} PROPERTIES DEPENDS_ON_ENTITY ${precompiled_vfsVfsRamFs} EXTRA_ENV " VFS_FILESYSTEM_BACKEND: client:kl.VfsRamFs") endif () # Create a storage drive image containing the dynamic libraries # The storage drive image will be created after completing the copylibs target, # which is created by the Cmake command build_kos_hw_image(). add_custom_command (OUTPUT ${DISK_IMG} DEPENDS copylibs COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${IMAGE_FS} -s 64 -f ext4 -img ${DISK_IMG} COMMENT "Creating disk image '${DISK_IMG}' from files in '${IMAGE_FS}' ...") # Create a solution image for the hardware platform # The copylibs target indicates that the automatically found dynamic # libraries will be copied to the directory ${LIBS_PATH}. This directory will be included # in the storage drive image. The value ${DISK_IMG} is specified in the # IMAGE_FILES parameter, so the storage drive image will be created before the solution image is created, # and it will be included in the solution image. build_kos_hw_image (kos-image ... IMAGE_FILES ${ENTITIES_LIST} ${DISK_IMG} PACK_DEPS_COPY_ONLY ON PACK_DEPS_LIBS_PATH ${LIBS_PATH} PACK_DEPS_COPY_TARGET copylibs)

Example 2:

# This example to be run in QEMU creates a solution image and # a separate storage drive image containing the dynamic libraries, # and this example to be run on the hardware platform creates an SD card image # to which the solution image and dynamic libraries are added. # Set the values of variables used during the build # for the hardware platform set (HW_IMAGE_FS "${CMAKE_BINARY_DIR}/hdd_hw") set (HW_LIBS_PATH "${HW_IMAGE_FS}/lib") # Set the values of variables used during the build # for QEMU set (QEMU_IMAGE_FS "${CMAKE_BINARY_DIR}/hdd_qemu") set (QEMU_LIBS_PATH "${QEMU_IMAGE_FS}/lib") set (QEMU_DISK_IMAGE sdcard0.img) set (QEMU_FLAGS "-nic none -m 2048 -drive file=${QEMU_DISK_IMAGE},if=sd,format=raw") set (QEMU_DEPENDENCIES ${QEMU_DISK_IMAGE}) if (blob_container_ENTITY_FOUND) # Configure the BlobContainer program set_target_properties (${blob_container_ENTITY} PROPERTIES DEPENDS_ON_ENTITY ${precompiled_vfsVfsSdCardFs} EXTRA_ENV " VFS_FILESYSTEM_BACKEND: client:kl.VfsSdCardFs") # Create a storage drive image containing the dynamic libraries for QEMU add_custom_command (${QEMU_DISK_IMAGE} DEPENDS copylibs_qemu COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${QEMU_IMAGE_FS} -s 64 -f fat32 -img ${QEMU_DISK_IMAGE} COMMENT "Creating disk image '${QEMU_DISK_IMAGE}' from files in '${QEMU_IMAGE_FS}' ...") # Create a solution image for QEMU # The copylibs_qemu target indicates that the automatically found dynamic # libraries will be copied to the directory ${QEMU_LIBS_PATH}. This directory will be included # in the storage drive image containing the dynamic libraries for QEMU. The value ${QEMU_FLAGS} # contains the -drive file=${QEMU_DISK_IMAGE},if=sd,format=raw parameters, which # are required for QEMU use of the storage drive image containing the dynamic # libraries. The value ${QEMU_DEPENDENCIES} is required to make sure that # the storage drive image containing the dynamic libraries is created before creation of the # solution image for QEMU. (The solution image will not include the storage drive image containing the # dynamic libraries, but you must add this target dependency # to create the storage drive image containing the dynamic libraries.) build_kos_qemu_image (kos-qemu-image ... QEMU_FLAGS "${QEMU_FLAGS}" QEMU_DEPENDENCIES "${QEMU_DEPENDENCIES}" PACK_DEPS_COPY_ONLY ON PACK_DEPS_LIBS_PATH "${QEMU_LIBS_PATH}" PACK_DEPS_COPY_TARGET copylibs_qemu IMAGE_FILES ${ENTITIES}) # Create a solution image for the hardware platform # The copylibs_hw target indicates that the automatically found dynamic # libraries will be copied to the directory ${HW_LIBS_PATH}. This directory will be included # in the SD card image that is created by the CMake command build_sd_image(). build_kos_hw_image (kos-image ... PACK_DEPS_COPY_ONLY ON PACK_DEPS_LIBS_PATH "${HW_LIBS_PATH}" PACK_DEPS_COPY_TARGET copylibs_hw IMAGE_FILES ${ENTITIES}) # The solution image for the hardware platform will be created after # the automatically found dynamic libraries are copied to the directory ${HW_LIBS_PATH}. # (The solution image will not include dynamic libraries, but you must add # this target dependency to complete copying prior to creation of # the SD card image.) add_dependencies (kos-image copylibs_hw) # Create the SD card image # The SD card image will be created based on the directory ${HW_IMAGE_FS}, # which includes the solution for the hardware platform and the directory # containing the dynamic libraries. The SD card image will be created # after creation of the solution image for the hardware platform. build_sd_image (sd-image KOS_IMAGE_TARGET kos-image IMAGE_FS ${HW_IMAGE_FS})

Manual search for dynamic libraries

You need to independently search for dynamic libraries required by the solution programs. This way, even dynamic libraries that were loaded into memory by calling the dlopen() function of the POSIX interface can be added to a solution.

Example 1:

# This example creates a solution image that includes # the libm.so dynamic library in addition to the executable files of programs. # Configure the VFS program set (VFS_SDCARD_ARGS "\ - -l - nodev /tmp ramfs 0 - -l - devfs /dev devfs 0 - -l - romfs /lib romfs ro") set_target_properties (${precompiled_vfsVfsSdCardFs} PROPERTIES EXTRA_ARGS ${VFS_SDCARD_ARGS}) if (blob_container_ENTITY_FOUND) # Configure the BlobContainer program set_target_properties (${blob_container_ENTITY} PROPERTIES DEPENDS_ON_ENTITY ${precompiled_vfsVfsSdCardFs} EXTRA_ENV " VFS_FILESYSTEM_BACKEND: client:kl.VfsSdCardFs") endif () if(PLATFORM_SUPPORTS_DYNAMIC_LINKING) # Get the full path to the libm.so dynamic library find_file(LIBM_SO_FILE libm.so PATH_SUFFIXES lib REQUIRED) set(EXTRA_FILES ${LIBM_SO_FILE}) else() set(EXTRA_FILES) endif() # Create a solution image for the hardware platform # The libm.so dynamic library will be added to the # solution image because the value ${EXTRA_FILES} # specified in the IMAGE_FILES parameter contains the full # path to this library. build_kos_hw_image(kos-image ... IMAGE_FILES ${ENTITIES} ${EXTRA_FILES})

Example 2:

# This example to be run in QEMU creates a solution image and # a separate storage drive image containing the libm.so dynamic library. # Setting values of variables set (QEMU_FLAGS "-nic none -m 2048") set (QEMU_DEPENDENCIES) if (PLATFORM_SUPPORTS_DYNAMIC_LINKING) # Setting values of variables set (IMAGE_FS "${CMAKE_BINARY_DIR}/hdd") set (LIBS_PATH "${IMAGE_FS}/lib") set (QEMU_DISK_IMAGE sdcard0.img) string (APPEND QEMU_FLAGS "-drive file=${QEMU_DISK_IMAGE},if=sd,format=raw") set (QEMU_DEPENDENCIES ${QEMU_DISK_IMAGE}) # Configure the BlobContainer program set_target_properties (${blob_container_ENTITY} PROPERTIES DEPENDS_ON_ENTITY ${precompiled_vfsVfsSdCardFs} EXTRA_ENV " VFS_FILESYSTEM_BACKEND: client:kl.VfsSdCardFs") # Get the full path to the libm.so dynamic library find_file (LIBM_SO_FILE libm.so PATH_SUFFIXES lib REQUIRED) # Create a storage drive image containing the libm.so dynamic library add_custom_command (OUTPUT ${QEMU_DISK_IMAGE} COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBS_PATH} COMMAND ${CMAKE_COMMAND} -E copy ${LIBM_SO_FILE} ${LIBS_PATH} COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${IMAGE_FS} -s 64 -f fat32 -img ${QEMU_DISK_IMAGE} COMMENT "Creating disk image '${QEMU_DISK_IMAGE}' from files in '${IMAGE_FS}' ...") endif () # Create a solution image for QEMU # The value ${QEMU_FLAGS} contains the -drive file=${QEMU_DISK_IMAGE},if=sd,format=raw parameters, # which are required for QEMU use of the storage drive image containing the # libm.so dynamic library. The value ${QEMU_DEPENDENCIES} is required to make sure that # the storage drive image containing the libm.so dynamic library is created before creation of the # solution image for QEMU. (The solution image will not include the storage drive image containing the # libm.so dynamic library, but you must add this target dependency # to create the storage drive image containing the libm.so dynamic library.) build_kos_qemu_image (kos-qemu-image ... QEMU_FLAGS "${QEMU_FLAGS}" QEMU_DEPENDENCIES "${QEMU_DEPENDENCIES}" IMAGE_FILES ${ENTITIES})
Page top
[Topic shared_libraries_adding_to_solution]