shell bypass 403
/** @file @brief File system events messages @details Copyright (c) 2017-2021 Acronis International GmbH @author Mikhail Krivtsov ([email protected]) @since $Id: $ */ #include "fs_event.h" #include "compat.h" #include "debug.h" #include "file_path_tools.h" #include "memory.h" #include "message.h" #include "path_tools.h" #include "task_info_map.h" #include "transport.h" #include "transport_protocol.h" #include "si_templates.h" #include "si_writer.h" #include "si_writer_common.h" // 'linux/cred.h' appeared in 'stable/v2.6.27' #include <linux/fcntl.h> // for O_CREAT, etc. flags #include <linux/fsnotify.h> #include <linux/kernel.h> // for macroses such as 'ARRAY_SIZE' #include <linux/limits.h> // PATH_MAX #include <linux/mman.h> #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 #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 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 *copy_file_context_msg_info_in_msg(msg_t *msg, const file_context_msg_info_t *info) { if (msg) { msg->file_context_msg_info = *info; } return msg; } static long send_msg_sync_and_get_block(msg_t *msg) { long block = 0; // Currently special files sending is not done synchronously. if (msg->subtype_mask & MSG_TYPE_TO_EVENT_MASK(FP_SI_ST_SPECIAL)) return 0; 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); return block; } static long send_msg_sync_unref_and_get_block(msg_t *msg) { long block; if (!msg) return 0; block = send_msg_sync_and_get_block(msg); msg_unref(msg); return block; } static inline void si_property_writer_write_object_key(si_property_writer_t *writer, const file_key_t* key) { SiObjectId object_id; object_id.DeviceId = key->dev; object_id.Id = key->ino; si_property_writer_write_object_id(writer, object_id); si_property_writer_write_object_file_generation(writer, key->gen); // TODO: This pointer should be hidden from userspace! si_property_writer_write_object_file_ptr(writer, key->ptr); } static const uint8_t k_object_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_FILE_FIELDS }; void fs_event_create(task_info_t* task_info, const struct path *path) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info; if (path_info_make_from_valid(&path_info, path)) return; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_object_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_NOTIFY_FILE_CREATE, 0, SI_CT_POST_CALLBACK, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_async_unref(msg); } static const uint8_t k_mkdir_fields[] = { SI_COMMON_FS_FIELDS , FP_SI_PI_OBJECT_NAME , FP_SI_PI_ACCESS_MODE , FP_SI_PI_OBJECT_FILE_DENTRY_PTR , FP_SI_PI_OBJECT_FILE_DENTRY_NAME_PTR }; void fs_event_mkdir(task_info_t* task_info, const struct path *path, umode_t mode) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; if (path_info_make(&path_info, path, true /*dir*/)) return; if (is_path_filtered(path_info.str.value)) goto end; event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_mkdir_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info); msg = msg_new(FP_SI_OT_NOTIFY_FILE_MKDIR, 0, SI_CT_PRE_CALLBACK, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); if (path_info.buf) { si_property_writer_write_object_name(&writer, path_info.str); } si_property_writer_write_access_mode(&writer, mode); si_property_writer_write_object_file_dentry_ptr(&writer, (uint64_t) path->dentry); si_property_writer_write_object_file_dentry_name_ptr(&writer, (uint64_t) path->dentry->d_name.name); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); end: path_info_free(&path_info); return send_msg_async_unref(msg); } static const uint8_t k_object_to_target_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_FILE_FIELDS, FP_SI_PI_TARGET_NAME }; void fs_event_pre_copyfile(task_info_t* task, const struct path *from, const struct path *to) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t from_path_info = (path_info_t){}; path_info_t to_path_info = (path_info_t){}; file_handle_info_t from_handle_info = (file_handle_info_t){}; if (path_info_make_from_valid(&from_path_info, from)) goto end; if (path_info_make(&to_path_info, to, false /*dir*/)) goto end; if (is_path_filtered(from_path_info.str.value) || is_path_filtered(to_path_info.str.value)) goto end; file_handle_info_make(&from_handle_info, from); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_object_to_target_fields) + SI_ESTIMATE_SIZE_PATH_INFO(from_path_info) + SI_ESTIMATE_SIZE_PATH_INFO(to_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(from_handle_info); msg = msg_new(FP_SI_OT_NOTIFY_FILE_COPY, 0, SI_CT_PRE_CALLBACK, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &from_path_info, from, &from_handle_info); si_property_writer_write_target_name(&writer, to_path_info.str); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task); end: path_info_free(&from_path_info); path_info_free(&to_path_info); file_handle_info_free(&from_handle_info); return send_msg_async_unref(msg); } static void msg_relabel(msg_t* msg, uint16_t ot, SUBTYPE_MASK_TYPE st, uint16_t ct) { msg->subtype_mask = st; msg->event.Operation = ot; msg->event.CallbackType = ct; } static long send_msg_sync_and_get_block_then_relabel_send_async(msg_t* msg, uint16_t notifyOt, SUBTYPE_MASK_TYPE notifySubType, uint16_t notifyCt) { long block = send_msg_sync_and_get_block(msg); if (!block) { // Play the same message but asynchronously msg_relabel(msg, notifyOt, notifySubType, notifyCt); send_msg_async(msg); } return block; } static long send_msg_sync_and_get_block_then_relabel_send_async_unref(msg_t* msg, uint16_t notifyOp, SUBTYPE_MASK_TYPE notifySubType, uint16_t notifyCt) { long block; if (!msg) { return 0; } block = send_msg_sync_and_get_block_then_relabel_send_async(msg, notifyOp, notifySubType, notifyCt); msg_unref(msg); return block; } static const uint8_t k_open_close_fields[] = { SI_COMMON_FS_FIELDS , SI_COMMON_OBJECT_FILE_FIELDS , FP_SI_PI_ACCESS_MODE , FP_SI_PI_FILE_MODIFIED }; long fs_event_pre_open(task_info_t* task_info, unsigned int flags, const struct path *path, const file_context_msg_info_t *info) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info; subtypes_t subtypes = fs_open_subtypes(flags, path->dentry->d_inode); if (path_info_make_from_valid(&path_info, path)) return 0; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_open_close_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_OPEN , (SUBTYPE_MASK_TYPE) subtypes.sync , FP_SI_CT_WANT_REPLY , unique_pid , event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_property_writer_write_access_mode(&writer, flags); si_event_writer_finalize(&msg->event, &writer); } copy_file_context_msg_info_in_msg(msg, info); msg->task_info = task_info_get(task_info); msg->id = event_uid; msg->open.pid_version = task_info->pid_version; msg->open.flags = (int) flags; copy_path_in_msg(msg, path); end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg , FP_SI_OT_NOTIFY_FILE_PRE_OPEN , (SUBTYPE_MASK_TYPE) subtypes.notify , SI_CT_PRE_CALLBACK); } static const uint8_t k_fs_mmap_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_FILE_FIELDS, FP_SI_PI_ACCESS_MODE, FP_SI_PI_FLAGS, FP_SI_PI_PROTECTION }; long fs_event_pre_mmap(task_info_t* task_info, unsigned int acc_mode, const struct path *path, unsigned long reqprot, unsigned long prot, unsigned long mmap_flags) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info = (file_handle_info_t){}; bool writable = (mmap_flags & MAP_SHARED) && (prot & PROT_WRITE); subtypes_t subtypes = fs_mmap_subtypes(writable, path->dentry->d_inode); (void) reqprot; if (path_info_make_from_valid(&path_info, path)) return 0; if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fs_mmap_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_MMAP , (SUBTYPE_MASK_TYPE) subtypes.sync , FP_SI_CT_WANT_REPLY , unique_pid , event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_property_writer_write_access_mode(&writer, acc_mode); si_property_writer_write_flags(&writer, mmap_flags); si_property_writer_write_protection(&writer, prot); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); msg->id = event_uid; copy_path_in_msg(msg, path); end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg , FP_SI_OT_NOTIFY_FILE_PRE_MMAP , (SUBTYPE_MASK_TYPE) subtypes.notify , SI_CT_PRE_CALLBACK); } void fs_event_pre_close(task_info_t* task_info, unsigned int flags, const struct path *path) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info = (file_handle_info_t){}; subtypes_t subtypes = fs_close_subtypes(flags & (O_WRONLY | O_RDWR), path->dentry->d_inode); bool file_modified = false; file_context_info_t info = {0}; make_file_context_info_with_inode(&info, path->dentry->d_inode, make_unique_pid(current)); // file is modified by this process if (check_update_file_modify_cache(&info)) { file_modified = true; } file_handle_info_init_empty(&handle_info); if (path_info_make_from_valid(&path_info, path)) return; if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_open_close_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_CLOSE , (SUBTYPE_MASK_TYPE) subtypes.sync , FP_SI_CT_WANT_REPLY , unique_pid , event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_property_writer_write_access_mode(&writer, flags); si_property_writer_write_file_modified(&writer, file_modified); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; copy_path_in_msg(msg, path); msg->task_info = task_info_get(task_info); end: path_info_free(&path_info); file_handle_info_free(&handle_info); // TODO DK: This should be asynchronous but with 'reply'? // TODO DK: This is problematic with current 'thread_safe' path approach return (void) send_msg_sync_and_get_block_then_relabel_send_async_unref(msg , FP_SI_OT_NOTIFY_FILE_PRE_CLOSE , (SUBTYPE_MASK_TYPE) subtypes.notify , SI_CT_PRE_CALLBACK); } static const uint8_t k_fs_rw_mini_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_MINI_FILE_FIELDS, FP_SI_PI_OBJECT_REGION, FP_SI_PI_ACCESS_MODE }; void fs_event_pre_full_read(task_info_t* task_info, const file_key_t* key, unsigned int f_flags, loff_t offset, size_t count) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; const uint32_t event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fs_rw_mini_fields); msg_t *msg = NULL; SiRegion region; msg = msg_new(FP_SI_OT_NOTIFY_FILE_FULL_READ, 0, SI_CT_PRE_CALLBACK, unique_pid, event_size); if (!msg) return; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_key(&writer, key); si_property_writer_write_access_mode(&writer, f_flags); region.Start = offset; region.Length = count; si_property_writer_write_object_region(&writer, region); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; msg->task_info = task_info_get(task_info); return send_msg_async_unref(msg); } long fs_event_pre_write(task_info_t* task_info, unsigned int f_flags, loff_t offset, size_t count, const struct path *path, const file_context_msg_info_t *info) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; const uint32_t event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fs_rw_mini_fields); msg_t *msg = NULL; msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_WRITE, fs_generic_subtype(path->dentry->d_inode), FP_SI_CT_WANT_REPLY, unique_pid, event_size); if (!msg) return 0; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; SiRegion region; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_mini_ids(&writer, path->dentry->d_inode); si_property_writer_write_access_mode(&writer, f_flags); region.Start = offset; region.Length = count; si_property_writer_write_object_region(&writer, region); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; msg->write.pid_version = task_info->pid_version; msg->write.flags = (int) f_flags; msg->write.low = (uint64_t) offset; msg->write.high = (uint64_t) offset + (uint64_t) count; copy_path_in_msg(msg, path); copy_file_context_msg_info_in_msg(msg, info); msg->task_info = task_info_get(task_info); return send_msg_sync_unref_and_get_block(msg); } static const uint8_t k_fs_rename_fields[] = { SI_COMMON_FS_FIELDS , SI_COMMON_OBJECT_FILE_FIELDS , SI_COMMON_TARGET_FILE_FIELDS , FP_SI_PI_FLAGS , FP_SI_PI_TARGET_EXISTS }; long fs_event_pre_rename(task_info_t *task_info, unsigned int flags, const struct path *oldpath, const struct path *newpath, bool target_exists) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t old_path_info = (path_info_t){}; path_info_t new_path_info = (path_info_t){}; file_handle_info_t old_handle_info = (file_handle_info_t){}; file_handle_info_t new_handle_info = (file_handle_info_t){}; const struct inode* oldinode = oldpath->dentry->d_inode; bool dir = S_ISDIR(oldinode->i_mode); bool oldspecial = !S_ISDIR(oldinode->i_mode) && !S_ISREG(oldinode->i_mode); bool newspecial = true; uint64_t subtype = 0; if (path_info_make(&old_path_info, oldpath, dir)) return 0; if (is_path_filtered(old_path_info.str.value)) goto end; if (newpath) { if (path_info_make(&new_path_info, newpath, dir)) goto end; if (is_path_filtered(new_path_info.str.value)) goto end; } if (target_exists) { const struct inode* newinode = newpath->dentry->d_inode; newspecial = !S_ISDIR(newinode->i_mode) && !S_ISREG(newinode->i_mode); } subtype = (!oldspecial || !newspecial) ? 0 : MSG_TYPE_TO_EVENT_MASK(FP_SI_ST_SPECIAL); file_handle_info_make(&old_handle_info, oldpath); if (newpath) file_handle_info_make(&new_handle_info, newpath); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fs_rename_fields) + SI_ESTIMATE_SIZE_PATH_INFO(old_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(old_handle_info); if (newpath) { event_size += SI_ESTIMATE_SIZE_PATH_INFO(new_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(new_handle_info); } msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_RENAME, subtype, FP_SI_CT_WANT_REPLY, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &old_path_info, oldpath, &old_handle_info); if (newpath) si_property_writer_write_target_file(&writer, &new_path_info, newpath, &new_handle_info); si_property_writer_write_flags(&writer, flags); si_property_writer_write_target_exists(&writer, target_exists); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; copy_path_in_msg(msg, oldpath); if (target_exists && newpath) { thread_safe_path_store_copy_directly(&msg->path2, newpath); } msg->task_info = task_info_get(task_info); end: path_info_free(&old_path_info); path_info_free(&new_path_info); file_handle_info_free(&old_handle_info); file_handle_info_free(&new_handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg, FP_SI_OT_NOTIFY_FILE_PRE_RENAME, subtype, SI_CT_PRE_CALLBACK); } long fs_event_pre_link(task_info_t *task_info, const struct path *oldpath, const struct path *newpath) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t old_path_info = (path_info_t){}; path_info_t new_path_info = (path_info_t){}; file_handle_info_t old_handle_info = (file_handle_info_t){}; const struct inode* inode = oldpath->dentry->d_inode; // This should never be 'true' but just in case bool dir = S_ISDIR(inode->i_mode); SUBTYPE_MASK_TYPE subtype = fs_generic_subtype(inode); if (path_info_make(&old_path_info, oldpath, dir)) return 0; if (is_path_filtered(old_path_info.str.value)) goto end; if (path_info_make(&new_path_info, newpath, dir)) goto end; if (is_path_filtered(new_path_info.str.value)) goto end; file_handle_info_make(&old_handle_info, oldpath); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_object_to_target_fields) + SI_ESTIMATE_SIZE_PATH_INFO(old_path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(old_handle_info) + SI_ESTIMATE_SIZE_PATH_INFO(new_path_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_LINK, subtype, FP_SI_CT_WANT_REPLY, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &old_path_info, oldpath, &old_handle_info); if (new_path_info.buf) si_property_writer_write_target_name(&writer, new_path_info.str); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; copy_path_in_msg(msg, oldpath); msg->task_info = task_info_get(task_info); end: path_info_free(&old_path_info); path_info_free(&new_path_info); file_handle_info_free(&old_handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg, FP_SI_OT_NOTIFY_FILE_PRE_LINK, subtype, SI_CT_PRE_CALLBACK); } static const uint8_t k_fs_fsnotify_rename_fields[] = { SI_COMMON_FS_FIELDS , SI_COMMON_OBJECT_MINI_FILE_FIELDS , FP_SI_PI_FLAGS , FP_SI_PI_TARGET_NAME }; void fs_event_rename(task_info_t *task_info, const struct path *path, bool is_newpath_ok) { path_info_t path_info = (path_info_t){}; msg_t *msg = NULL; uint32_t event_size; uint64_t event_uid; uint64_t subtype = fs_generic_subtype(path->dentry->d_inode); // path is sent in msg only if newpath was not ok - that's because on syscall pre-rename target path is missing bool want_path = !is_newpath_ok; if (want_path) { // newpath was not ok so we need to add properties for post rename'd file. Notably we are interested in making a target_name if (path_info_make_from_valid(&path_info, path)) return; if (is_path_filtered(path_info.str.value)) goto end; } event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fs_fsnotify_rename_fields); if (want_path) event_size += SI_ESTIMATE_SIZE_PATH_INFO(path_info); msg = msg_new(FP_SI_OT_SYNC_FILE_RENAME, subtype, FP_SI_CT_WANT_REPLY, make_unique_pid(current), event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_object_mini_ids(&writer, path->dentry->d_inode); si_property_writer_write_flags(&writer, FS_MOVE_SELF); if (want_path) si_property_writer_write_target_name(&writer, path_info.str); si_event_writer_finalize(&msg->event, &writer); } copy_path_in_msg(msg, path); msg->id = event_uid; msg->task_info = task_info_get(task_info); end: path_info_free(&path_info); return (void) send_msg_sync_and_get_block_then_relabel_send_async_unref(msg, FP_SI_OT_NOTIFY_FSNOTIFY_RENAME, subtype, SI_CT_POST_CALLBACK); } long fs_event_pre_unlink(task_info_t* task_info, const struct path *path) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; uint64_t subtype = fs_generic_subtype(path->dentry->d_inode); path_info_t path_info; file_handle_info_t handle_info; if (path_info_make_from_valid(&path_info, path)) return 0; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_object_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_UNLINK, subtype, FP_SI_CT_WANT_REPLY, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; copy_path_in_msg(msg, path); msg->task_info = task_info_get(task_info); end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg, FP_SI_OT_NOTIFY_FILE_PRE_UNLINK, subtype, SI_CT_PRE_CALLBACK); } long fs_event_pre_truncate(task_info_t* task_info, const struct path *path) { uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info; uint64_t subtype = fs_generic_subtype(path->dentry->d_inode); if (path_info_make_from_valid(&path_info, path)) return 0; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_object_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_SYNC_FILE_PRE_TRUNCATE, subtype, FP_SI_CT_WANT_REPLY, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); msg->id = event_uid; copy_path_in_msg(msg, path); end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_sync_and_get_block_then_relabel_send_async_unref(msg, FP_SI_OT_NOTIFY_FILE_PRE_TRUNCATE, subtype, SI_CT_PRE_CALLBACK); } void fs_event_pre_chmod(task_info_t *task_info, const struct path *path, umode_t mode) { static const uint8_t k_chmod_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_FILE_FIELDS, FP_SI_PI_ACCESS_MODE }; uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info; uint64_t subtype = fs_generic_subtype(path->dentry->d_inode); if (path_info_make_from_valid(&path_info, path)) return; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_chmod_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_NOTIFY_FILE_CHMOD, subtype, SI_CT_PRE_CALLBACK, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_property_writer_write_access_mode(&writer, mode); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); msg->id = event_uid; end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_async_unref(msg); } void fs_event_pre_chown(task_info_t *task_info, const struct path *path, uid_t uid, gid_t gid) { static const uint8_t k_chown_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_FILE_FIELDS, FP_SI_PI_USER_ID, FP_SI_PI_GROUP_ID }; uint64_t unique_pid = make_unique_pid(current); uint64_t event_uid; uint32_t event_size; msg_t *msg = NULL; path_info_t path_info; file_handle_info_t handle_info; uint64_t subtype = fs_generic_subtype(path->dentry->d_inode); if (path_info_make_from_valid(&path_info, path)) return; file_handle_info_init_empty(&handle_info); if (is_path_filtered(path_info.str.value)) goto end; file_handle_info_make(&handle_info, path); event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_chown_fields) + SI_ESTIMATE_SIZE_PATH_INFO(path_info) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(FP_SI_OT_NOTIFY_FILE_CHOWN, subtype, SI_CT_PRE_CALLBACK, unique_pid, event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_fsids(&writer); si_property_writer_write_object_file_and_volume(&writer, &path_info, path, &handle_info); si_property_writer_write_user_id(&writer, uid); si_property_writer_write_group_id(&writer, gid); si_event_writer_finalize(&msg->event, &writer); } msg->task_info = task_info_get(task_info); msg->id = event_uid; end: path_info_free(&path_info); file_handle_info_free(&handle_info); return send_msg_async_unref(msg); } static const uint8_t k_fsnotify_fields[] = { SI_COMMON_FS_FIELDS, SI_COMMON_OBJECT_MINI_FILE_FIELDS, FP_SI_PI_FLAGS }; void fs_event_fsnotify(task_info_t *task_info, const file_key_t* key, uint64_t flags, msg_type_t type, uint64_t subtype) { msg_t *msg = NULL; const uint32_t event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fsnotify_fields); uint64_t event_uid; msg = msg_new(type, subtype, SI_CT_POST_CALLBACK, make_unique_pid(current), event_size); if (!msg) return; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); si_property_writer_write_object_key(&writer, key); si_property_writer_write_flags(&writer, flags); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; msg->task_info = task_info_get(task_info); send_msg_async(msg); msg_unref(msg); } static const uint8_t k_fsnotify_mkdir_fields[] = { SI_COMMON_FS_FIELDS , SI_COMMON_OBJECT_FILE_IDS_FIELDS , FP_SI_PI_OBJECT_FILE_DENTRY_PTR , FP_SI_PI_OBJECT_FILE_DENTRY_NAME_PTR , FP_SI_PI_FLAGS }; void fs_event_fsnotify_mkdir(task_info_t *task_info , const struct inode* inode , struct dentry* dentry , const void* dentry_name_ptr , uint64_t flags , msg_type_t type , uint64_t subtype) { msg_t *msg = NULL; uint32_t event_size; uint64_t event_uid; file_handle_info_t handle_info = (file_handle_info_t){}; // Mind that this path is not real - at best we can use it to extract file handle if (dentry) { struct path path = (struct path){}; path.dentry = dentry; file_handle_info_make(&handle_info, &path); } event_size = SI_ESTIMATE_SIZE_CONST_PARAMS(k_fsnotify_mkdir_fields) + SI_ESTIMATE_SIZE_FILE_HANDLE_INFO(handle_info); msg = msg_new(type, subtype, SI_CT_POST_CALLBACK, make_unique_pid(current), event_size); if (!msg) goto end; event_uid = transport_global_sequence_next(); { si_property_writer_t writer; si_event_writer_init(&writer, &msg->event, event_size); si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info); // This function is a simplified version of si_property_writer_write_object_ids but without 'mnt' handling // It affected 'stat' collection primarily that requires proper 'mnt' + 'mount_id' collection si_property_writer_write_object_file_attributes(&writer, inode->i_flags); si_property_writer_write_object_mini_ids(&writer, inode); si_property_writer_write_object_stat(&writer, inode); si_property_writer_write_volume(&writer, inode); if (handle_info.f_handle) si_property_writer_write_object_file_handle(&writer, &handle_info); if (dentry) si_property_writer_write_object_file_dentry_ptr(&writer, (uint64_t) dentry); si_property_writer_write_object_file_dentry_name_ptr(&writer, (uint64_t) dentry_name_ptr); si_property_writer_write_flags(&writer, flags); si_event_writer_finalize(&msg->event, &writer); } msg->id = event_uid; msg->task_info = task_info_get(task_info); end: file_handle_info_free(&handle_info); return send_msg_async_unref(msg); }