IPC message structure
In KasperskyOS, all interactions between entities have statically defined types. The permissible structures of an IPC message are defined in the IDL description of the interfaces of the entity that receives the message (server).
A correct IPC message (request and response) contains a constant part and an arena.
Constant part of a message
The constant part of a message contains arguments of a fixed size, and the RIID and MID.
Fixed-size arguments can be arguments of any IDL types except the sequence
type.
The RIID and MID identify the interface and method being called:
- The RIID (Runtime Implementation ID) is the number of the entity interface implementation being called, starting at zero.
- The MID (Method ID) is the number of the method within the interface that contains it, starting at zero.
The type of the constant part of the message is generated by the NK compiler based on the IDL description of the interface. A separate structure is generated for each interface method. Union
types are also generated for storing any request to a server, component or interface.
For example, for the Ping
method of the Ping
interface (the Ping
component of the Server
entity in the echo example), the NK compiler will create the Ping_Ping_req
type for the constant part of the request and the Ping_Ping_res
type for the constant part of the response. The following union
types will also be generated:
Ping_req
andPing_res
are constant parts of the request and response for any method of thePing
interface.Ping_component_req
andPing_component_res
are constant parts of the request and response for any method of any interface whose implementation is included in thePing
component.If embedded components are present, these types also contain structures of the constant part of a message for any method of any interface whose implementations are included in all embedded components. For more details, refer to Generated methods and types.
Server_entity_req
andServer_entity_res
are the constant parts of the request and response for any method of any interface whose implementation is included in any component whose instance is included in theServer
entity.
Arena
The arena is a buffer for storing variable-size arguments (sequence
IDL type).
Validating a message in Kaspersky Security System
The Kaspersky Security Module verifies that the structure of the message being sent is correct. Requests and responses are both validated. If the message has an incorrect structure, it will be rejected without calling the security model methods associated with it.
Forming a message structure
KasperskyOS Community Edition includes the following tools that make it easier for the developer to create and package an IPC message:
- The
transport-kos
library for working with NkKosTransport. - The NK compiler that lets you generate special methods and types.
The echo example shows the creation of a simple IPC message.
NkKosTransport
NkKosTransport
is a convenient wrapper for the Call
, Recv
and Reply
system calls. It lets you work separately with messages' constant parts and arenas.
The NkKosTransport
structure and methods for working with it are declared in the transport-kos.h
file.
To initialize the transport, it is sufficient to call the NkKosTransport_Init()
function by specifying the IPC handle of the channel that should be used to transmit messages (handle
):
…
NkKosTransport transport;
NkKosTransport_Init(&transport, handle, NK_NULL, 0);
A channel has two IPC handles: client and server. Therefore, when initializing the transport, you need to specify the client handle for the utilized channel on the client side and the server handle on the server side.
The functions nk_transport_call()
, nk_transport_recv()
and nk_transport_reply()
declared in transport.h
(included in the transport-kos.h
file) are used to call the transport.
The nk_transport_call()
function is intended for sending a request and receiving a response:
/* The constant part (req) and arena of the request (req_arena) must be initialized
* with the actual input arguments of the method being called. The constant part (req)
* must also contain the RIID and MID values.
* The nk_transport_call() function generates a request and executes the Call system call.
* The response received from the server is inserted into res (constant part of the response) and
* res_arena (response arena). */
nk_transport_call(&transport.base, (struct nk_message *)&req, &req_arena, (struct nk_message *)&res, &res_arena);
When using a generated interface method (for example, the IPing_Ping
method from the echo example) on the client side, the corresponding values of the RIID and MID are automatically inserted into the request, after which the nk_transport_call()
function is called.
The nk_transport_recv()
function is intended for receiving a request:
/* The nk_transport_recv () function executes the Recv system call.
* The request received from the client is inserted into req (constant part of the response) and
* req_arena (response arena). */
nk_transport_recv(&transport.base, (struct nk_message *)&req, &req_arena);
The nk_transport_reply()
function is intended for sending a response:
/* The constant part (res) and request arena (res_arena) must be initialized
* with the actual output arguments of the server method being called.
* The nk_transport_reply() function generates a response and executes a Reply system call. */
nk_transport_reply(&transport.base, (struct nk_message *)&res, &res_arena);
Generated methods and types
When building a solution, the NK compiler uses the EDL-, CDL- and IDL descriptions to generate a set of special methods and types that simplify the creation, forwarding, receipt and processing of IPC messages.
Examine the static description of the Server
entity from the echo example. This description consists of three files: Server.edl
, Ping.cdl
and Ping.idl
:
Server.edl
/* Description of the Server entity. */
entity Server
/* pingComp is a named instance of the Ping component. */
components {
pingComp: Ping
}
Ping.cdl
/* Description of the Ping component. */
component Ping
/* pingImpl is the Ping interface implementation. */
interfaces {
pingImpl: Ping
}
Ping.idl
/* Description of the Ping interface. */
package Ping
interface {
Ping(in UInt32 value, out UInt32 result);
}
These files will be used to generate the files named Server.edl.h
, Ping.cdl.h
, and Ping.idl.h
, which contain the following methods and types:
Methods and types that are common to the client and server
- Abstract interfaces containing the pointers to the implementations of the methods included in them.
In our example, one abstract interface (
Ping
) will be generated:struct Ping_ops {
nk_err_t (*Ping)(struct Ping *,
const struct Ping_req *,
const struct nk_arena *,
struct Ping_res *,
struct nk_arena *); };
struct Ping {
const struct Ping_ops *ops;
};
- Set of interface methods.
When calling an interface method, corresponding values of the RIID and MID are automatically inserted into the request, after which the
nk_transport_call()
function is called.In our example, a single
Ping_Ping
interface method will be generated:nk_err_t Ping_Ping(struct Ping *,
const struct Ping_Ping_req *,
const struct nk_arena *,
struct Ping_Ping_res *,
struct nk_arena *);
Methods and types used only on the client
- Types of proxy objects.
A proxy object is used as an argument in an interface method. In our example, a single
Ping_proxy
proxy object type will be generated:struct Ping_proxy {
struct Ping base;
struct nk_transport *transport;
nk_iid_t iid;
};
- Functions for initializing proxy objects.
In our example, the single initializing function
Ping_proxy_init
will be generated:void Ping_proxy_init(struct Ping_proxy *, struct nk_transport *, nk_iid_t);
- Types that define the structure of the constant part of a message for each specific method.
In our example, two such types will be generated:
Ping_Ping_req
(for a request) andPing_Ping_res
(for a response).struct Ping_Ping_req {
struct nk_message base_;
nk_uint32_t value;
};
struct Ping_Ping_res {
struct nk_message base_;
nk_uint32_t result;
};
Methods and types used only on the server
- Type containing implementations of all component interfaces, and the initializing function. (For each server component.)
If there are embedded components, this type also contains their instances, and the initializing function takes their corresponding initialized structures. Therefore, if embedded components are present, their initialization must begin with the most deeply embedded component.
In our example, the
Ping_component
structure andPing_component_init
function will be generated:struct Ping_component {
struct Ping *pingImpl;
};
void Ping_component_init(struct Ping_component *, struct Ping *);
- Type containing implementations of all interfaces provided directly by the server entity; all instances of components included in the server entity; and the initializing function.
In our example, the
Server_entity
structure andServer_entity_init
function will be generated:struct Server_entity {
struct Ping_component *pingComp;
};
void Server_entity_init(struct Server_entity *, struct Ping_component *);
- Types that define the structure of the constant part of a message for any method of a specific interface.
In our example, two such types will be generated:
Ping_req
(for a request) andPing_res
(for a response).union Ping_req {
struct nk_message base_;
struct Ping_Ping_req Ping;
};
union Ping_res {
struct nk_message base_;
struct Ping_Ping_res Ping;
};
- Types that define the structure of the constant part of a message for any method of any interface whose implementation is included in the specific component.
If embedded components are present, these types also contain structures of the constant part of a message for any method of any interface whose implementations are included in all embedded components.
In our example, two such types will be generated:
Ping_component_req
(for a request) andPing_component_res
(for a response).union Ping_component_req {
struct nk_message base_;
union Ping_req pingImpl;
};
union Ping_component_res {
struct nk_message base_;
union Ping_res pingImpl;
};
- Types that define the structure of the constant part of a message for any method of any interface whose implementation is included in any component whose instance is included in the server entity.
If embedded components are present, these types also contain structures of the constant part of a message for any method of any interface whose implementations are included in all embedded components.
In our example, two such types will be generated:
Server_entity_req
(for a request) andServer_entity_res
(for a response).union Server_entity_req {
struct nk_message base_;
union Ping_req pingComp_pingImpl;
};
union Server_entity_res {
struct nk_message base_;
union Ping_res pingComp_pingImpl;
};
- Dispatch methods (dispatchers) for a separate interface, component, or the entity.
Dispatchers analyze the received request (the RIID and MID values), call the implementation of the corresponding method, and then save the response in the buffer. In our example, three dispatchers will be generated:
Ping_dispatch
,Ping_component_dispatch
, andServer_entity_dispatch
.The entity dispatcher handles the request and calls the methods implemented by this entity. If the request contains an incorrect RIID (for example, an RIID for a different interface implementation that this entity does not have) or an incorrect MID, the dispatcher returns
NK_EOK
orNK_ENOENT
.nk_err_t Server_entity_dispatch(struct Server_entity *,
const union Server_entity_req *,
const struct nk_arena *,
union Server_entity_res *,
struct nk_arena *);
In special cases, you can use dispatchers of the interface and the component. They take an additional argument: interface implementation ID (
nk_iid_t
). The request will be handled only if the passed argument and RIID from the request match, and if the MID is correct. Otherwise, the dispatchers returnNK_EOK
orNK_ENOENT
.nk_err_t Ping_dispatch(struct Ping *,
nk_iid_t,
const union Ping_req *,
const struct nk_arena *,
union Ping_res *,
struct nk_arena *);
nk_err_t Ping_component_dispatch(struct Ping_component *,
nk_iid_t,
const union Ping_component_req *,
const struct nk_arena *,
union Ping_component_res *,
struct nk_arena *);