/
usr
/
src
/
file_protector-1.1-1507
/
transport
/
File Upload :
llllll
Current File: //usr/src/file_protector-1.1-1507/transport/fs_event.c
/** @file @brief File system events messages @details Copyright (c) 2017-2021 Acronis International GmbH @author Mikhail Krivtsov (mikhail.krivtsov@acronis.com) @since $Id: $ */ #include "fs_event.h" #include "compat.h" #include "debug.h" #include "memory.h" #include "message.h" #include "task_info_map.h" #include "transport.h" #include "transport_protocol.h" // 'linux/cred.h' appeared in 'stable/v2.6.27' #include <linux/fcntl.h> // for O_CREAT, etc. flags #include <linux/kernel.h> // for macroses such as 'ARRAY_SIZE' #include <linux/limits.h> // PATH_MAX // 'fs_event_img_t' accessors #define FSE_IMG_PID(fs_event_img) *(&(fs_event_img)->pid) #define FSE_IMG_TID(fs_event_img) *(&(fs_event_img)->tid) #define FSE_IMG_PAYLOAD(fs_event_img) (void *) (fs_event_img)->payload #define PATH_FILTERING_ENABLED // comment this #define to disable path filtering #ifdef PATH_FILTERING_ENABLED #define DEFINE_FILTER_MASK(path) {path, sizeof(path) - 1} typedef struct filter_mask { char *filter_mask_path; size_t filter_mask_len; } filter_mask_t; filter_mask_t filter_masks[] = { DEFINE_FILTER_MASK("/sys"), DEFINE_FILTER_MASK("/proc"), DEFINE_FILTER_MASK("/dev") }; #define FILTER_MASKS_NUMB ARRAY_SIZE(filter_masks) #endif // PATH_FILTERING_ENABLED static msg_t *fs_event_msg_new(msg_type_t msg_type, size_t payload_size) { msg_t *msg; size_t fs_event_img_size; size_t msg_img_size; DPRINTF("msg_type=%i/%s payload_size=%zu", msg_type, msg_type_to_string(msg_type), payload_size); fs_event_img_size = sizeof(fs_event_img_t) + payload_size; msg_img_size = sizeof(msg_img_t) + fs_event_img_size; msg = msg_new_type(msg_img_size, msg_type); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); /* * userspace kernel * getpid() current->tgid * gettid() current->pid */ fse_img->pid = current->tgid; fse_img->tid = current->pid; get_current_fsuid_fsgid_compat(&fse_img->fsuid, &fse_img->fsgid); } DPRINTF("msg=%p", msg); return msg; } #ifdef PATH_FILTERING_ENABLED /* * FIXME: This function is actually useless in case of relative path or any path * that contains "..", because we do not normalize paths, so arbitrary amount of * ".." can eventually point us to any file inside any directory. */ static bool is_path_filtered(const char *pathname) { size_t i = 0; for (i = 0; i < FILTER_MASKS_NUMB; i++) { // if 'path' is in 'filter_mask' folder (strncmp = 0) -> it is filtered if (((bool)strncmp(pathname, filter_masks[i].filter_mask_path, filter_masks[i].filter_mask_len)) == 0) { DPRINTF("pathname '%s' is filtered by filter_mask='%s'", pathname, filter_masks[i].filter_mask_path); return 1; } } DPRINTF("pathname '%s' isn't filtered by filter_masks", pathname); return 0; } #else static inline bool is_path_filtered(const char *pathname) { return 0; } #endif // PATH_FILTERING_ENABLED static inline bool is_msg_filtered(const char *pathname) { task_status_t status = task_info_status_get(current->tgid); if (TS_IGNORE == status) { DPRINTF("process has 'ignore' status"); return true; } if (TS_WHITE == status) { DPRINTF("process has 'white' status"); return true; } if (is_path_filtered(pathname)) { return true; } return false; } static msg_t *fs_rw_msg_new(msg_type_t msg_type, long ret_val, const char *pathname, unsigned int flags, loff_t offset, size_t count) { msg_t *msg; size_t path_size; size_t fs_event_rw_img_size; DPRINTF("msg_type=%i/%s ret_val=%ld pathname=%s " "flags=0o%o/0x%X offset=0x%llX/%lli count=%zu/0x%zX", msg_type, msg_type_to_string(msg_type), ret_val, pathname, flags, flags, (long long)offset, (long long)offset, count, count); if (is_msg_filtered(pathname)) { msg = NULL; goto out; } path_size = strlen(pathname) + 1; fs_event_rw_img_size = sizeof(fs_event_rw_img_t) + path_size; msg = fs_event_msg_new(msg_type, fs_event_rw_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_rw_img_t *rw_img = FSE_IMG_PAYLOAD(fse_img); rw_img->ret_val = ret_val; rw_img->flags = flags; rw_img->offset = offset; rw_img->count = count; memcpy(rw_img->path, pathname, path_size); } out: DPRINTF("msg=%p", msg); return msg; } static msg_t *fs_rw_ex_msg_new(msg_type_t msg_type, long ret_val, const char *pathname, const file_key_t* key, unsigned int flags, loff_t offset, size_t count) { msg_t *msg; size_t path_size; size_t fs_event_rw_img_size; DPRINTF("msg_type=%i/%s ret_val=%ld pathname=%s " "flags=0o%o/0x%X offset=0x%llX/%lli count=%zu/0x%zX", msg_type, msg_type_to_string(msg_type), ret_val, pathname, flags, flags, (long long)offset, (long long)offset, count, count); if (is_msg_filtered(pathname)) { msg = NULL; goto out; } path_size = strlen(pathname) + 1; fs_event_rw_img_size = sizeof(fs_event_rw_ex_img_t) + path_size; msg = fs_event_msg_new(msg_type, fs_event_rw_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_rw_ex_img_t *rw_img = FSE_IMG_PAYLOAD(fse_img); rw_img->ret_val = ret_val; rw_img->flags = flags; rw_img->offset = offset; rw_img->count = count; rw_img->key = *key; memcpy(rw_img->path, pathname, path_size); } out: DPRINTF("msg=%p", msg); return msg; } static msg_t *fs_rw_key_msg_new(msg_type_t msg_type, long ret_val, const file_key_t* key, unsigned int flags, loff_t offset, size_t count) { msg_t *msg; DPRINTF("msg_type=%i/%s ret_val=%ld " "flags=0o%o/0x%X offset=0x%llX/%lli count=%zu/0x%zX", msg_type, msg_type_to_string(msg_type), ret_val, flags, flags, (long long)offset, (long long)offset, count, count); msg = fs_event_msg_new(msg_type, sizeof(fs_event_rw_key_img_t)); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_rw_key_img_t *rw_img = FSE_IMG_PAYLOAD(fse_img); rw_img->ret_val = ret_val; rw_img->flags = flags; rw_img->offset = offset; rw_img->count = count; rw_img->key = *key; } DPRINTF("msg=%p", msg); return msg; } inline static msg_t *move_path_in_msg(msg_t *msg, struct path *path) { if (msg) { thread_safe_path_store_move_directly(&msg->path, path); } return msg; } inline static msg_t *copy_path_in_msg(msg_t *msg, const struct path *path) { if (msg) { thread_safe_path_store_copy_directly(&msg->path, path); } return msg; } inline static msg_t *move_path2_if_exists_in_msg(msg_t *msg, struct path *path) { if (msg && path) { thread_safe_path_store_move_directly(&msg->path2, path); } return msg; } inline static msg_t *fs_pre_create_msg_new(const char *pathname, const struct path *path) { /* man 2 creat: creat() is equivalent to open() with * flags equal to O_CREAT|O_WRONLY|O_TRUNC * * To faciliate userspace business logic optimisation, send this flags here. */ return copy_path_in_msg(fs_rw_msg_new(MT_FILE_PRE_CREATE, 0, pathname, O_CREAT | O_WRONLY | O_TRUNC, 0, 0), path); } inline static msg_t *fs_create_ex_msg_new(long ret_val, const char *pathname, const file_key_t* key, unsigned int flags) { return fs_rw_ex_msg_new(MT_FILE_CREATE_EX, ret_val, pathname, key, flags, 0, 0); } inline static msg_t *fs_pre_open_msg_new(const char *filename, unsigned int flags, const struct path *path) { return copy_path_in_msg(fs_rw_msg_new(MT_FILE_PRE_OPEN, 0, filename, flags, 0, 0), path); } inline static msg_t *fs_pre_open_ex_msg_new(const char *filename, const file_key_t* key, unsigned int flags, struct path *path) { return move_path_in_msg(fs_rw_ex_msg_new(MT_FILE_PRE_OPEN_EX, 0, filename, key, flags, 0, 0), path); } inline static msg_t *fs_pre_close_ex_msg_new(const char *filename, const file_key_t* key, unsigned int flags, const struct path *path) { return copy_path_in_msg(fs_rw_ex_msg_new(MT_FILE_PRE_CLOSE_EX, 0, filename, key, flags, 0, 0), path); } inline static msg_t *fs_pre_read_msg_new(const file_key_t* key, unsigned int f_flags, loff_t offset, size_t count) { return fs_rw_key_msg_new(MT_FILE_PRE_READ_EX, 0, key, f_flags, offset, count); } inline static msg_t *fs_pre_write_msg_new(const file_key_t* key, unsigned int f_flags, loff_t offset, size_t count, const struct path *path) { return copy_path_in_msg(fs_rw_key_msg_new(MT_FILE_PRE_WRITE_EX, 0, key, f_flags, offset, count), path); } static long send_msg_sync_unref_and_get_block(msg_t *msg) { long block = 0; if (msg) { send_msg_sync(msg); // If message was interrupted, the process was killed. // For the consistency, this means that syscall must be // blocked, otherwise APL might fail to backup. // Thankfully, process will not care about the // syscall result as it will be dead anyways. if (msg->block) block = -EPERM; if (msg->interrupted) block = -EINTR; thread_safe_path_clear(&msg->path); thread_safe_path_clear(&msg->path2); msg_unref(msg); } return block; } long fs_event_pre_create(const char *pathname, const struct path *path) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_CREATE)) { return send_msg_sync_unref_and_get_block(fs_pre_create_msg_new(pathname, path)); } else { return 0; } } void fs_event_create_ex(long ret_val, const char *pathname, const file_key_t* key, unsigned int flags) { if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_CREATE_EX)) { send_msg_sync_unref(fs_create_ex_msg_new(ret_val, pathname, key, flags)); } } long fs_event_pre_open(const char *filename, unsigned int flags, const struct path *path) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_OPEN)) { return send_msg_sync_unref_and_get_block(fs_pre_open_msg_new(filename, flags, path)); } else { return 0; } } long fs_event_pre_open_ex(const char *filename, const file_key_t* key, unsigned int flags, struct path *path) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_OPEN_EX)) { return send_msg_sync_unref_and_get_block(fs_pre_open_ex_msg_new(filename, key, flags, path)); } else { return 0; } } void fs_event_pre_close_ex(const char *filename, unsigned int flags, const struct path *path, const file_key_t* key) { detect_exec(); // TODO DK: This should be asynchronous but with 'reply'? // TODO DK: This is problematic with current 'thread_safe' path approach if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_CLOSE_EX)) { send_msg_sync_unref(fs_pre_close_ex_msg_new(filename, key, flags, path)); } } void fs_event_pre_read_ex(const file_key_t* key, unsigned int f_flags, loff_t offset, size_t count) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_READ_EX)) { return send_msg_async_unref(fs_pre_read_msg_new(key, f_flags, offset, count)); } else { return; } } long fs_event_pre_write_ex(const file_key_t* key, unsigned int f_flags, loff_t offset, size_t count, const struct path *path) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_FILE_PRE_WRITE_EX)) { return send_msg_sync_unref_and_get_block(fs_pre_write_msg_new(key, f_flags, offset, count, path)); } else { return 0; } } static inline int is_rename_msg_filtered(const char *oldname, const char *newname) { if (is_msg_filtered(oldname)) { return true; } if (newname && is_path_filtered(newname)) { return true; } return false; } static msg_t *fs_event_rename_msg_new_impl(msg_type_t msg_type, long ret_val, const char* oldname, const char* newname, unsigned int flags) { msg_t *msg; size_t oldname_size, newname_size; size_t fs_event_rename_img_size; DPRINTF("msg_type=%i/%s, ret_val=%ld, oldname = %s, " "newname = %s, " "flags = %u", msg_type, msg_type_to_string(msg_type), ret_val, oldname, newname, flags); if (is_rename_msg_filtered(oldname, newname)) { msg = NULL; goto out; } oldname_size = strlen(oldname) + 1; newname_size = strlen(newname) + 1; fs_event_rename_img_size = sizeof(fs_event_rename_img_t) + oldname_size + newname_size; msg = fs_event_msg_new(msg_type, fs_event_rename_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_rename_img_t *rename_img = FSE_IMG_PAYLOAD(fse_img); size_t newname_offset = oldname_size; rename_img->newname_offset = newname_offset; memcpy(rename_img->names, oldname, oldname_size); memcpy(rename_img->names + newname_offset, newname, newname_size); rename_img->ret_val = ret_val; rename_img->flags = flags; } out: DPRINTF("msg=%p", msg); return msg; } static msg_t *fs_event_rename_ex_msg_new_impl(msg_type_t msg_type, long ret_val, const char* oldname, const file_key_t* source_key, const char* newname, const file_key_t* target_key, unsigned int flags) { msg_t *msg; size_t oldname_size, newname_size; size_t fs_event_rename_img_size; DPRINTF("msg_type=%i/%s, ret_val=%ld, oldname = %s, " "newname = %s, " "flags = %u", msg_type, msg_type_to_string(msg_type), ret_val, oldname, newname, flags); if (is_rename_msg_filtered(oldname, newname)) { msg = NULL; goto out; } oldname_size = strlen(oldname) + 1; newname_size = newname ? strlen(newname) + 1 : 0; fs_event_rename_img_size = sizeof(fs_event_rename_ex_img_t) + oldname_size + newname_size; msg = fs_event_msg_new(msg_type, fs_event_rename_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_rename_ex_img_t *rename_img = FSE_IMG_PAYLOAD(fse_img); size_t newname_offset = oldname_size; rename_img->newname_offset = newname_offset; rename_img->source_key = *source_key; rename_img->target_exists = !!target_key; if (target_key) { rename_img->target_key = *target_key; } else { rename_img->target_key.ptr = 0; rename_img->target_key.ino = 0; rename_img->target_key.dev = 0; } memcpy(rename_img->names, oldname, oldname_size); if (newname) { memcpy(rename_img->names + newname_offset, newname, newname_size); } rename_img->ret_val = ret_val; rename_img->flags = flags; } out: DPRINTF("msg=%p", msg); return msg; } inline static msg_t *fs_event_pre_rename_ex_msg_new(const char* oldname, const file_key_t* source_key, const char* newname, const file_key_t* target_key, unsigned int flags, const struct path *oldpath, struct path *newpath) { return move_path2_if_exists_in_msg( copy_path_in_msg(fs_event_rename_ex_msg_new_impl(MT_PRE_RENAME_EX, 0, oldname, source_key, newname, target_key, flags), oldpath), newpath); } inline static msg_t *fs_event_rename_msg_new(long ret_val, const char* oldname, const char* newname, unsigned int flags) { return fs_event_rename_msg_new_impl(MT_RENAME, ret_val, oldname, newname, flags); } inline static msg_t *fs_event_rename_ex_msg_new(long ret_val, const char* oldname, const file_key_t* source_key, const char* newname, const file_key_t* target_key, unsigned int flags, struct path *oldpath) { return move_path_in_msg(fs_event_rename_ex_msg_new_impl(MT_RENAME_EX, ret_val, oldname, source_key, newname, target_key, flags), oldpath); } long fs_event_pre_rename_ex(const char* oldname, const file_key_t* source_key, const char* newname, const file_key_t* target_key, unsigned int flags, const struct path *oldpath, struct path *newpath) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_PRE_RENAME_EX)) { return send_msg_sync_unref_and_get_block( fs_event_pre_rename_ex_msg_new(oldname, source_key, newname, target_key, flags, oldpath, newpath)); } else { return 0; } } void fs_event_rename(long ret_val, const char* oldname, const char* newname, unsigned int flags) { if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_RENAME)) { send_msg_sync_unref(fs_event_rename_msg_new(ret_val, oldname, newname, flags)); } } void fs_event_rename_ex(long ret_val, const char* oldname, const file_key_t* source_key, const char* newname, const file_key_t* target_key, unsigned int flags, struct path *oldpath) { if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_RENAME_EX)) { send_msg_sync_unref(fs_event_rename_ex_msg_new(ret_val, oldname, source_key, newname, target_key, flags, oldpath)); } } static msg_t *fs_event_unlink_msg_new_impl(msg_type_t msg_type, long ret_val, const char *pathname, int flag) { msg_t *msg; size_t path_size; size_t fs_event_unlink_img_size; DPRINTF("msg_type=%i/%s, ret_val=%ld, pathname = %s, flag = %d", msg_type, msg_type_to_string(msg_type), ret_val, pathname, flag); if (is_msg_filtered(pathname)) { msg = NULL; goto out; } path_size = strlen(pathname) + 1; fs_event_unlink_img_size = sizeof(fs_event_unlink_img_t) + path_size; msg = fs_event_msg_new(msg_type, fs_event_unlink_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_unlink_img_t *unlink_img = FSE_IMG_PAYLOAD(fse_img); unlink_img->ret_val = ret_val; unlink_img->flag = flag; memcpy(unlink_img->path, pathname, path_size); } out: DPRINTF("msg=%p", msg); return msg; } static msg_t *fs_event_unlink_ex_msg_new_impl(msg_type_t msg_type, long ret_val, const char *pathname, const file_key_t *key, int flag) { msg_t *msg; size_t path_size; size_t fs_event_unlink_img_size; DPRINTF("msg_type=%i/%s, ret_val=%ld, pathname = %s, flag = %d", msg_type, msg_type_to_string(msg_type), ret_val, pathname, flag); if (is_msg_filtered(pathname)) { msg = NULL; goto out; } path_size = strlen(pathname) + 1; fs_event_unlink_img_size = sizeof(fs_event_unlink_ex_img_t) + path_size; msg = fs_event_msg_new(msg_type, fs_event_unlink_img_size); if (msg) { msg_img_t *msg_img = MSG_IMG(msg); fs_event_img_t *fse_img = IMG_PAYLOAD(msg_img); fs_event_unlink_ex_img_t *unlink_img = FSE_IMG_PAYLOAD(fse_img); unlink_img->ret_val = ret_val; unlink_img->flag = flag; unlink_img->key = *key; memcpy(unlink_img->path, pathname, path_size); } out: DPRINTF("msg=%p", msg); return msg; } inline static msg_t *fs_event_pre_unlink_ex_msg_new(const char *pathname, const file_key_t *key, int flag, struct path *path) { return move_path_in_msg(fs_event_unlink_ex_msg_new_impl(MT_PRE_UNLINK_EX, 0, pathname, key, flag), path); } inline static msg_t *fs_event_unlink_msg_new(long ret_val, const char* pathname, int flag) { return fs_event_unlink_msg_new_impl(MT_UNLINK, ret_val, pathname, flag); } inline static msg_t *fs_event_unlink_ex_msg_new(long ret_val, const char* pathname, const file_key_t *key, int flag) { return fs_event_unlink_ex_msg_new_impl(MT_UNLINK_EX, ret_val, pathname, key, flag); } long fs_event_pre_unlink_ex(const char* pathname, const file_key_t *key, int flag, struct path *path) { detect_exec(); if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_PRE_UNLINK_EX)) { return send_msg_sync_unref_and_get_block(fs_event_pre_unlink_ex_msg_new(pathname, key, flag, path)); } else { return 0; } } void fs_event_unlink(long ret_val, const char* pathname, int flag) { if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_UNLINK)) { send_msg_sync_unref(fs_event_unlink_msg_new(ret_val, pathname, flag)); } } void fs_event_unlink_ex(long ret_val, const char* pathname, const file_key_t* key, int flag) { if (transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(MT_UNLINK_EX)) { send_msg_sync_unref(fs_event_unlink_ex_msg_new(ret_val, pathname, key, flag)); } }
Copyright ©2k19 -
Hexid
|
Tex7ure