Managing processes (low-level API task_api.h)
The API is defined in the header file sysroot-*-kos/include/coresrv/task/task_api.h
from the KasperskyOS SDK.
Main capabilities of the API:
- Create, start, and terminate processes.
- Handle exceptions.
- Get information about processes, including information about the reasons for their termination.
- Define priorities and scheduler classes for initial threads of processes.
Information about API functions is provided in the table below.
The libkos
library also provides a high-level API for process management. This API is defined in the header file sysroot-*-kos/include/kos/task.h
from the KasperskyOS SDK. It is recommended to use this specific API. The low-level API should be used only if the high-level API does not have sufficient capabilities.
Creating and starting processes
To create a process, call the KnTaskCreate()
or KnTaskCreateEx()
function. These functions create an "empty" process, which is a process in whose memory the ELF image of the program is not loaded. Before starting this process, complete the following steps:
- Create a seed value by calling the
KosRandomGenerate()
function, which is declared in the header filesysroot-*-kos/include/kos/random/random_api.h
from the KasperskyOS SDK.This step is required for completion of the next step.
- Define the seed value by calling the
KnTaskReseedAslr()
function.This step is required for address space layout randomization. Address Space Layout Randomization (ASLR) is the use of random addresses for the location of data structures (ELF image, dynamic libraries, stack and heap) in process memory to make it harder to exploit vulnerabilities associated with a conventional process address space structure that is known by a hacker in advance.
The
KnTaskReseedAslr()
function defines the seed value of the random number generator that is used to automatically select the base address of an allocated virtual memory region in functions such asKnVmAllocate()
,KnPmmMdlMap()
,KnIoDmaMap()
, andKnTaskVmReserve()
. The stack and heap are created in the process and dynamic libraries are loaded into the process memory by the operating system using theKnVmAllocate()
function. Theaddr
parameter is set to zero so that the address of the allocated virtual memory region is selected automatically (as a random value). - Wipe the seed value created at step 1 from memory.
This step is required for security purposes. To complete this step, use the
RtlRandomMemSanitize()
function, which is declared in the header filesysroot-*-kos/include/rtl/random.h
from the KasperskyOS SDK. - Load ELF image segments into process memory by using the
KnTaskLoadSeg()
function.In the
loadAddr
field of theseg
parameter, specify the load address of the ELF image segment. To ensure ASLR support (as a supplement to step 2), the load address of the ELF image segment specified in the ELF file must be increased by the ELF image load offset. The ELF image load offset must be a random value. TheKnElfCreateVmSegEx()
function declared in the header filesysroot-*-kos/include/coresrv/elf/elf_api.h
from the KasperskyOS SDK generates the random offset for loading the ELF image and calculates the load addresses of ELF image segments according to this offset.As a result of this step, MDL buffers that contain ELF image segments will be mapped to virtual memory of the process.
- [Optional] Load the symbol table
.symtab
and string table.strtab
into process memory by calling theKnTaskLoadElfSyms()
function.The load addresses of ELF image segments containing the symbol table
.symtab
and string table.strtab
must be calculated just like the load addresses of other ELF image segments. This calculation is performed by theKnElfCreateVmSegEx()
function declared in the header filesysroot-*-kos/include/coresrv/elf/elf_api.h
from the KasperskyOS SDK.The kernel uses the symbol table
.symtab
and string table.strtab
to get the names of functions for generating stack backtrace data (call stack information). - Define the program entry point and the ELF image load offset by calling the
KnTaskSetInitialState()
function.The program entry point is the sum of the address specified in the
e_entry
field of the ELF image header and the ELF image load offset. TheKnElfCreateVmSegEx()
function declared in the header filesysroot-*-kos/include/coresrv/elf/elf_api.h
from the KasperskyOS SDK generates a random offset for loading the ELF image and calculates the address of the program entry point according to this offset. - [Optional] Load the ELF image header into process memory by calling the
KnTaskSetElfHdr()
function.This step must be completed if data from the ELF image header must be available in the created process.
The handle of a process can be transferred to another process via IPC.
By default, the initial thread of a process is a standard thread whose priority can take values ranging from 0 to 15. (For details about thread scheduler classes, see Managing threads (low-level API thread_api.h).) To change the scheduler class and/or priority of the initial thread of a process, call the KnTaskSetInitialPolicy()
function. To change the priority of the initial thread of a process, call the KnTaskSetInitialThreadPriority()
function. The KnTaskSetInitialPolicy()
and KnTaskSetInitialThreadPriority()
functions can be used after the program entry point is defined. These functions can also be used after starting the process.
To start the process, call the KnTaskResume()
function. A running process cannot be stopped.
Before a process is started, it receives data from its parent process via a static connection page. A static connection page (SCP) is a set of structures containing data for statically creating IPC channels, startup parameters, and environment variables of a program. A parent process writes data to the SCP of a child process by calling the KnTaskSetEnv()
function. When a child process is started, it reads data from the SCP by calling the KnTaskGetEnv()
function, then it deletes the SCP by calling the KnTaskFreeEnv()
function. All three functions do not need to be explicitly called because their calls are made by the libkos
library.
Terminating processes
Process termination includes the following:
- Terminating all threads of the process.
- Freeing the memory of the process.
- Freeing system resources and user resources that are exclusively owned by the process.
When a process is terminated, all the handles that it owns are closed. If a closed handle was the only handle of a resource, this resource is freed.
A process can be terminated for the following reasons:
- On its own initiative.
The
KnTaskExit()
function is called, or all threads of the process are terminated. - By external request.
The
KnTaskTerminate()
function is called. - As a result of an unhandled exception (crash).
By calling the
KnTaskPanic()
function, a process can purposefully initiate an exception that cannot be handled and leads to the process terminating. This assures that the process can terminate itself. (For example, if the process contains threads attached to interrupts, theKnTaskExit()
cannot terminate the process, while theKnTaskPanic()
function can.)
The exit codes of processes are defined by the developer of the KasperskyOS-based solution. These codes must be specified in the status
parameter of the KnTaskExit()
function. If a process was terminated due to the termination of all its threads, the exit code of this process will be the exit code of its initial thread. To get the exit code of a process that was terminated on its own initiative, call the KnTaskGetExitCode()
function.
To get information regarding the reason for process termination, call the KnTaskGetExitStatus()
function. This function determines whether a process was terminated on its own initiative, by external request, or unexpectedly.
To get information about an unhandled exception that led to an unexpected termination of a process, call the KnTaskGetExceptionInfo()
function. This information includes the exception code and the context of the thread in which this exception occurred.
If the process was created by calling the KnTaskCreateEx()
function with the TaskExceptionFreezesTask
flag in the flags
parameter, an unhandled exception will cause this process to switch to a "frozen" state instead of terminating. When a process is switched to a "frozen" state, its threads are terminated as a result of the unhandled exception but its resources are not freed, which means that you can get information about this process. To get the context of a thread that is part of a frozen process, call the KnTaskGetThreadContext()
function. To get information about the virtual memory region that belongs to a frozen process, call the KnTaskGetNextVmRegion()
function. This information includes the base address and size of the virtual memory region, and the access rights to this virtual memory region. Before a process switches to the frozen state, stack backtrace data (call stack information) is printed for the thread in which the unhandled exception occurred. To terminate a frozen process, call the KnTaskTerminateAfterFreezing()
function.
To ensure that the kernel object describing a process is deleted after this process is terminated, each of its handles must be closed or revoked in all processes that own these handles before or after termination of this process. To do so, use the KnHandleClose()
and/or KnHandleRevoke()
functions that are declared in the header file sysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK.
Handling exceptions
To register an exception handling function, call the KnTaskSetExceptionHandler()
function. This function deregisters the previous exception handling function and returns its ID. By saving this ID, you can subsequently register the previous exception handling function again.
An exception handling function is called when an exception occurs in any process thread. If the exception is successfully handled, this function returns a value other than zero. Otherwise it returns zero. The input parameter of the exception handling function is a structure containing information about the exception. The type of this structure is defined in the header file sysroot-*-kos/include/thread/tcbpage.h
from the KasperskyOS SDK.
If an exception handling function registered at the process level failed to successfully handle an exception, the exception handling function registered at the level of the thread in which the exception occurred will be called. (For details about handling exceptions at the thread level, see Managing threads (low-level API thread_api.h)).
Reserving memory in a child process
The API includes the KnTaskVmReserve()
and KnTaskVmFree()
functions, which reserve and free virtual memory regions, respectively, in a child process that does not yet have a defined program entry point. These functions comprise only a part of the functionality intended to increase control of the parent process over the virtual address space of a child process. This functionality is currently under development.
Getting the GSI address
Global system information (GSI) is a structure containing system information, such as the timer count since the kernel started, the timer counts per second, the number of processors (processor cores) in active state, and processor cache data. The type of structure is defined in the header file sysroot-*-kos/include/task/pcbpage.h
from the KasperskyOS SDK. The KnTaskGetGsi()
function gets the GSI address. This function is intended for use by the libc
library.
Getting the PCB address
A process control block (PCB) is a structure containing process information that is used by the kernel to manage this process. The type of structure is defined in the header file sysroot-*-kos/include/task/pcbpage.h
from the KasperskyOS SDK. The KnTaskGetPcb()
function gets the PCB address. This function is intended for use by the libc
library.
Information about API functions
task_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a process. Parameters
Returned values If successful, the function returns |
|
Purpose Creates a process. Parameters
Returned values If successful, the function returns Additional information In the
|
|
Purpose Gets the GSI address for the calling process. Parameters N/A Returned values Pointer to the GSI. The data type for GSI storage is defined in the header file |
|
Purpose Gets the address of the process control block (PCB) for the calling process. Parameters N/A Returned values Pointer to the PCB. The data type for PCB storage is defined in the header file |
|
Purpose Gets the SCP address of the calling process. Parameters
Returned values Pointer to the SCP, or |
|
Purpose Writes data to the SCP of a process. Parameters
Returned values If successful, the function returns |
|
Purpose Deletes the SCP of the calling process. Parameters N/A Returned values If successful, the function returns |
|
Purpose Writes the ELF image header to the PCB of a process. Parameters
Returned values If successful, the function returns |
|
Purpose Starts a process. Parameters
Returned values If successful, the function returns |
|
Purpose Terminates the calling process. Parameters
Returned values Error code. Additional information Does not terminate the process as long as it contains threads attached to interrupts. |
|
Purpose Terminates a process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets information about the reason for process termination. Parameters
Returned values If successful, the function returns Additional information You can use the
|
|
Purpose Gets information about an unhandled exception that led to an unexpected termination of a process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the context of a thread that is part of a frozen process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets information about the virtual memory region that belongs to a frozen process. Parameters
Returned values If successful, the function returns |
|
Purpose Terminates a frozen process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the exit code of a process that terminated on its own initiative. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the process ID (PID) for the calling process. Parameters N/A Returned values Process ID. The ID type is defined in the header file |
|
Purpose Gets the name of a calling process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the name of the executable file (in ROMFS) that was used to create the calling process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the priority of the initial thread of a process. Parameters
Returned values If successful, the function returns |
|
Purpose Defines the priority of the initial thread of a process. Parameters
Returned values If successful, the function returns |
|
Purpose Registers the exception handling function for the calling process. Parameters
Returned values ID of the previously registered exception handling function if one exists, otherwise |
|
Purpose Loads an ELF image segment into process memory. Parameters
Returned values If successful, the function returns |
|
Purpose Reserves a virtual memory region in a process. Parameters
Returned values If successful, the function returns Additional information In the
Permissible combinations of flags defining the access rights to the virtual memory region:
|
|
Purpose Frees the virtual memory region that was reserved by calling the Parameters
Returned values If successful, the function returns |
|
Purpose Defines the program entry point and the ELF image load offset. Parameters
Returned values If successful, the function returns |
|
Purpose Loads the symbol table Parameters
Returned values If successful, the function returns |
|
Purpose Defines the scheduler class and priority of the initial thread of a process. Parameters
Returned values If successful, the function returns Additional information In the In the |
|
Purpose Defines the seed value for ASLR support in the defined process. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the addresses and sizes of the symbol table Parameters
Returned values If successful, the function returns Additional information If the symbol table The function is intended for a mechanism that displays stack backtrace data and runs in a process and not in the kernel. This mechanism is currently under development. |
|
Purpose Gets the process ID (PID). Parameters
Returned values If successful, the function returns |
|
Purpose Initiates an exception that cannot be handled and leads to the process terminating. Parameters N/A Returned values N/A |
|
Purpose Transfers a handle to a process that is not yet running. Parameters
Returned values If successful, the function returns Additional information In contrast to the |