KasperskyOS Community Edition 1.1

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 to simplify the use of CMake scripts:

  • In the project root, create a CMakeLists.txt boot file containing the general build instructions for the entire solution.
  • The source code of each program being developed should be placed into a separate directory within the src subdirectory.
  • Create CMakeLists.txt files for building each application in the corresponding directories.
  • To generate the source code of the Einit program, you should create a separate einit directory containing the src subdirectory in which you should put the init.yaml.in and security.psl.in templates.

    Any other files that need to be included in the solution image can also be put into this directory.

  • Create a CMakeLists.txt file for building the Einit program in the einit directory.
  • The files of EDL, CDL and IDL descriptions should be put into the resources directory in the project root.
  • [Optional] Create a cross-build.sh build script containing the commands to start generating build files (cmake command), to build the solution (make command), and to start the solution.

Example structure of project directories

example$ tree

.

├── CMakeLists.txt

├── cross-build.sh

├── hello

│ ├── CMakeLists.txt

│ ├── src

│ │ ├── hello.c

├── einit

│ ├── CMakeLists.txt

│ ├── src

│ │ ├── init.yaml.in

│ │ ├── security.psl.in

│ │ ├── fstab

├── resources

│ ├── Hello.idl

│ ├── Hello.cdl

│ ├── Hello.edl

Building a project

To prepare for a build using the CMake build system, the following is required:

  1. Prepare a CMakeLists.txt boot file containing the general build instructions for the entire solution.
  2. Prepare CMakeLists.txt files for each application to be built.
  3. Prepare a CMakeLists.txt file for the Einit program.
  4. Prepare the init.yaml.in and security.psl.in templates.

To perform cross-compilation using the CMake build automation system, the following is required:

  1. Create a subdirectory for the build.

    BUILD=$PWD/.build

    mkdir -p $BUILD && cd $BUILD

  2. Prior to starting generation of build scripts (cmake command), set the following values for environment variables:
    • export LANG=C
    • export PKG_CONFIG=""
    • export SDK_PREFIX="/opt/KasperskyOS-Community-Edition-<version>"
    • export PATH="$SDK_PREFIX/toolchain/bin:$PATH"
    • export INSTALL_PREFIX=$BUILD/../install
    • export TARGET="aarch64-kos"
  3. When starting generation of build scripts (cmake command), specify the following:
    • -G "Unix Makefiles" parameter
    • Path to the file with the build system extension (toolchain.cmake) in the CMAKE_TOOLCHAIN_FILE variable.

      The file with the build system extension is located in the following directory: /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/toolchain-aarch64-kos.cmake

    • Value of the CMAKE_BUILD_TYPE:STRING=Debug variable
    • Value of the CMAKE_INSTALL_PREFIX:STRING=$INSTALL_PREFIX variable
    • Path to the CMakeLists.txt boot file
  4. When starting the build (make command), specify one of the build targets.

    The target name must match the build target name passed to the solution build command in the CMakeLists.txt file for the Einit program.

Example cross-build.sh build script

cross-build.sh

#!/bin/bash

# Create a subdirectory for the build

BUILD=$PWD/.build

mkdir -p $BUILD && cd $BUILD

# Set the values of environment variables

export LANG=C

export PKG_CONFIG=""

export SDK_PREFIX="/opt/KasperskyOS-Community-Edition-<version>"

export PATH="$SDK_PREFIX/toolchain/bin:$PATH"

export INSTALL_PREFIX=$BUILD/../install

export TARGET="aarch64-kos"

# Start generating files for the build. The current directory is $BUILD,

# so the CMakeLists.txt boot file is in the parent directory

cmake -G "Unix Makefiles" \

-D CMAKE_BUILD_TYPE:STRING=Debug \

-D CMAKE_INSTALL_PREFIX:STRING=$BUILD/../.install \

-D CMAKE_TOOLCHAIN_FILE=$SDK_PREFIX/toolchain/share/toolchain-$TARGET.cmake \

../

# Start the build. Include the VERBOSE flag for Make and redirect the output to the build.log file

VERBOSE=1 make kos-qemu-image 2>&1 | tee build.log

# Run the built solution image in QEMU.

# -kernel $BUILD/einit/kos-qemu-image path to the built kernel image

$SDK_PREFIX/toolchain/bin/qemu-system-aarch64 \

-m 1024 \

-cpu core2duo \

-serial stdio \

-kernel $BUILD/einit/kos-qemu-image

In this section

CMakeLists.txt boot 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 boot file

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

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

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

    For a KasperskyOS-based solution build, CMake version 3.12 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_11: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-aarch64-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 boot file

CMakeLists.txt

cmake_minimum_required(VERSION 3.12)

project (example)

# Initializes the CMake library for the KasperskyOS SDK.

include (platform)

initialize_platform ()

project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")

# Add package importing components for working with Virtual File System.

# Components are imported from the following directory: /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/vfs/vfs-config.cmake

find_package (vfs REQUIRED COMPONENTS ENTITY CLIENT_LIB)

include_directories (${vfs_INCLUDE})

# Add a package importing components for building an audit program and

# connecting to it.

find_package (klog REQUIRED)

include_directories (${klog_INCLUDE})

# Build the Einit initializing program

add_subdirectory (einit)

# Build the hello application

add_subdirectory (hello)

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_11: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_LIB} 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-aarch64-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.

    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.

    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)

# Tools for working with the NK compiler.

include (platform/nk)

# Set compile flags.

project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")

# Define the name of the project that includes the program.

set (LOCAL_MODULE_NAME "example")

# Define the application name.

set (ENTITY_NAME "Hello")

# Please note the contents of the init.yaml.in and security.psl.in templates

# They define program names as ${LOCAL_MODULE_NAME}.${ENTITY_NAME}

# Define the targets that will be used to create the generated files of the program.

set (ENTITY_IDL_TARGET ${ENTITY_NAME}_idl)

set (ENTITY_CDL_TARGET ${ENTITY_NAME}_cdl)

set (ENTITY_EDL_TARGET ${ENTITY_NAME}_edl)

# Define the name of the target that will be used to build the program.

set (APP_TARGET ${ENTITY_NAME}_app)

# Add the idl.h file build target.

nk_build_idl_files (${ENTITY_IDL_TARGET}

NK_MODULE ${LOCAL_MODULE_NAME}

IDL "resources/Hello.idl"

)

# Add the cdl.h file build target.

nk_build_cdl_files (${ENTITY_CDL_TARGET}

IDL_TARGET ${ENTITY_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 ( ${ENTITY_NAME}

PREFIX ${LOCAL_MODULE_NAME}

)

# Add the edl.h file build target.

nk_build_edl_files (${ENTITY_EDL_TARGET}

NK_MODULE ${LOCAL_MODULE_NAME}

EDL ${EDL_FILE}

)

# Define the target for the program build.

add_executable (${APP_TARGET} "src/hello.c")

# The program name in init.yaml and security.psl must match the name of the executable file

set_target_properties (${APP_TARGET} PROPERTIES OUTPUT_NAME ${ENTITY_NAME})

# Libraries that are linked to the program during the build

target_link_libraries ( ${APP_TARGET}

PUBLIC ${vfs_CLIENT_LIB} # The program uses file I/O

# and must be connected as a client to VFS

)

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_11: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-aarch64-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.

    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} 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.

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} 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 both commands for building the solution image:
    • build_kos_hw_image() creates the build target that can then be used to build the image for the hardware platform using make.
    • build_kos_qemu_image() creates the build target that can then be used to build the image for running in QEMU using make.

Example CMakeLists.txt file for building the Einit program

CMakeLists.txt

project (einit)

# Connect the library containing solution image build scripts.

include (platform/image)

# Set compile flags.

project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")

# 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 variable ${blkdev_ENTITY}_REPLACEMENT

# For more information about exported variables and properties of the VFS program,

# see /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/vfs/vfs-config.cmake

# find_package(ata)

# set_target_properties (${vfs_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} 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}

Hello_app

)

# Solution image for target hardware platform.

# Create the build target named kos-image that can then be used

# to build the image for the hardware platform using make kos-image.

build_kos_hw_image (kos-image

EINIT_ENTITY EinitHw

CONNECTIONS_CFG "src/init.yaml.in" # template of the init.yaml file

SECURITY_PSL "src/security.psl.in" # template of the security.psl file

IMAGE_FILES ${ENTITIES}

)

# Solution image for the QEMU hardware platform.

# Create the build target named kos-qemu-image that can then be used

# to build a QEMU image using make kos-qemu-image.

build_kos_qemu_image (kos-qemu-image

EINIT_ENTITY EinitQemu

CONNECTIONS_CFG "src/init.yaml.in"

SECURITY_PSL "src/security.psl.in"

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-aarch64-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:

  • Describing the global parameters of a solution security policy
  • Including PSL files
  • Including EDL files of application software
  • Creating security model objects
  • Binding methods of security models to security events
  • Describing 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]