/
usr
/
src
/
file_protector-1.1-1497
/
transport
/
File Upload :
llllll
Current File: //usr/src/file_protector-1.1-1497/transport/message.c
/** @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(PING); CASE_MT_RETURN(PONG); CASE_MT_RETURN(PID_SET_ST); CASE_MT_RETURN(PID_DEL); CASE_MT_RETURN(GET_PID_INFO); CASE_MT_RETURN(PID_INFO); CASE_MT_RETURN(GET_FS_ROOT); CASE_MT_RETURN(FS_ROOT); 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); 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_interruptible_sync(&msg->wait_queue); } msg_unref(msg); } 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; 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 *ping_reply_msg_new(msg_t *ping_msg) { static const char reply[] = "reply"; size_t ping_reply_img_size = sizeof(ping_reply_img_t) + sizeof(reply); size_t msg_img_size = sizeof(msg_img_t) + ping_reply_img_size; msg_t *msg = msg_new_type(msg_img_size, MT_PING); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); ping_reply_img_t *ping_reply_img = IMG_PAYLOAD(msg_img); memcpy(ping_reply_img->reply, reply, sizeof(reply)); } DPRINTF("msg=%p", msg); return msg; } // assuming correct 'ping_msg' msg_t *pong_msg_new(msg_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(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; } int pid_info_msg_new(msg_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; 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(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; *msg = msg_new_type(msg_img_size, MT_PID_INFO); if (*msg) { msg_img_t *msg_img = MSG_IMG(*msg); 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_msg_new(msg_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; 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; *msg = msg_new_type(msg_img_size, MT_FS_ROOT); if (*msg == NULL) { mem_free(path_buf); return -ENOMEM; } msg_img = MSG_IMG(*msg); 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; } // 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()); }
Copyright ©2k19 -
Hexid
|
Tex7ure