Arena overview
From the perspective of a developer of KasperskyOS-based solutions, an IPC message arena is a byte buffer in the memory of a process intended for storing variable-size data transmitted over IPC. This variable-size data includes input parameters, output parameters, and error parameters of interface methods (and/or elements of these parameters) that have variable-size IDL types. An arena is also used when querying the Kaspersky Security Module to store input parameters of security interface methods (and/or elements of these parameters) that have variable-size IDL types. (Parameters of fixed-size interface methods are stored in the constant part of an IPC message.) Arenas are used on the client side and on the server side. One arena is intended either for transmitting or for receiving variable-size data through IPC, but not for both transmitting and receiving this data at the same time. In other words, arenas can be divided into IPC request arenas (containing input parameters of interface methods) and IPC response arenas (containing output parameters and error parameters of interface methods).
Only the utilized part of an arena that is occupied by data is transmitted over IPC. (If it has no data, the arena is not transmitted.) The utilized part of an arena includes one or more segments. One segment of an arena stores an array of same-type objects, such as an array of single-byte objects or an array of structures. Arrays of different types of objects may be stored in different segments of an arena. The starting address of an arena must be equal to the boundary of a 2^N-byte sequence, where 2^N is a value that is greater than or equal to the size of the largest primitive type in the arena (for example, the largest field of a primitive type in a structure). The address of an arena chunk must also be equal to the boundary of a 2^N-byte sequence, where 2^N is a value that is greater than or equal to the size of the largest primitive type in the arena chunk.
An arena must have multiple segments if the interface method has multiple variable-size input, output, or error parameters, or if multiple elements of input, output, or error parameters of the interface method have a variable size. For example, if an interface method has an input parameter of the sequence
IDL type and an input parameter of the bytes
IDL type, the IPC request arena will have at least two segments. In this case, it may even require additional segments if a parameter of the sequence
IDL type consists of elements of a variable-size IDL type (for example, if elements of a sequence are string
buffers). As another example, if an interface method has one output parameter of the struct
IDL type that contains two fields of the bytes
and string
type, the IPC response arena will have two segments.
Due to the alignment of arena chunk addresses, there may be unused intervals between these chunks. Therefore, the size of the utilized part of an arena may exceed the size of the data it contains.
API for working with an arena
The set of functions and macros for working with an arena is defined in the header file sysroot-*-kos/include/nk/arena.h
from the KasperskyOS SDK. In addition, the function for copying a string to an arena is declared in the header file sysroot-*-kos/include/coresrv/nk/transport-kos.h
from the KasperskyOS SDK.
Information on the functions and macros defined in the header file sysroot-*-kos/include/nk/arena.h
is provided in the table below. In these functions and macros, an arena and arena chunk are identified by an arena descriptor (the nk_arena
type) and an arena chunk descriptor (the nk_ptr_t
type), respectively. An arena descriptor is a structure containing three pointers: one pointer to the start of the arena, one pointer to the start of the unused part of the arena, and one pointer to the end of the arena. An arena chunk descriptor is a structure containing the offset of the arena chunk in bytes (relative to the start of the arena) and the size of the arena chunk in bytes. (The arena chunk descriptor type is defined in the header file sysroot-*-kos/include/nk/types.h
from the KasperskyOS SDK.)
Creating an arena
To pass variable-size parameters of interface methods over IPC, you must create arenas on the client side and on the server side. (When IPC requests are handled on the server side using the NkKosDoDispatch()
function defined in the header file sysroot-*-kos/include/coresrv/nk/transport-kos-dispatch.h
from the KasperskyOS SDK, the IPC request arena and IPC response arena are created automatically.)
To create an arena, you must create a buffer (in the stack or heap) and initialize the arena descriptor.
The address of the buffer must be aligned to comply with the maximum size of a primitive type that can be put into this buffer. The address of a dynamically created buffer usually has adequate alignment to hold the maximum amount of data of the primitive type. To ensure the required alignment of the address of a statically created buffer, you can use the alignas
specifier.
To initialize an arena descriptor using the pointer to an already created buffer, you must use an API function or macro:
NK_ARENA_INITIALIZER()
macronk_arena_init()
functionnk_arena_create()
functionNK_ARENA_FINAL()
macronk_arena_init_final()
macroThe type of pointer makes no difference because this pointer is converted into a pointer to a single-byte object in the code of API functions and macros.
The NK_ARENA_INITIALIZER()
macro and the nk_arena_init()
and nk_arena_create()
functions initialize arena descriptor that may contain one or more segments. The NK_ARENA_FINAL()
and nk_arena_init_final()
macros initialize arena descriptor that contains only one segment spanning the entire arena throughout its entire life cycle.
To create a buffer in the stack and initialize the handle in one step, use the NK_ARENA_AUTO()
macro. This macro creates an arena that may contain one or more segments, and the address of the buffer created by this macro has adequate alignment to hold the maximum amount of data of the primitive type.
The size of an arena must be sufficient to hold variable-size parameters for IPC requests or IPC responses of one interface method or a set of interface methods corresponding to one interface, component, or process class while accounting for the alignment of segment addresses. Automatically generated transport code (the header files *.idl.h
, *.cdl.h
, and *.edl.h
) contain *_arena_size
constants whose values are guaranteed to comply with sufficient sizes of arenas in bytes.
The header files *.idl.h
, *.cdl.h
, and *.edl.h
contain the following *_arena_size
constants:
<interface name>_<interface method name>_req_arena_size
– size of an IPC request arena for the specified interface method of the specified interface<interface name>_<interface method name>_res_arena_size
– size of an IPC response arena for the specified interface method of the specified interface<interface name>_req_arena_size
– size of an IPC request arena for any interface method of the specified interface<interface name>_res_arena_size
– size of an IPC response arena for any interface method of the specified interfaceThe header files *.cdl.h
and *.edl.h
also contain the following *_arena_size
constants:
<component name>_component_req_arena_size
– size of an IPC request arena for any interface method of the specified component<component name>_component_res_arena_size
– size of an IPC response arena for any interface method of the specified componentThe *.edl.h
header files also contain the following *_arena_size
constants:
<process class name>_entity_req_arena_size
– size of an IPC request arena for any interface method of the specified process class<process class name>_entity_res_arena_size
– size of an IPC response arena for any interface method of the specified process classConstants containing the size of an IPC request arena or IPC response arena for one interface method (<interface name>_<interface method name>_req_arena_size
and <interface name>_<interface method name>_res_arena_size
) are intended for use on the client side. All other constants can be used on the client side and on the server side.
Examples of creating an arena:
/* Example 1 */
alignas(8) char reqBuffer[Write_WriteInLog_req_arena_size];
struct nk_arena reqArena = NK_ARENA_INITIALIZER(
reqBuffer, reqBuffer + sizeof(reqBuffer));
/* Example 2 */
struct nk_arena res_arena;
char res_buf[kl_rump_DhcpcdConfig_GetOptionNtpServers_res_arena_size];
nk_arena_init(&res_arena, res_buf, res_buf + sizeof(res_buf));
/* Example 3 */
char req_buffer[kl_CliApplication_Run_req_arena_size];
struct nk_arena req_arena = nk_arena_create(req_buffer, sizeof(req_buffer));
/* Example 4 */
nk_ptr_t ptr;
const char *cstr = "example";
nk_arena arena = NK_ARENA_FINAL(&ptr, cstr, strlen(cstr));
/* Example 5 */
const char *path = "path_to_file";
size_t len = strlen(path);
/* Structure for saving the constant part of an IPC request */
struct kl_VfsFilesystem_Rmdir_req req;
struct nk_arena req_arena;
nk_arena_init_final(&req_arena, &req.path, path, len);
/* Example 6 */
struct nk_arena res_arena = NK_ARENA_AUTO(kl_Klog_component_res_arena_size);
Adding data to an arena before transmission over IPC
Before transmitting an IPC request on the client side or an IPC response on the server side, data must be added to the arena. If the NK_ARENA_FINAL()
macro or the nk_arena_init_final()
macro is used to create an arena, you do not need to reserve an arena chunk. Instead, you only need to add data to this chunk. If the NK_ARENA_INITIALIZER()
or NK_ARENA_AUTO()
macro, or the nk_arena_init()
or nk_arena_create()
function is used to create an arena, one or multiple segments in the arena must be reserved to hold data. To reserve an arena chunk, you must use an API function or macro:
__nk_arena_alloc()
functionnk_arena_store()
macro__nk_arena_store()
functionnk_arena_alloc()
macroNkKosCopyStringToArena()
functionThe arena chunk descriptor, which is passed through the output parameter of these functions and macros and through the output parameter of the NK_ARENA_FINAL()
and nk_arena_init_final()
macros, must be put into the constant part or into the arena of an IPC message. If an interface method has a variable-size parameter, the constant part of IPC messages contains arena chunk descriptor containing the parameter instead of the actual parameter. If an interface method has a fixed-size parameter with variable-size elements, the constant part of IPC messages contains arena chunk descriptors containing the parameter elements instead of the actual parameter elements. If an interface method has a variable-size parameter containing variable-size elements, the constant part of IPC messages contains arena chunk descriptor containing the descriptors of other arena chunks that contain these parameter elements.
The nk_arena_store()
macro and the __nk_arena_store()
and NkKosCopyStringToArena()
functions not only reserve an arena chunk, but also copy data to this chunk.
The nk_arena_alloc()
macro gets the address of a reserved arena chunk. An arena chunk address can also be received by using the __nk_arena_get()
function or the nk_arena_get()
macro, which additionally pass the arena size through the output parameter.
A reserved arena chunk can be reduced. To do so, use the nk_arena_shrink()
macro or the _nk_arena_shrink()
function.
To undo a current reservation of arena chunks so that new chunks can be reserved for other data (after sending an IPC message), call the nk_arena_reset()
function. If the NK_ARENA_FINAL()
macro or nk_arena_init_final()
macro is used to create an arena, you do not need to undo a segment reservation because the arena contains one segment spanning the entire arena throughout its entire life cycle.
Examples of adding data to an arena:
/* Example 1 */
char req_buffer[kl_rump_NpfctlFilter_TableAdd_req_arena_size];
struct nk_arena req_arena = NK_ARENA_INITIALIZER(req_buffer, req_buffer + sizeof(req_buffer));
/* Structure for saving the constant part of an IPC request */
struct kl_rump_NpfctlFilter_TableAdd_req req;
if (nk_arena_store(char, &req_arena, &req.tid, tid, tidlen))
return ENOMEM;
if (nk_arena_store(char, &req_arena, &req.cidrAddr, cidr_addr, cidr_addrlen))
return ENOMEM;
/* Example 2 */
char req_arena_buf[StringMaxSize];
struct nk_arena req_arena = NK_ARENA_INITIALIZER(req_arena_buf,
req_arena_buf + sizeof(req_arena_buf));
/* Structure for saving the constant part of an IPC request */
kl_drivers_FBConsole_SetFont_req req;
size_t buf_size = strlen(fileName) + 1;
char *buf = nk_arena_alloc(char, &req_arena, &req.fileName, buf_size);
memcpy(buf, fileName, buf_size);
/* Example 3 */
char reqArenaBuf[kl_core_DCM_req_arena_size];
struct nk_arena reqArena
= NK_ARENA_INITIALIZER(reqArenaBuf,
reqArenaBuf + sizeof(reqArenaBuf));
/* Structure for saving the constant part of an IPC request */
kl_core_DCM_Subscribe_req req;
rc = NkKosCopyStringToArena(&reqArena, &req.endpointType, endpointType);
if (rc != rcOk)
return rc;
rc = NkKosCopyStringToArena(&reqArena, &req.endpointName, endpointName);
if (rc != rcOk)
return rc;
rc = NkKosCopyStringToArena(&reqArena, &req.serverName, serverName);
if (rc != rcOk)
return rc;
/* Example 4 */
unsigned counter = 0;
nk_ptr_t *paths;
/* Reserve an arena chunk for descriptors of other arena chunks */
paths = nk_arena_alloc(nk_ptr_t, resArena, &res->logRes, msgCount);
while(...)
{
...
/* Reserve arena chunks and save their descriptors in
* a previously reserved arena chunk with the paths address */
char *str = nk_arena_alloc(
char,
resArena,
&paths[counter],
stringLength + 1);
if (str == NK_NULL)
return NK_ENOMEM;
snprintf(str, (stringLength + 1), "%s", buffer);
...
counter++;
}
Retrieving data from an arena after receipt over IPC
Prior to receiving an IPC request on the server side or an IPC response on the client side for an arena that will store the data received over IPC, you must undo the current reservation of segments by calling the nk_arena_reset()
function. This must be done even if the NK_ARENA_FINAL()
macro or the nk_arena_init_final()
macro is used to create the arena. (The NK_ARENA_INITIALIZER()
and NK_ARENA_AUTO()
macros, and the nk_arena_init()
and nk_arena_create()
functions create an arena without reserved segments. You do not need to call the nk_arena_reset()
function if this arena will only be used once to save data received over IPC.)
To receive pointers to arena chunks and the sizes of these chunks, you must use the __nk_arena_get()
function or the nk_arena_get()
macro while using the input parameter to pass the corresponding arena chunk descriptors received from the constant part and arena of the IPC message.
Example of receiving data from an arena:
struct nk_arena res_arena;
char res_buf[kl_rump_DhcpcdConfig_Version_res_ver_size];
nk_arena_init(&res_arena, res_buf, res_buf + sizeof(res_buf));
/* Structure for saving an IPC request */
struct kl_rump_DhcpcdConfig_Version_req req;
req.buflen = buflen;
/* Structure for saving an IPC response */
struct kl_rump_DhcpcdConfig_Version_res res;
/* Call the interface method */
if (kl_rump_DhcpcdConfig_Version(dhcpcd.proxy, &req, NULL, &res, &res_arena) != NK_EOK)
return -1;
size_t ptrlen;
char *ptr = nk_arena_get(char, &res_arena, &res.ver, &ptrlen);
memcpy(buf, ptr, ptrlen);
Additional capabilities of the API
To get the arena size, call the nk_arena_capacity()
function.
To get the size of the utilized part of the arena, call the nk_arena_allocated_size()
function.
To verify that the arena chunk descriptor is correct, use the nk_arena_validate()
macro or the __nk_arena_validate()
function.
Information about API functions and macros
Functions and macros of arena.h
Function/Macro |
Information about the function/macro |
---|---|
|
Purpose Initializes the arena descriptor. Parameters
Macro values Arena descriptor initialization code. |
|
Purpose Initializes the arena descriptor. Parameters
Returned values N/A |
|
Purpose Creates and initializes the arena descriptor. Parameters
Returned values Arena descriptor. |
|
Purpose Creates a buffer in the stack, and creates and initializes the arena descriptor. Parameters
Macro values Arena descriptor. |
|
Purpose Initializes the arena descriptor containing only one segment. Parameters
Macro values Arena descriptor. |
|
Purpose Resets the reservation of arena chunks. Parameters
Returned values N/A |
|
Purpose Reserves an arena chunk with a specific size and a specific alignment. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the size of an arena. Parameters
Returned values Size of the arena in bytes. Additional information If the parameter has the |
|
Purpose Verifies that the arena chunk descriptor is correct. Parameters
Macro values It has a value of
It has a value of
It has a value of |
|
Purpose Verifies that the arena chunk descriptor is correct. Parameters
Returned values Returns
Returns
Returns |
|
Purpose Gets the pointer to the arena chunk and the size of this chunk. Parameters
Returned values Pointer to the arena chunk or |
|
Purpose Gets the size of the utilized part of the arena. Parameters
Returned values Size of the utilized part of the arena, in bytes. Additional information If the parameter has the |
|
Purpose Reserves an arena chunk for the specified number of objects of the defined type and copies these objects to the reserved chunk. Parameters
Macro values It has a value of |
|
Purpose Reserves an arena chunk with a defined alignment for data of a specific size and copies this data to the reserved segment. Parameters
Returned values Returns |
|
Purpose Initializes the arena descriptor containing only one segment. Parameters
Macro values N/A |
|
Purpose Reserves an arena chunk for the defined number of objects of the specified type. Parameters
Macro values It has the address of the reserved arena chunk if successful, otherwise |
|
Purpose Gets the address of an arena chunk and the number of objects of the specified type that can be put into this chunk. Parameters
Macro values It has the address of the arena chunk if successful, otherwise Additional information If the size of the arena chunk is not a multiple of the size of the type of objects for which this chunk is intended, it has the |
|
Purpose Reduces the size of an arena chunk. Parameters
Macro values It has the address of the reduced arena chunk if successful, otherwise Additional information If the required size of the arena chunk exceeds the current size, it has the If the alignment of the arena chunk that needs to be reduced does not match the type of objects for which the reduced chunk is intended, it has the If the arena chunk that needs to be reduced is the last chunk in the arena, the freed part of this chunk will become available for reservation of subsequent chunks. |
|
Purpose Reduces the size of an arena chunk. Parameters
Returned values Returns the address of the reduced arena chunk if successful, otherwise returns Additional information If the required size of the arena chunk exceeds the current size, it returns If the alignment of the arena chunk that needs to be reduced does not match the specified alignment, it returns If the arena chunk that needs to be reduced is the last chunk in the arena, the freed part of this chunk will become available for reservation of subsequent chunks. |