ÿØÿà JFIF ` ` ÿþ
|
Server : Apache System : Linux cloud.heroica.com.br 4.18.0-553.36.1.el8_10.x86_64 #1 SMP Wed Jan 22 03:07:54 EST 2025 x86_64 User : farolpborg ( 1053) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /usr/src/file_protector-1.1-1505/transport/ |
Upload File : |
/**
@file
@brief kernel/userspace transport messages
@details Copyright (c) 2017-2021 Acronis International GmbH
@author Mikhail Krivtsov (mikhail.krivtsov@acronis.com)
@since $Id: $
*/
#include "message.h"
#include "compat.h"
#include "debug.h"
#include "memory.h"
#include "task_info_map.h"
#include <linux/file.h> // fput()
#include <linux/fs_struct.h> // get_fs_root()
#include <linux/mm.h> // get_task_exe_file()
const char* msg_type_to_string(msg_type_t type)
{
switch (type)
{
#define CASE_MT_RETURN(t) case MT_##t: return #t
CASE_MT_RETURN(HELLO);
CASE_MT_RETURN(PONG);
CASE_MT_RETURN(EXEC);
CASE_MT_RETURN(EXIT);
CASE_MT_RETURN(FORK);
CASE_MT_RETURN(DIR_OPEN);
CASE_MT_RETURN(DIR_WRITE);
CASE_MT_RETURN(DIR_CLOSE);
CASE_MT_RETURN(FILE_PRE_CREATE);
CASE_MT_RETURN(FILE_CREATE);
CASE_MT_RETURN(FILE_PRE_OPEN);
CASE_MT_RETURN(FILE_OPEN);
CASE_MT_RETURN(FILE_PRE_WRITE);
CASE_MT_RETURN(FILE_WRITE);
CASE_MT_RETURN(FILE_CLOSE);
CASE_MT_RETURN(PRE_RENAME);
CASE_MT_RETURN(RENAME);
CASE_MT_RETURN(PRE_UNLINK);
CASE_MT_RETURN(UNLINK);
CASE_MT_RETURN(FILE_PRE_CLOSE);
default: return "?";
}
}
const char* action_type_to_string(action_type_t type)
{
switch (type)
{
#define CASE_AT_RETURN(t) case AT_##t: return #t
CASE_AT_RETURN(PING);
CASE_AT_RETURN(PID_SET_ST);
CASE_AT_RETURN(PID_DEL);
CASE_AT_RETURN(GET_PID_INFO);
CASE_AT_RETURN(GET_FS_ROOT);
CASE_AT_RETURN(GET_VERSION);
CASE_AT_RETURN(OPEN_FILE_FROM_MSG);
CASE_AT_RETURN(OPEN_FILE_BY_PATH);
CASE_AT_RETURN(ENABLE_EVENTS);
CASE_AT_RETURN(DISABLE_EVENTS);
default: return "?";
}
}
const char* return_type_to_string(return_type_t type)
{
switch (type)
{
#define CASE_RT_RETURN(t) case RT_##t: return #t
CASE_RT_RETURN(ERROR);
CASE_RT_RETURN(PID_INFO);
CASE_RT_RETURN(FS_ROOT);
CASE_RT_RETURN(OPENED_FILE);
default: return "?";
}
}
static void msg_free(msg_t * msg)
{
DPRINTF("msg=%p img_size=%zu type=%i/%s id=%llX reply=%i",
msg, msg->img_size,
MSG_TYPE(msg), msg_type_to_string(MSG_TYPE(msg)),
MSG_ID(msg), MSG_REPLY(msg));
mem_free(msg);
}
msg_t *msg_ref(msg_t *msg)
{
atomic_inc(&msg->ref_cnt);
DPRINTF("msg=%p ref_cnt=%i", msg, atomic_read(&msg->ref_cnt));
return msg;
}
void msg_unref(msg_t *msg)
{
DPRINTF("msg=%p ref_cnt=%i", msg, atomic_read(&msg->ref_cnt));
if (atomic_dec_and_test(&msg->ref_cnt)) {
msg_free(msg);
}
}
msg_t *msg_reply_wait_count_inc(msg_t *msg)
{
msg_ref(msg);
atomic_inc(&msg->reply_wait_count);
DPRINTF("msg=%p reply_wait_count=%i", msg, atomic_read(&msg->reply_wait_count));
return msg;
}
void msg_reply_wait_count_dec(msg_t *msg)
{
DPRINTF("msg=%p reply_wait_count=%i", msg, atomic_read(&msg->reply_wait_count));
if (atomic_dec_and_test(&msg->reply_wait_count)) {
wake_up(&msg->wait_queue);
}
msg_unref(msg);
}
msg_sized_t* msg_varsized_init(msg_varsized_t *msg, size_t msg_img_size) {
msg_sized_t* smsg;
msg->on_heap = msg_img_size > MSG_MAX_SMALL_PAYLOAD_SIZE;
if (msg->on_heap) {
msg->data.heap.ptr = msg_sized_new(msg_img_size);
}
smsg = MSG_VARSIZED_GET_SIZED(msg);
if (smsg) {
smsg->img_size = msg_img_size;
}
return smsg;
}
void msg_varsized_uninit(msg_varsized_t *msg) {
if (msg->on_heap) {
msg_sized_free(msg->data.heap.ptr);
}
}
static msg_t *msg_init(msg_t *msg, size_t msg_img_size)
{
atomic_set(&msg->ref_cnt, 1);
atomic_set(&msg->reply_wait_count, 0);
init_waitqueue_head(&msg->wait_queue);
msg->img_size = msg_img_size;
msg->interrupted = false;
msg->block = false;
thread_safe_path_init(&msg->path);
return msg;
}
msg_sized_t *msg_sized_new(size_t msg_img_size)
{
size_t msg_size = sizeof(msg_sized_t) + msg_img_size;
msg_sized_t *msg = mem_alloc(msg_size);
if (msg) {
msg->img_size = msg_img_size;
}
return msg;
}
msg_t *msg_new(size_t msg_img_size)
{
size_t msg_size = sizeof(msg_t) + msg_img_size;
msg_t *msg = mem_alloc0(msg_size);
if (msg) {
msg_init(msg, msg_img_size);
}
DPRINTF("msg=%p msg_size=%zu msg_img_size=%zu", msg, msg_size, msg_img_size);
return msg;
}
msg_t *msg_new_nowait(size_t msg_img_size)
{
size_t msg_size = sizeof(msg_t) + msg_img_size;
msg_t *msg = mem_alloc0_nowait(msg_size);
if (msg) {
msg_init(msg, msg_img_size);
}
DPRINTF("msg=%p msg_size=%zu msg_img_size=%zu", msg, msg_size, msg_img_size);
return msg;
}
msg_t *msg_new_type(size_t msg_img_size, msg_type_t type)
{
msg_t *msg = msg_new(msg_img_size);
if (msg) {
msg_img_t *msg_img = MSG_IMG(msg);
msg_img->type = type;
}
DPRINTF("msg=%p type=%i/%s", msg, type, msg_type_to_string(type));
return msg;
}
msg_t *msg_new_type_nowait(size_t msg_img_size, msg_type_t type)
{
msg_t *msg = msg_new_nowait(msg_img_size);
if (msg) {
msg_img_t *msg_img = MSG_IMG(msg);
msg_img->type = type;
}
DPRINTF("msg=%p type=%i/%s", msg, type, msg_type_to_string(type));
return msg;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
msg_t *hello_msg_new(void)
{
static const char hello[] = "hello";
size_t hello_img_size = sizeof(hello_img_t) + sizeof(hello);
size_t msg_img_size = sizeof(msg_img_t) + hello_img_size;
msg_t *msg = msg_new_type(msg_img_size, MT_HELLO);
if (msg) {
msg_img_t *msg_img = MSG_IMG(msg);
hello_img_t *hello_img = IMG_PAYLOAD(msg_img);
memcpy(hello_img->payload, hello, sizeof(hello));
}
DPRINTF("msg=%p", msg);
return msg;
}
// assuming correct 'ping_msg'
msg_t *pong_msg_new(msg_sized_t *ping_msg)
{
msg_img_t *ping_msg_img = MSG_IMG(ping_msg);
ping_img_t *ping_img = IMG_PAYLOAD(ping_msg_img);
ping_pong_sequence_t sequence = ping_img->sequence;
size_t ping_img_size = ping_msg->img_size - sizeof(msg_img_t);
size_t payload_size = ping_img_size - sizeof(ping_img_t);
size_t pong_img_size = sizeof(pong_img_t) + payload_size;
size_t msg_img_size = sizeof(msg_img_t) + pong_img_size;
msg_t *msg = msg_new_type(msg_img_size, MT_PONG);
if (msg) {
msg_img_t *msg_img = MSG_IMG(msg);
pong_img_t *pong_img = IMG_PAYLOAD(msg_img);
pong_img->sequence = sequence;
if (payload_size) {
memcpy(pong_img->payload, ping_img->payload,
payload_size);
}
}
DPRINTF("msg=%p payload_size=%zu", msg, payload_size);
return msg;
}
static int path_to_string(char **p_buf, const char **p_start, struct path *path)
{
char *buf;
char *start;
int ret;
buf = mem_alloc(PATH_MAX);
if (!buf) {
return -ENOMEM;
}
*p_buf = buf;
start = d_path(path, buf, PATH_MAX);
if (IS_ERR(start)) {
ret = PTR_ERR(start);
WPRINTF("'d_path()' failure %i", ret);
mem_free(buf);
return ret;
}
*p_start = start;
return 0;
}
enum check_exec_code {
CEC_WAS,
CEC_WAS_NOT,
CEC_NEW_PROC
};
static enum check_exec_code check_exec(pid_t tgid, struct path exe_path)
{
task_info_t *task_info;
enum check_exec_code ret;
struct path old_path;
task_info = task_info_lookup(tgid);
if (!task_info) {
task_info = task_info_get(tgid);
if (task_info) {
spin_lock(&task_info->spinlock);
task_info->status = TS_GREY;
old_path = task_info->exe_path;
task_info->exe_path = exe_path;
path_get(&task_info->exe_path);
spin_unlock(&task_info->spinlock);
path_put(&old_path); // shouldn't call under spinlock, because might sleep
task_info_unref(task_info);
}
ret = CEC_NEW_PROC;
} else {
spin_lock(&task_info->spinlock);
if ((task_info->status == TS_IGNORE) || (path_equal(&task_info->exe_path, &exe_path))) {
spin_unlock(&task_info->spinlock);
ret = CEC_WAS_NOT;
} else {
task_info->status = TS_GREY;
old_path = task_info->exe_path;
task_info->exe_path = exe_path;
path_get(&task_info->exe_path);
spin_unlock(&task_info->spinlock);
path_put(&old_path); // shouldn't call under spinlock, because might sleep
ret = CEC_WAS;
}
task_info_unref(task_info);
}
return ret;
}
static msg_t *heur_exec_msg_new(void)
{
struct path exe_path;
struct file *exe_file;
char *path_buf = NULL;
const char *path_start = NULL;
size_t path_size;
size_t exec_img_size;
size_t msg_img_size;
int ret;
msg_t *msg;
enum check_exec_code check_code;
pid_t ptgid = 0, ppid = 0;
pid_t tgid, pid;
tgid = current->tgid;
pid = current->pid;
if (TS_IGNORE == task_info_status_get(tgid)
|| (pid != tgid && TS_IGNORE == task_info_status_get(pid))) {
return NULL;
}
exe_file = get_task_exe_file_compat(current);
// Note: kernel's threads do not have 'exe_file'
if (!exe_file) {
return NULL;
}
path_get(&exe_file->f_path);
exe_path = exe_file->f_path;
fput(exe_file);
check_code = check_exec(tgid, exe_path);
if (check_code == CEC_WAS_NOT) {
path_put(&exe_path);
return NULL;
}
ret = path_to_string(&path_buf, &path_start, &exe_path);
path_put(&exe_path);
if (ret) {
return NULL;
}
if (current->real_parent) {
ptgid = current->real_parent->tgid;
ppid = current->real_parent->pid;
}
path_size = path_start ? strlen(path_start) + 1 : 0;
exec_img_size = sizeof(exec_img_t) + path_size;
msg_img_size = sizeof(msg_img_t) + exec_img_size;
msg = msg_new_type(msg_img_size, MT_EXEC);
if (msg) {
msg_img_t *msg_img = MSG_IMG(msg);
exec_img_t *exec_img = IMG_PAYLOAD(msg_img);
/*
* userspace kernel
* getpid() task->tgid
* gettid() task->pid
*/
exec_img->pid = tgid;
exec_img->tid = pid;
exec_img->ppid = ptgid;
exec_img->ptid = ppid;
exec_img->sure = check_code == CEC_WAS;
if (path_start) {
memcpy(exec_img->path, path_start, path_size);
}
}
mem_free(path_buf);
return msg;
}
static msg_sized_t* msg_varsized_init_type(msg_varsized_t *msg, size_t msg_img_size, return_type_t type) {
msg_sized_t* smsg = msg_varsized_init(msg, msg_img_size);
if (smsg) {
MSG_TYPE(smsg) = type;
}
return smsg;
}
int pid_info_return_msg_new(msg_varsized_t *msg, pid_t nr)
{
struct path exe_path;
struct pid *pid;
struct task_struct *task;
struct file *exe_file;
char *path_buf = NULL;
const char *path_start = NULL;
pid_t task_tgid;
pid_t task_pid;
size_t path_size;
size_t pid_info_img_size;
size_t msg_img_size;
msg_sized_t *smsg;
int ret;
pid = find_get_pid(nr);
task = get_pid_task(pid, PIDTYPE_PID);
put_pid(pid);
if (!task) {
WPRINTF("'%s(%i)' failure", "get_pid_task", nr);
ret = -ENOENT;
goto out;
}
task_tgid = task->tgid;
task_pid = task->pid;
exe_file = get_task_exe_file_compat(task);
put_task_struct(task);
// Note: kernel's threads do not have 'exe_file'
if (exe_file) {
path_get(&exe_file->f_path);
exe_path = exe_file->f_path;
fput(exe_file);
ret = path_to_string(&path_buf, &path_start, &exe_path);
path_put(&exe_path);
if (ret) {;
goto out;
}
}
path_size = path_start ? strlen(path_start) + 1 : 0;
pid_info_img_size = sizeof(pid_info_img_t) + path_size;
msg_img_size = sizeof(msg_img_t) + pid_info_img_size;
smsg = msg_varsized_init_type(msg, msg_img_size, RT_PID_INFO);
if (smsg) {
msg_img_t *msg_img = MSG_IMG(smsg);
pid_info_img_t *pid_info_img = IMG_PAYLOAD(msg_img);
/*
* userspace kernel
* getpid() task->tgid
* gettid() task->pid
*/
pid_info_img->pid = task_tgid;
pid_info_img->tid = task_pid;
if (path_start) {
memcpy(pid_info_img->path, path_start, path_size);
}
ret = 0;
} else {
ret = -ENOMEM;
}
mem_free(path_buf);
out:
return ret;
}
int fs_root_return_msg_new(msg_varsized_t *msg, pid_t nr)
{
int ret;
struct pid *pid;
struct task_struct *task;
struct path target_fs_root;
struct path current_fs_root;
char *path_buf = NULL;
const char *path_start = NULL;
size_t path_size;
size_t fs_root_img_size;
msg_sized_t *smsg;
size_t msg_img_size;
msg_img_t *msg_img;
fs_root_img_t *fs_root_img;
pid = find_get_pid(nr);
task = get_pid_task(pid, PIDTYPE_PID);
put_pid(pid);
if (!task) {
WPRINTF("'%s(%i)' failure", "get_pid_task", nr);
return -ENOENT;
}
if (!task->fs) {
WPRINTF("'task' %i without 'file system'", nr);
put_task_struct(task);
return -ENOENT;
}
get_fs_root(task->fs, &target_fs_root);
put_task_struct(task);
/*
* It is required that 'active_protection' is not chrooted - so, our
* root is global root.
*/
get_fs_root(current->fs, ¤t_fs_root);
// if (process is chroot'ed)
if ((target_fs_root.dentry != current_fs_root.dentry) ||
(target_fs_root.mnt != current_fs_root.mnt)) {
ret = path_to_string(&path_buf, &path_start, &target_fs_root);
if (ret) {
WPRINTF("'%s' failure, err = %d", "path_to_string", ret);
path_put(&target_fs_root);
path_put(¤t_fs_root);
return ret;
}
}
path_put(&target_fs_root);
path_put(¤t_fs_root);
path_size = path_start ? strlen(path_start) + 1 : 0;
fs_root_img_size = sizeof(fs_root_img_t) + path_size;
msg_img_size = sizeof(msg_img_t) + fs_root_img_size;
smsg = msg_varsized_init_type(msg, msg_img_size, RT_FS_ROOT);
if (!smsg) {
mem_free(path_buf);
return -ENOMEM;
}
msg_img = MSG_IMG(smsg);
fs_root_img = IMG_PAYLOAD(msg_img);
if (path_start)
memcpy(fs_root_img->fs_root, path_start, path_size);
mem_free(path_buf);
return 0;
}
int open_file_return_msg_new(msg_varsized_t *msg, int fd)
{
size_t msg_img_size;
msg_img_t *msg_img;
opened_file_img_t *open_file_img;
msg_sized_t *smsg;
msg_img_size = sizeof(msg_img_t) + sizeof(opened_file_img_t);
smsg = msg_varsized_init_type(msg, msg_img_size, RT_OPENED_FILE);
if (!smsg) {
return -ENOMEM;
}
msg_img = MSG_IMG(smsg);
open_file_img = IMG_PAYLOAD(msg_img);
open_file_img->fd = fd;
return 0;
}
int version_info_return_msg_new(msg_varsized_t *msg)
{
size_t msg_img_size;
msg_img_t *msg_img;
version_info_img_t *version_info_img;
msg_sized_t *smsg;
msg_img_size = sizeof(msg_img_t) + sizeof(version_info_img_t);
smsg = msg_varsized_init_type(msg, msg_img_size, RT_VERSION_INFO);
if (!smsg) {
return -ENOMEM;
}
msg_img = MSG_IMG(smsg);
version_info_img = IMG_PAYLOAD(msg_img);
version_info_img->max_action = AT_LAST;
version_info_img->features = DRIVER_FEATURE_CLOSE_EVENT;
return 0;
}
int data_queue_offsets_return_msg_new(msg_varsized_t *msg, uint32_t size)
{
size_t msg_img_size;
msg_img_t *msg_img;
data_queue_offsets_t *data_queue_offsets_img;
msg_sized_t *smsg;
msg_img_size = sizeof(msg_img_t) + sizeof(data_queue_offsets_t);
smsg = msg_varsized_init_type(msg, msg_img_size, RT_DATA_QUEUE_OFFSETS);
if (!smsg) {
return -ENOMEM;
}
msg_img = MSG_IMG(smsg);
data_queue_offsets_img = IMG_PAYLOAD(msg_img);
data_queue_offsets_img->size = size;
data_queue_offsets_img->headOff = offsetof(shared_data_queue_t, head);
data_queue_offsets_img->tailOff = offsetof(shared_data_queue_t, tail);
data_queue_offsets_img->entriesOff = offsetof(shared_data_queue_t, entries);
return 0;
}
// Checks pid's 'executable file' and sends 'exec' message in case of change.
// FIXME: move out of 'message.*'
void detect_exec(void)
{
send_msg_sync_unref(heur_exec_msg_new());
}