PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
| Dir : /usr/src/file_protector-1.1-1592/ftrace_hooks/ |
| Server: Linux ituca148.hostpapavps.net 4.18.0-553.141.2.el8_10.x86_64 #1 SMP Wed Jul 8 10:28:18 EDT 2026 x86_64 IP: 216.7.89.187 |
| Dir : //usr/src/file_protector-1.1-1592/ftrace_hooks/fsnotify_events.c |
/**
@file fsnotify_events.h
@brief fsnotify events
@details Copyright (c) 2024 Acronis International GmbH
@author Denis Kopyrin (denis.kopyrin@acronis.com)
@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;
uint64_t generatedEventsMask = 0;
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;
generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(type);
if (!(transport_global_get_combined_mask() & generatedEventsMask))
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, generatedEventsMask);
if (task_info_can_skip(task_info, &transport_ids, generatedEventsMask))
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, generatedEventsMask);
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;
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, generatedEventsMask);
refresh_task(task_info, &transport_ids);
if (!task_info_can_skip(task_info, &transport_ids, generatedEventsMask))
{
file_context_add_cache_request_t info = {0};
// !!! Note that this function uses unique pid instead of pid version. Not a mistake because EXEC may keep file descriptors
make_file_context_req_modify(&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);
}
}