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/ftrace_events.c |
/**
@file ftrace_events.c
@brief Events acquired via ftrace
@details Copyright (c) 2024 Acronis International GmbH
@author Bruce Wang (bruce.wang@acronis.com)
@since $Id: $
*/
#include "ftrace_hooks/ftrace_events.h"
// This is true for roughly Linux Kernel 3.7.
#ifdef HAVE_FTRACE_OPS_FL_SAVE_REGS
#ifdef KERNEL_MOCK
#include <mock/mock.h>
#endif
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/fsnotify.h>
#include <linux/namei.h>
#include <linux/skbuff.h>
#include <linux/splice.h>
#include <linux/types.h>
#include <net/netlink.h>
#include "audit_user.h"
#include "compat.h"
#include "debug.h"
#include "exec_event.h"
#include "exit_event.h"
#include "file_contexts.h"
#include "file_key_tools.h"
#include "fsnotify_events.h"
#include "fsnotify_listener.h"
#include "fork_event.h"
#include "fs_event.h"
#include "lsm_hooks/lsm_common.h"
#include "memory.h"
#include "message.h"
#include "path_tools.h"
#include "reg_tools.h"
#include "si_size.h"
#include "si_templates.h"
#include "si_writer_common.h"
#include "syscall_common.h"
#include "task_tools.h"
#if 0
FSNOTIFY_V1
// version <= 5.8:
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
const struct qstr *old_name,
int isdir, struct inode *target,
struct dentry *moved)
{
fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie);
fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie);
}
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
fsnotify_dirent(inode, dentry, FS_CREATE);
}
static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
{
fsnotify_dirent(dir, dentry, FS_DELETE);
}
static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
__u32 mask)
{
fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0);
}
static inline void fsnotify_name(struct inode *dir, __u32 mask,
struct inode *child,
const struct qstr *name, u32 cookie)
{
fsnotify(dir, mask, child, FSNOTIFY_EVENT_INODE, name, cookie);
}
int fsnotify(struct inode *to_tell, __u32 mask, const void *data,
int data_type, const struct qstr *name, u32 cookie);
####################
FSNOTIFY_V2
// 5.8 < version < 5.16
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
const struct qstr *old_name,
int isdir, struct inode *target,
struct dentry *moved)
{
fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie);
fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie);
}
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
fsnotify_dirent(inode, dentry, FS_CREATE);
}
static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
{
fsnotify_dirent(dir, dentry, FS_DELETE);
}
static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
__u32 mask)
{
fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0);
}
static inline void fsnotify_name(struct inode *dir, __u32 mask,
struct inode *child,
const struct qstr *name, u32 cookie)
{
fsnotify(mask, child, FSNOTIFY_EVENT_INODE, dir, name, NULL, cookie);
}
int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
const struct qstr *file_name, struct inode *inode, u32 cookie);
###########
FSNOTIFY_V3 (or V2)
// version >= 5.16
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
const struct qstr *old_name,
int isdir, struct inode *target,
struct dentry *moved)
{
fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE,
old_dir, old_name, fs_cookie);
fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE,
new_dir, new_name, fs_cookie);
}
static inline void fsnotify_delete(struct inode *dir, struct inode *inode,
struct dentry *dentry)
{
fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name,
0);
}
static inline void fsnotify_create(struct inode *dir, struct dentry *dentry)
{
fsnotify_dirent(dir, dentry, FS_CREATE);
}
static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry,
__u32 mask)
{
fsnotify_name(mask, dentry, FSNOTIFY_EVENT_DENTRY, dir, &dentry->d_name, 0);
}
static inline int fsnotify_name(__u32 mask, const void *data, int data_type,
struct inode *dir, const struct qstr *name,
u32 cookie)
{
return fsnotify(mask, data, data_type, dir, name, NULL, cookie);
}
int fsnotify(__u32 mask, const void *data, int data_type,
struct inode *dir, const struct qstr *name,
struct inode *inode, u32 cookie);
#endif
static void fsnotify_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
#ifndef HAVE_FSNOTIFY_PUBLIC_API
uint32_t mask;
const void *data;
int data_type;
const void *name_ptr;
(void) ip; (void) parent_ip; (void) op;
if (!HOOK_PROLOG())
return;
#ifdef FSNOTIFY_MASK_SECOND
mask = GET_KERNEL_ARGUMENT(regs, 1);
data = (const void*)GET_KERNEL_ARGUMENT(regs, 2);
data_type = (int) GET_KERNEL_ARGUMENT(regs, 3);
#else
mask = GET_KERNEL_ARGUMENT(regs, 0);
data = (const void*)GET_KERNEL_ARGUMENT(regs, 1);
data_type = (int) GET_KERNEL_ARGUMENT(regs, 2);
#endif
name_ptr = (const void*)GET_KERNEL_ARGUMENT(regs, 4);
#ifdef HAVE_FSNOTIFY_QSTR
name_ptr = name_ptr ? ((const struct qstr *)name_ptr)->name : NULL;
#endif
handle_fsnotify_event(mask, data, data_type, name_ptr);
HOOK_EPILOG();
#else
(void) regs; (void) op; (void) ip; (void) parent_ip;
#endif
}
static void exec_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct task_struct* tsk = (struct task_struct *)GET_KERNEL_ARGUMENT(regs, 0);
(void) ip; (void) parent_ip; (void) op;
if (!HOOK_PROLOG())
{
return;
}
exec_event(tsk);
HOOK_EPILOG();
}
static void exit_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct task_struct* tsk = (struct task_struct *)GET_KERNEL_ARGUMENT(regs, 0);
(void) ip; (void) parent_ip; (void) op;
if (!HOOK_PROLOG())
{
return;
}
exit_event(tsk);
HOOK_EPILOG();
}
static void fork_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct task_struct* tsk = (struct task_struct *)GET_KERNEL_ARGUMENT(regs, 0);
(void) ip; (void) parent_ip; (void) op;
if (!HOOK_PROLOG())
{
return;
}
fork_event(tsk);
HOOK_EPILOG();
}
#define SI_LOGIN_LOGOUT_FIELDS(tmpl) \
SI_COMMON_FIELDS(tmpl) \
tmpl(FP_SI_PI_OBJECT_NAME) \
tmpl(FP_SI_PI_FLAGS)
static void audit_handle_msg(struct sk_buff* skb, struct nlmsghdr *nlh)
{
u16 msg_type = nlh->nlmsg_type;
(void) skb;
if (msg_type == AUDIT_USER_LOGIN || msg_type == AUDIT_USER_LOGOUT)
{
int msg_len = nlmsg_len(nlh);
msg_t* msg;
size_t msg_size;
uint64_t event_uid;
SiSizedString data;
task_info_t* task_info;
const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_LOGIN_LOGOUT);
if (msg_len < 2)
return;
{
transport_ids_t ids;
transport_global_get_ids(&ids, generatedEventsMask);
task_info = task_info_map_get(current);
refresh_task(task_info, &ids);
// not skipping event - always send login/logout events
}
data.value = (const char*) NLMSG_DATA(nlh);
data.length = strnlen(data.value, msg_len);
msg_size = SI_ESTIMATE_TMPL_SIZE(SI_LOGIN_LOGOUT_FIELDS) + data.length;
msg = msg_new(FP_SI_OT_NOTIFY_LOGIN_LOGOUT, 0, SI_CT_POST_CALLBACK, make_unique_pid(current), msg_size);
if (msg) {
event_uid = transport_global_sequence_next();
{
si_property_writer_t writer;
si_event_writer_init(&writer, &msg->event, msg_size);
si_property_writer_write_common(&writer, event_uid, current->pid, current->tgid, task_info);
si_property_writer_write_object_name(&writer, data);
si_property_writer_write_flags(&writer, msg_type);
si_event_writer_finalize(&msg->event, &writer);
}
send_msg_async_unref(msg);
}
if (task_info)
task_info_put(task_info);
}
}
static void audit_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct sk_buff* skb = (struct sk_buff*)GET_KERNEL_ARGUMENT(regs, 0);
struct nlmsghdr *nlh;
int len;
const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_LOGIN_LOGOUT);
if (!(transport_global_get_combined_mask() & generatedEventsMask)
|| transport_process_belongs_to_control(current)) {
return;
}
(void) ip; (void) parent_ip; (void) op;
nlh = nlmsg_hdr(skb);
len = skb->len;
while (NLMSG_OK(nlh, len)) {
audit_handle_msg(skb, nlh);
nlh = NLMSG_NEXT(nlh, len);
}
}
static void pre_write(const struct path *path, int flags, loff_t offset, size_t count)
{
transport_ids_t transport_ids;
task_info_t* task_info;
file_context_info_t file_context_info = {0};
const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_SYNC_FILE_PRE_WRITE);
if (!(transport_global_get_combined_mask() & generatedEventsMask)
|| 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 (make_file_context_info_rw(&file_context_info, path, READ_ONCE(task_info->pid_version), offset, offset + count) &&
check_write_cache(&transport_ids, &file_context_info))
goto err_skipped;
(void) fs_event_pre_write(task_info, flags, offset, count, path, &file_context_info.msg_info);
err_skipped:
task_info_put(task_info);
}
static void pre_read(const struct path *path, loff_t offset, size_t count)
{
transport_ids_t transport_ids;
task_info_t* task_info;
file_key_t key;
const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_FILE_FULL_READ);
if (!(transport_global_get_combined_mask() & generatedEventsMask)
|| 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;
{
file_context_info_t file_context_info = {0};
if (make_file_context_info_rw(&file_context_info, path, READ_ONCE(task_info->pid_version), offset, offset + count) &&
check_and_update_read_cache(&transport_ids, &file_context_info))
{
goto err_skipped;
}
}
make_key(&key, path);
fs_event_pre_full_read(task_info, path);
err_skipped:
task_info_put(task_info);
}
static void rw_verify_area_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
int read_write = (int)GET_KERNEL_ARGUMENT(regs, 0);
bool write = WRITE == read_write;
bool read = READ == read_write;
struct file *file = (struct file *)GET_KERNEL_ARGUMENT(regs, 1);
const loff_t *ppos = (const loff_t *)GET_KERNEL_ARGUMENT(regs, 2);
size_t count = (size_t)GET_KERNEL_ARGUMENT(regs, 3);
loff_t pos;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
BUILD_BUG_ON(!__builtin_types_compatible_p(typeof(&rw_verify_area), int (*)(int, struct file*, const loff_t*, size_t)));
#endif
(void) ip; (void) parent_ip; (void) op;
if (!file || !ppos)
return;
if (!read && !write)
return;
#ifdef FMODE_NONOTIFY
if (file->f_mode & FMODE_NONOTIFY)
return;
#endif
pos = *ppos;
// I am not even going to consider these weird cases
// rw_verify_area will check for those and I will do so too
if (pos < 0)
return;
if ((ssize_t) count < 0)
return;
if ((loff_t) (pos + count) < 0)
return;
if (!file_is_valid(file))
return;
if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
return;
if (!HOOK_PROLOG())
return;
if (write)
pre_write(&file->f_path, file->f_flags, pos, count);
if (read)
pre_read(&file->f_path, pos, count);
HOOK_EPILOG();
}
static void check_copy_file(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len)
{
transport_ids_t transport_ids;
task_info_t* task_info;
const uint64_t generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(FP_SI_OT_NOTIFY_FILE_COPY);
loff_t in_size;
loff_t out_size;
if (0 != pos_in || 0 != pos_out)
return;
if (!path_is_valid(&file_in->f_path) || !path_is_valid(&file_out->f_path))
return;
in_size = i_size_read(file_in->f_path.dentry->d_inode);
out_size = i_size_read(file_out->f_path.dentry->d_inode);
if (in_size > len || out_size > len)
return;
if (!HOOK_PROLOG())
return;
if (!(transport_global_get_combined_mask() & generatedEventsMask)
|| transport_process_belongs_to_control(current)) {
goto out;
}
task_info = task_info_map_get(current);
if (!task_info)
goto out;
transport_global_get_ids(&transport_ids, generatedEventsMask);
refresh_task(task_info, &transport_ids);
if (!task_info_can_skip(task_info, &transport_ids, generatedEventsMask))
fs_event_pre_copyfile(task_info, &file_in->f_path, &file_out->f_path);
task_info_put(task_info);
out:
HOOK_EPILOG();
}
#ifdef HAVE_VFS_CLONE_FILE_RANGE
static void clone_file_range_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct file *file_in = (struct file *)GET_KERNEL_ARGUMENT(regs, 0);
loff_t pos_in = (loff_t)GET_KERNEL_ARGUMENT(regs, 1);
struct file *file_out = (struct file *)GET_KERNEL_ARGUMENT(regs, 2);
loff_t pos_out = (loff_t)GET_KERNEL_ARGUMENT(regs, 3);
loff_t len = (loff_t)GET_KERNEL_ARGUMENT(regs, 4);
BUILD_BUG_ON(!(__builtin_types_compatible_p(typeof(&vfs_clone_file_range), int (*)(struct file*, loff_t, struct file*, loff_t, u64))
|| __builtin_types_compatible_p(typeof(&vfs_clone_file_range), loff_t (*)(struct file*, loff_t, struct file*, loff_t, loff_t, unsigned int))));
(void) ip; (void) parent_ip; (void) op;
check_copy_file(file_in, pos_in, file_out, pos_out, len);
}
#endif
#ifdef HAVE_VFS_COPY_FILE_RANGE
static void copy_file_range_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct file *file_in = (struct file *)GET_KERNEL_ARGUMENT(regs, 0);
loff_t pos_in = (loff_t)GET_KERNEL_ARGUMENT(regs, 1);
struct file *file_out = (struct file *)GET_KERNEL_ARGUMENT(regs, 2);
loff_t pos_out = (loff_t)GET_KERNEL_ARGUMENT(regs, 3);
size_t len = (size_t)GET_KERNEL_ARGUMENT(regs, 4);
BUILD_BUG_ON(!__builtin_types_compatible_p(typeof(&vfs_copy_file_range), ssize_t (*)(struct file*, loff_t, struct file *, loff_t, size_t, unsigned int)));
(void) ip; (void) parent_ip; (void) op;
check_copy_file(file_in, pos_in, file_out, pos_out, len);
}
#endif
static void do_splice_direct_entry_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
{
struct file *in = (struct file *)GET_KERNEL_ARGUMENT(regs, 0);
loff_t *ppos = (loff_t *)GET_KERNEL_ARGUMENT(regs, 1);
struct file *out = (struct file *)GET_KERNEL_ARGUMENT(regs, 2);
loff_t *opos = NULL;
size_t len;
(void) ip; (void) parent_ip; (void) op;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
BUILD_BUG_ON(!__builtin_types_compatible_p(typeof(&do_splice_direct), long (*)(struct file*, loff_t*, struct file*, loff_t*, size_t, unsigned int)));
opos = (loff_t *)GET_KERNEL_ARGUMENT(regs, 3);
len = (size_t)GET_KERNEL_ARGUMENT(regs, 4);
#elif defined(HAVE_DO_SPLICE_DIRECT_IN_FS)
if (__builtin_types_compatible_p(typeof(&do_splice_direct), long (*)(struct file*, loff_t*, struct file*, size_t, unsigned int))) {
len = (size_t)GET_KERNEL_ARGUMENT(regs, 3);
} else {
opos = (loff_t *)GET_KERNEL_ARGUMENT(regs, 3);
len = (size_t)GET_KERNEL_ARGUMENT(regs, 4);
}
#else
opos = (loff_t *)GET_KERNEL_ARGUMENT(regs, 3);
len = (size_t)GET_KERNEL_ARGUMENT(regs, 4);
#endif
if (!ppos || !opos)
return;
check_copy_file(in, *ppos, out, *opos, len);
}
// !!! These must align exactly with ftrace_post_event_type_t !!!
static fp_probe_t g_probes[] = {
{
.ops = {
.func = (ftrace_func_t) fsnotify_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = (unsigned long) fsnotify,
.name = NULL,
.registered = false,
},
{
.ops = {
.func = (ftrace_func_t) exec_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = 0,
.name = "proc_exec_connector",
.registered = false,
},
{
.ops = {
.func = (ftrace_func_t) exit_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = 0,
.name = "proc_exit_connector",
.registered = false,
},
{
.ops = {
.func = (ftrace_func_t) fork_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = 0,
.name = "proc_fork_connector",
.registered = false,
},
{
.ops = {
.func = (ftrace_func_t) audit_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = 0,
.name = "audit_receive",
.registered = false,
},
{
.ops = {
.func = (ftrace_func_t) rw_verify_area_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
// rw_verify_area is a public symbol in modern kernels but not in the older ones.
// TODO: 'rw_verify_area' misses 'remap_verify_area' case so cloning is not handled.
// Perhaps a simple solution could be hooking the clone functions like
// 'vfs_clone_file_range' and 'vfs_dedupe_file_range_one'?
// themselves?
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
.fn = (unsigned long) rw_verify_area,
.name = NULL,
#else
.fn = 0,
.name = "rw_verify_area",
#endif
.registered = false,
},
{
#ifdef HAVE_VFS_CLONE_FILE_RANGE
.ops = {
.func = (ftrace_func_t) clone_file_range_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = (unsigned long) vfs_clone_file_range,
.name = NULL,
.registered = false,
#endif
},
{
#ifdef HAVE_VFS_COPY_FILE_RANGE
.ops = {
.func = (ftrace_func_t) copy_file_range_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
.fn = (unsigned long) vfs_copy_file_range,
.name = NULL,
.registered = false,
#endif
},
{
.ops = {
.func = (ftrace_func_t) do_splice_direct_entry_handler,
.flags = FTRACE_OPS_FL_SAVE_REGS,
},
// public symbol since 3.18
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
.fn = (unsigned long) do_splice_direct,
.name = NULL,
#else
.fn = 0,
.name = "do_splice_direct",
#endif
.registered = false,
},
};
int register_ftrace_post_event(fp_probe_t *probe, struct ftrace_ops *ops)
{
int ret;
if (probe->name)
{
probe->fn = compat_kallsyms_lookup_name(probe->name);
if (!probe->fn)
{
EPRINTF("Failed to find %s", probe->name);
return -1;
}
DPRINTF("%s -> %lu", probe->name, probe->fn);
}
ret = ftrace_set_filter_ip(ops, probe->fn, 0, 0);
if (ret < 0)
{
EPRINTF("Failed to set filter ip");
return ret;
}
ret = register_ftrace_function(ops);
if (ret < 0)
{
EPRINTF("Failed to register ftrace");
return ret;
}
probe->registered = true;
return 0;
}
void register_ftrace_post_events(void)
{
int i = 0;
for (; i < (int) ARRAY_SIZE(g_probes); i++)
{
fp_probe_t* probe = &g_probes[i];
struct ftrace_ops *ops = &probe->ops;
int ret;
#ifdef HAVE_FSNOTIFY_PUBLIC_API
if (i == FTRACE_POST_EVENT_FSNOTIFY)
{
IPRINTF("fsnotify public API is used instead of ftrace");
continue;
}
#endif
if (!probe->fn && !probe->name)
{
continue;
}
ret = register_ftrace_post_event(probe, ops);
if( ret < 0)
{
EPRINTF("Failed to plant ftrace for %ps", (void*) probe->fn);
continue;
}
IPRINTF("Planted ftrace %ps", (void*) probe->fn);
}
}
void unregister_ftrace_post_event(fp_probe_t *probe)
{
if (probe->registered)
{
struct ftrace_ops *ops = &probe->ops;
IPRINTF("Remove ftrace for %ps", (void *)probe->fn);
unregister_ftrace_function(ops);
ftrace_set_filter_ip(ops, probe->fn, 1, 0);
probe->registered = false;
}
}
void unregister_ftrace_post_events(void)
{
int i = 0;
for (; i < (int) ARRAY_SIZE(g_probes); i++)
{
unregister_ftrace_post_event(&g_probes[i]);
}
}
bool ftrace_post_event_have(ftrace_post_event_type_t ev)
{
if (ev == FTRACE_POST_EVENT_FSNOTIFY && fsnotify_events_listener_registered())
return true;
return g_probes[ev].registered;
}
#else
void register_ftrace_post_events(void)
{
}
void unregister_ftrace_post_events(void)
{
}
bool ftrace_post_event_have(ftrace_post_event_type_t ev)
{
return false;
}
void unregister_ftrace_post_event(fp_probe_t *probe)
{
return;
}
int register_ftrace_post_event(fp_probe_t *probe, struct ftrace_ops *ops)
{
return -1;
}
#endif