\x20\40\x20\40
/**
@file
@brief kernel and userspace transport protocol
@details Copyright (c) 2017 Acronis International GmbH
@author Mikhail Krivtsov (mikhail.krivtsov@acronis.com)
@since $Id: $
*/
#pragma once
// Note: This file is shared between kernel and user space transport code.
// Note: Linux kernel build system defines '__KERNEL__'
#if defined __KERNEL__
#include <linux/types.h> // bool, [u]int(8|16|32|64)_t, pid_t
#else
#include <stdbool.h> // bool
#include <stdint.h> // [u]int(8|16|32|64)_t
#include <sys/types.h> // pid_t
#endif
#if !defined PACKED
#define PACKED __attribute__((packed))
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define TRANSPORT_DEVICE_NAME "apl_transport"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
Each message is either a 'query' or a 'reply'. Each message contains
an identifier ('id') necessary to match 'reply' to corresponding
'query'. Zero 'id' in 'query' means that 'reply' is not necessary.
'reply' with zero 'id' is not used.
*/
typedef uint64_t msg_id_t;
typedef enum {
MT_HELLO = 0,
// reserved 1
MT_PONG = 2,
// reserved till 9
MT_EXEC = 9,
MT_EXIT,
MT_FORK,
// file system events:
MT_DIR_OPEN,
MT_DIR_WRITE,
MT_DIR_CLOSE,
MT_FILE_PRE_CREATE,
MT_FILE_CREATE_EX,
MT_FILE_PRE_OPEN,
// reserved 18
MT_FILE_PRE_WRITE_EX = 19,
// reserved 20-21
MT_PRE_RENAME_EX = 22,
MT_RENAME,
MT_PRE_UNLINK_EX,
MT_UNLINK,
MT_FILE_PRE_CLOSE_EX,
MT_FILE_PRE_READ_EX,
MT_FILE_PRE_OPEN_EX,
MT_RENAME_EX,
MT_UNLINK_EX,
MT_MAX,
} msg_type_t;
typedef enum {
// reserved 0 as an error type
AT_PING = 1,
// reserved 2
AT_PID_SET_ST = 3,
AT_PID_DEL = 4,
AT_GET_PID_INFO = 5,
// reserved 6
AT_GET_FS_ROOT = 7,
// 8 was reserved but now used for 'AT_GET_VERSION'
// as it would behave fine - it was not used by ioctl or write
AT_GET_VERSION = 8,
AT_OPEN_FILE_FROM_MSG,
AT_OPEN_FILE_BY_PATH,
AT_ENABLE_EVENTS,
AT_DISABLE_EVENTS,
AT_INIT_SHARED_DATA_QUEUE,
AT_WAIT_SHARED_DATA_QUEUE,
AT_EX_EVENTS_SUPPORTED,
AT_LAST,
} action_type_t;
typedef enum {
RT_ERROR = 0,
// reserved till 6
RT_PID_INFO = 6,
// reserved 7
RT_FS_ROOT = 8,
RT_OPENED_FILE,
RT_VERSION_INFO,
RT_DATA_QUEUE_OFFSETS,
} return_type_t;
typedef uint8_t msg_type_img_t;
typedef struct PACKED {
msg_id_t id;
msg_type_img_t type; // msg_type_t
bool reply;
uint8_t payload[0];
} msg_img_t;
inline static
msg_id_t msg_img_id(const msg_img_t *msg_img)
{
return msg_img->id;
}
inline static
msg_type_img_t msg_img_type(const msg_img_t *msg_img)
{
return msg_img->type;
}
inline static
bool msg_img_is_reply(const msg_img_t *msg_img)
{
return msg_img->reply;
}
inline static
bool msg_img_is_reply_required(const msg_img_t *msg_img)
{
return msg_img_id(msg_img) && !msg_img_is_reply(msg_img);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
Generic 'reply' message
*/
// Note: Empty 'reply' may be used as shortcut for 'default' reply
/*
// Legacy 'reply_img_t'
typedef struct PACKED {
uint8_t reply[0];
} reply_img_t;
*/
typedef enum {
RT_ALLOW,
RT_BLOCK,
} reply_type_t;
typedef uint8_t reply_type_img_t;
typedef struct PACKED {
reply_type_img_t type;
uint8_t payload[0];
} reply_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
'hello' message is sent on 'first' user space connection.
*/
typedef struct PACKED {
// TODO: add version information here
uint8_t payload[0];
} hello_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
'transport' testing
'pong' message is 'high level' reply to 'ping' message. 'pong'
message returns 'payload' from 'ping' message.
'ping' and 'pong' messages can be sent in both 'synchronous' (i.e
with *_reply') and 'asynchronous' (i.e without *_reply') modes.
'ping_reply' and 'pong_reply' are respective 'low level'
confirmations for 'ping' and 'pong' messages. They do not return
'payload'. Instead they return some arbitrary 'reply'.
*/
typedef uint64_t ping_pong_sequence_t;
typedef struct PACKED {
ping_pong_sequence_t sequence;
uint8_t payload[0];
} ping_img_t;
typedef struct PACKED {
ping_pong_sequence_t sequence;
uint8_t payload[0];
} pong_img_t;
typedef struct PACKED {
uint8_t reply[0];
} ping_reply_img_t;
typedef struct PACKED {
uint8_t reply[0];
} pong_reply_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
task_info_map management
*/
typedef uint32_t pid_img_t;
typedef uint32_t uid_img_t;
typedef uint32_t gid_img_t;
// FIXME: rename 'task_status' to '([fs_]events|monitoring|watch)[ mode]'
typedef enum {
TS_UNKNOWN, // 0, initial default
TS_IGNORE, // active protection daemon and friends
TS_WHITE, // harmless
TS_BLACK, // harmful
TS_GREY, // FIXME: What is this for?
} task_status_t;
typedef struct PACKED {
pid_img_t pid; // pid_t
task_status_t status;
} pid_set_st_img_t;
typedef struct PACKED {
pid_img_t pid; // pid_t
} pid_del_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AT_GET_PID_INFO
typedef struct PACKED {
pid_img_t pid; // pid_t
} get_pid_info_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RT_PID_INFO
typedef struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
char path[0];
} pid_info_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AT_GET_FS_ROOT
typedef struct PACKED {
pid_img_t pid; // pid_t
} get_fs_root_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RT_FS_ROOT
typedef struct PACKED {
char fs_root[0];
} fs_root_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AT_OPEN_FILE_FROM_MSG
typedef struct PACKED {
// useful for 'rename*' message that may refer to 2 files
int num;
} open_file_from_msg_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AT_OPEN_FILE_BY_PATH
typedef struct PACKED {
int flags;
int mode;
char path[0];
} open_file_by_path_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RT_OPENED_FILE
typedef struct PACKED {
int fd;
} opened_file_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define DRIVER_FEATURE_CLOSE_EVENT 0x1
// RT_VERSION_INFO
typedef struct PACKED {
// Max Action allowed to be called in 'ioctl'/'write' calls
// If AT_GET_VERSION errors out itself, 'max_action' should be AT_GET_VERSION
uint8_t max_action;
// Features exposed by the module that are outside of 'ioctl'/'write' scope
uint64_t features;
} version_info_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 'MT_EXEC' is the first event user might want to listen to
#define MT_FIRST_ACTIVITY_EVENT MT_EXEC
// Convert a given MT to the event mask. Only events past MT_EXEC can be selected.
#define MSG_TYPE_TO_EVENT_MASK(mt) (1 << ((mt) - MT_FIRST_ACTIVITY_EVENT))
// AT_ENABLE_EVENTS
// AT_DISABLE_EVENTS
typedef struct PACKED {
// Mask of events as per 'MSG_TYPE_TO_EVENT_MASK'
uint64_t events_mask;
} events_mask_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
pid_img_t ppid; // pid_t
pid_img_t ptid; // pid_t
int8_t sure; // false if process is new for task_info_map
char path[0];
} exec_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
} exit_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef struct PACKED {
struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
} parent;
struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
} child;
} fork_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
File system events
Note: File system events must be 'synchronous' to let userspace
backup affected files prior to any actual modification by kernel.
*/
typedef struct PACKED {
pid_img_t pid; // pid_t
pid_img_t tid; // pid_t
uid_img_t fsuid;
gid_img_t fsgid;
uint8_t payload[0];
} fs_event_img_t;
typedef uint64_t offset_img_t; // Note: 'loff_t' is 'signed'
typedef uint64_t size_img_t;
// 'RW' message is for CREAT, OPEN, [PRE_]WRITE
// Note: 'offset' and 'count' are relevant for 'write' only
typedef struct PACKED {
int64_t ret_val;
uint32_t flags;
offset_img_t offset; // loff_t
size_img_t count; // size_t
char path[0];
} fs_event_rw_img_t;
typedef struct PACKED {
uint64_t ptr;
uint64_t ino;
uint64_t gen;
uint64_t dev;
} file_key_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flags;
offset_img_t offset; // loff_t
size_img_t count; // size_t
file_key_t key;
char path[0];
} fs_event_rw_ex_img_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flags;
// oldname = names[0]
// newname = names[newname_offset]
uint16_t newname_offset;
char names[0];
} fs_event_rename_img_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flags;
file_key_t source_key;
file_key_t target_key;
// oldname = names[0]
// newname = names[newname_offset]
uint16_t newname_offset;
uint8_t target_exists;
char names[0];
} fs_event_rename_ex_img_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flag;
char path[0];
} fs_event_unlink_img_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flag;
file_key_t key;
char path[0];
} fs_event_unlink_ex_img_t;
typedef struct PACKED {
int64_t ret_val;
uint32_t flags;
offset_img_t offset; // loff_t
size_img_t count; // size_t
file_key_t key;
} fs_event_rw_key_img_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef enum {
IOCTL_READ_MSG = 1,
IOCTL_WRITE_MSG = 2,
IOCTL_WRITE_AND_READ_MSG = 3,
IOCTL_READ_VERSION = 4,
} ioctl_cmd_t;
typedef uint16_t ioctl_size_img_t;
typedef struct PACKED {
ioctl_size_img_t capacity; // payload capacity;
ioctl_size_img_t size; // actual payload size;
uint8_t payload[0];
} ioctl_hdr_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Shared Data queue protocol
// Entry description in the mmap'd buffer
typedef struct {
uint32_t size;
uint8_t data[0];
} data_queue_entry_t;
// Params passed to the data_queue init
// AT_INIT_SHARED_DATA_QUEUE
typedef struct PACKED {
uint32_t size;
} data_queue_params_t;
// Those offsets correspond to values in the 'mmap' buffer
//
/*
struct shared_data_queue {
uint32_t size ____cacheline_aligned_in_smp;
uint32_t head ____cacheline_aligned_in_smp;
uint32_t tail ____cacheline_aligned_in_smp;
struct data_queue_entry entries[0] ____cacheline_aligned_in_smp;
};
*/
// RT_DATA_QUEUE_OFFSETS
typedef struct {
uint32_t size; // as size of the whole 'queue'
uint32_t headOff;
uint32_t tailOff;
uint32_t entriesOff;
} data_queue_offsets_t;