shell bypass 403
/** @file fsnotify_events.h @brief fsnotify events @details Copyright (c) 2024 Acronis International GmbH @author Denis Kopyrin ([email protected]) @since $Id: $ */ #include "fsnotify_events.h" #include <linux/fsnotify.h> #include <linux/fsnotify_backend.h> #include "fs_event.h" #include "lsm_common.h" #include "path_tools.h" #include "task_info_map.h" #include "task_tools.h" #if defined(FS_IN_ISDIR) && !defined(FS_ISDIR) #define FS_ISDIR FS_IN_ISDIR #endif static void send_fsnotify_event(struct dentry* dentry, struct inode* inode, const void* dentry_name_ptr, uint64_t flags) { task_info_t* task_info; transport_ids_t transport_ids; msg_type_t type; file_key_t key; bool always_send = false; if (flags & FS_CREATE) { type = FP_SI_OT_NOTIFY_FSNOTIFY_CREATE; always_send = true; } if (flags & (FS_DELETE | FS_DELETE_SELF)) { type = FP_SI_OT_NOTIFY_FSNOTIFY_UNLINK; always_send = true; } if (flags & FS_MOVE_SELF) type = FP_SI_OT_NOTIFY_FSNOTIFY_RENAME; if (flags & FS_OPEN) type = FP_SI_OT_NOTIFY_FSNOTIFY_OPEN; if (flags & FS_MODIFY) type = FP_SI_OT_NOTIFY_FSNOTIFY_MODIFY; if (!(transport_global_get_combined_mask() & MSG_TYPE_TO_EVENT_MASK(type))) return; if (!always_send && transport_process_belongs_to_control(current)) return; task_info = task_info_map_get(current); if (!task_info) return; if (!always_send) { transport_global_get_ids(&transport_ids); if (task_info_can_skip(task_info, &transport_ids, MSG_TYPE_TO_EVENT_MASK(type))) goto out; } if (((FS_CREATE | FS_ISDIR) & flags) == (FS_CREATE | FS_ISDIR)) { fs_event_fsnotify_mkdir(task_info, inode, dentry, dentry ? dentry->d_name.name : dentry_name_ptr, flags, type, fs_generic_subtype(inode)); } else { make_key_from_inode(&key, inode); fs_event_fsnotify(task_info, &key, flags, type, fs_generic_subtype(inode)); } out: task_info_put(task_info); } struct fsnotify_target { struct inode *inode; struct dentry *dentry; }; static struct fsnotify_target fsnotify_event_handler_target(const void *data, int data_type) { struct fsnotify_target target = (struct fsnotify_target){ 0 }; if (!data) return target; switch (data_type) { case FSNOTIFY_EVENT_PATH: { struct path *path = (struct path *)data; struct dentry* dentry = path->dentry; if (dentry) { target.inode = dentry->d_inode; target.dentry = dentry; } break; } case FSNOTIFY_EVENT_INODE: { target.inode = (struct inode *)data; break; } #ifdef HAVE_FSNOTIFY_EVENT_DENTRY case FSNOTIFY_EVENT_DENTRY: { struct dentry *dentry = (struct dentry *)data; target.dentry = dentry; if (dentry) target.inode = dentry->d_inode; break; } #endif default: break; } return target; } static void pre_close(const struct path *path, bool modified) { task_info_t* task_info; transport_ids_t transport_ids; int flags = modified ? O_RDWR : O_RDONLY; const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_SYNC_FILE_PRE_CLOSE) | MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_FILE_PRE_CLOSE); subtypes_t subtypes; if (!path_is_usable(path)) return; if (!(transport_global_get_combined_mask() & generatedEventsMask)) return; subtypes = fs_close_subtypes(modified, path->dentry->d_inode); if (!transport_global_subtype_needed(subtypes.sync) && !transport_global_subtype_needed(subtypes.notify)) return; if (transport_process_belongs_to_control(current)) return; task_info = task_info_map_get(current); if (!task_info) return; transport_global_get_ids(&transport_ids); refresh_task(task_info, &transport_ids); if (task_info_can_skip(task_info, &transport_ids, generatedEventsMask)) goto err_skipped; if (!path_is_valid(path)) goto err_skipped; DPRINTF("calling fs_event_pre_close(flags=0o%o/0x%x)", flags, flags); fs_event_pre_close(task_info, flags, path); DPRINTF("finished fs_event_pre_close(flags=0o%o/0x%x)", flags, flags); err_skipped: task_info_put(task_info); } static void add_file_modify_cache_for_pre_close(const struct inode *inode) { task_info_t *task_info; transport_ids_t transport_ids; file_context_info_t info = {0}; const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_SYNC_FILE_PRE_CLOSE) | MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_FILE_PRE_CLOSE); if (!(transport_global_get_combined_mask() & generatedEventsMask)) return; if (transport_process_belongs_to_control(current)) return; task_info = task_info_map_get(current); if (!task_info) return; transport_global_get_ids(&transport_ids); refresh_task(task_info, &transport_ids); if (!task_info_can_skip(task_info, &transport_ids, generatedEventsMask)) { make_file_context_info_with_inode(&info, inode, make_unique_pid(current)); add_file_modify_cache(&info); } task_info_put(task_info); } void handle_fsnotify_event(u32 mask, const void *data, int data_type, const void* dentry_name_ptr) { struct fsnotify_target target; uint32_t want_mask; if (data_type == FSNOTIFY_EVENT_PATH && (mask & (FS_CLOSE_NOWRITE | FS_CLOSE_WRITE))) { const struct path *path = (const struct path *)data; return pre_close(path, (mask & FS_CLOSE_WRITE) != 0); } want_mask = wanted_fsnotify_events(); if (!(mask & want_mask)) return; target = fsnotify_event_handler_target(data, data_type); if (!inode_is_valid(target.inode)) return; if (mask & FS_MODIFY) { add_file_modify_cache_for_pre_close(target.inode); } send_fsnotify_event(target.dentry, target.inode, dentry_name_ptr, mask); if (mask & (FS_DELETE_SELF | FS_CREATE)) { file_key_t key; make_key_from_inode(&key, target.inode); remove_common_cache_all(&key); } }