diff --git a/src/hooks/syscalls_hc.c b/src/hooks/syscalls_hc.c index da05bed..4adbbf1 100644 --- a/src/hooks/syscalls_hc.c +++ b/src/hooks/syscalls_hc.c @@ -300,8 +300,8 @@ static long process_syscall_hooks( long modified_ret = orig_ret; struct kernel_syscall_hook *hook; int i; - bool info_initialized = false; rcu_read_lock(); + fill_handler(&original_info, argc, args, syscall_name); // 1. Check the "match all syscalls" list first if (!hlist_empty(&syscall_all_hooks)) { hlist_for_each_entry_rcu(hook, &syscall_all_hooks, name_hlist) { @@ -312,10 +312,6 @@ static long process_syscall_hooks( matches = hook->hook.on_return && hook_matches_syscall_return(hook, syscall_name, argc, args, modified_ret); } if (matches) { - if (unlikely(!info_initialized)) { - fill_handler(&original_info, argc, args, syscall_name); - info_initialized = true; - } memcpy(&syscall_args_holder, &original_info, sizeof(struct syscall_event)); syscall_args_holder.hook = &hook->hook; if (!is_entry) syscall_args_holder.retval = modified_ret; @@ -359,10 +355,6 @@ static long process_syscall_hooks( matches = hook->hook.on_return && hook_matches_syscall_return(hook, syscall_name, argc, args, modified_ret); } if (matches) { - if (unlikely(!info_initialized)) { - fill_handler(&original_info, argc, args, syscall_name); - info_initialized = true; - } memcpy(&syscall_args_holder, &original_info, sizeof(struct syscall_event)); syscall_args_holder.hook = &hook->hook; if (!is_entry) syscall_args_holder.retval = modified_ret; @@ -464,81 +456,3 @@ int syscalls_hc_init(void) { hash_init(syscall_hook_table); return 0; } - -/* Deferred unregistration so we can invoke from inside a syscall callback */ -struct deferred_unregister { - struct kernel_syscall_hook *hook; - struct list_head list; -}; -static LIST_HEAD(deferred_unregister_list); -static DEFINE_SPINLOCK(deferred_unregister_lock); - -static void process_deferred_unregisters(struct work_struct *work) -{ - struct deferred_unregister *deferred, *tmp; - LIST_HEAD(local_list); - - // Move all pending unregistrations to local list - spin_lock(&deferred_unregister_lock); - list_splice_init(&deferred_unregister_list, &local_list); - spin_unlock(&deferred_unregister_lock); - - // Process unregistrations outside of spinlock - list_for_each_entry_safe(deferred, tmp, &local_list, list) { - DBG_PRINTK("IGLOO: Processing deferred unregistration for hook %p\n", - deferred->hook); - - // Actually unregister the hook - unregister_syscall_hook(deferred->hook); - - // Clean up the deferred entry - list_del(&deferred->list); - kfree(deferred); - } -} - -static DECLARE_WORK(deferred_unregister_work, process_deferred_unregisters); - -static int do_unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr) -{ - if (!hook_ptr) { - return -EINVAL; - } - - spin_lock(&syscall_hook_lock); - - hash_del(&hook_ptr->hlist); - hlist_del_rcu(&hook_ptr->name_hlist); - - spin_unlock(&syscall_hook_lock); - - kfree_rcu(hook_ptr, rcu); - - DBG_PRINTK("IGLOO: Unregistered syscall hook %p\n", hook_ptr); - return 0; -} - -// Modified unregister function -int unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr) -{ - struct deferred_unregister *deferred; - - // Check if we're in syscall processing context - if (in_interrupt() || rcu_read_lock_held()) { - // Defer the unregistration - deferred = kmalloc(sizeof(*deferred), GFP_ATOMIC); - if (!deferred) return -ENOMEM; - - deferred->hook = hook_ptr; - spin_lock(&deferred_unregister_lock); - list_add_tail(&deferred->list, &deferred_unregister_list); - spin_unlock(&deferred_unregister_lock); - - // Schedule work to process deferred unregistrations - schedule_work(&deferred_unregister_work); - return 0; - } - - // Safe to unregister immediately - return do_unregister_syscall_hook(hook_ptr); -} diff --git a/src/hooks/syscalls_hc.h b/src/hooks/syscalls_hc.h index 171cb48..3f7886c 100644 --- a/src/hooks/syscalls_hc.h +++ b/src/hooks/syscalls_hc.h @@ -41,18 +41,18 @@ struct syscall_hook { bool on_return; /* Hook on syscall return */ bool on_all; /* Hook on all syscalls */ char name[SYSCALL_NAME_MAX_LEN]; /* Name of syscall to hook */ - + /* PID filtering */ bool pid_filter_enabled; /* Enable PID filtering */ pid_t filter_pid; /* Process ID to filter on */ - + /* Process filtering */ bool comm_filter_enabled; /* Enable process name filtering */ char comm_filter[TASK_COMM_LEN]; /* Process name to match */ - + /* Argument filtering with complex comparisons */ struct value_filter arg_filters[IGLOO_SYSCALL_MAXARGS]; /* Argument filters */ - + /* Return value filtering with complex comparisons */ struct value_filter retval_filter; /* Return value filter */ }; @@ -84,9 +84,6 @@ extern struct hlist_head syscall_hook_table[1024]; extern spinlock_t syscall_hook_lock; -/* Unregister a syscall hook using its pointer */ -int unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr); - int syscalls_hc_init(void); /* Normalize syscall names by removing common prefixes like 'sys_', '_sys_', 'compat_sys_' */ @@ -94,26 +91,26 @@ static inline const char *normalize_syscall_name(const char *name) { if (!name) return NULL; - + /* Skip leading underscores (e.g. _sys_) */ while (*name == '_') name++; - + /* Check for 'sys_' prefix */ if (strncmp(name, "sys_", 4) == 0) return name + 4; - + /* Check for 'compat_sys_' prefix */ if (strncmp(name, "compat_sys_", 11) == 0) return name + 11; - + /* Check for other arch-specific prefixes */ if (strncmp(name, "arm64_sys_", 10) == 0) return name + 10; - + if (strncmp(name, "riscv_sys_", 10) == 0) return name + 10; - + return name; } @@ -123,11 +120,11 @@ static inline u32 syscall_name_hash(const char *str) const char *normalized; if (!str) return 0; - + // First normalize the syscall name to handle various prefixes normalized = normalize_syscall_name(str); - + return full_name_hash(NULL, normalized, strlen(normalized)); } -#endif /* _SYSCALLS_HC_H */ \ No newline at end of file +#endif /* _SYSCALLS_HC_H */ diff --git a/src/portal/portal_op_list.h b/src/portal/portal_op_list.h index 3a94a73..ffdec12 100644 --- a/src/portal/portal_op_list.h +++ b/src/portal/portal_op_list.h @@ -19,6 +19,7 @@ X(register_uprobe, REGISTER_UPROBE) \ X(unregister_uprobe, UNREGISTER_UPROBE) \ X(register_syscall_hook, REGISTER_SYSCALL_HOOK) \ + X(unregister_syscall_hook, UNREGISTER_SYSCALL_HOOK) \ X(ffi_exec, FFI_EXEC) \ X(kallsyms_lookup, KALLSYMS_LOOKUP) \ X(tramp_generate, TRAMP_GENERATE) \ diff --git a/src/portal/portal_syscall.c b/src/portal/portal_syscall.c index adc4fe6..0a28f59 100644 --- a/src/portal/portal_syscall.c +++ b/src/portal/portal_syscall.c @@ -20,12 +20,12 @@ void handle_op_register_syscall_hook(portal_region *mem_region) { struct syscall_hook *hook; struct kernel_syscall_hook *kernel_hook; - + igloo_pr_debug("igloo: Handling HYPER_OP_REGISTER_SYSCALL_HOOK\n"); - + // Map the data buffer to our hook structure hook = (struct syscall_hook *)PORTAL_DATA(mem_region); - + // Allocate a new kernel hook structure kernel_hook = kzalloc(sizeof(*kernel_hook), GFP_KERNEL); if (!kernel_hook) { @@ -33,7 +33,7 @@ void handle_op_register_syscall_hook(portal_region *mem_region) mem_region->header.op = HYPER_RESP_READ_FAIL; return; } - + // Copy the hook configuration memcpy(&kernel_hook->hook, hook, sizeof(struct syscall_hook)); kernel_hook->in_use = true; @@ -46,11 +46,11 @@ void handle_op_register_syscall_hook(portal_region *mem_region) } else { kernel_hook->normalized_name[0] = '\0'; } - + // Add to the main hook table indexed by pointer address spin_lock(&syscall_hook_lock); hash_add_rcu(syscall_hook_table, &kernel_hook->hlist, (unsigned long)kernel_hook); - + // Also add to name-based hash table for faster lookups if (kernel_hook->hook.on_all) { // Special case for hooks that want all syscalls @@ -60,10 +60,104 @@ void handle_op_register_syscall_hook(portal_region *mem_region) u32 name_hash = syscall_name_hash(kernel_hook->hook.name); hash_add_rcu(syscall_name_table, &kernel_hook->name_hlist, name_hash); } - + spin_unlock(&syscall_hook_lock); - + // Return the hook's memory address in the size field mem_region->header.size = (unsigned long)kernel_hook; mem_region->header.op = HYPER_RESP_READ_NUM; -} \ No newline at end of file +} + +/* Deferred unregistration so we can invoke from inside a syscall callback */ +struct deferred_unregister { + struct kernel_syscall_hook *hook; + struct list_head list; +}; +static LIST_HEAD(deferred_unregister_list); +static DEFINE_SPINLOCK(deferred_unregister_lock); + +static int do_unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr) +{ + if (!hook_ptr) { + return -EINVAL; + } + + spin_lock(&syscall_hook_lock); + + hash_del(&hook_ptr->hlist); + hlist_del_rcu(&hook_ptr->name_hlist); + + spin_unlock(&syscall_hook_lock); + + kfree_rcu(hook_ptr, rcu); + + igloo_pr_debug("igloo: Unregistered syscall hook %p\n", hook_ptr); + return 0; +} + +static void process_deferred_unregisters(struct work_struct *work) +{ + struct deferred_unregister *deferred, *tmp; + LIST_HEAD(local_list); + + // Move all pending unregistrations to local list + spin_lock(&deferred_unregister_lock); + list_splice_init(&deferred_unregister_list, &local_list); + spin_unlock(&deferred_unregister_lock); + + // Process unregistrations outside of spinlock + list_for_each_entry_safe(deferred, tmp, &local_list, list) { + igloo_pr_debug("IGLOO: Processing deferred unregistration for hook %p\n", + deferred->hook); + + // Actually unregister the hook + do_unregister_syscall_hook(deferred->hook); + + // Clean up the deferred entry + list_del(&deferred->list); + kfree(deferred); + } +} + +static DECLARE_WORK(deferred_unregister_work, process_deferred_unregisters); + + +void handle_op_unregister_syscall_hook(portal_region *mem_region) +{ + struct deferred_unregister *deferred; + struct kernel_syscall_hook *hook_ptr; + + igloo_pr_debug("igloo: Handling HYPER_OP_UNREGISTER_SYSCALL_HOOK\n"); + + // Map the data buffer to our hook structure + hook_ptr = (struct kernel_syscall_hook *)PORTAL_DATA(mem_region); + + //First, disable hook + WRITE_ONCE(hook_ptr->hook.enabled, false); + + // Check if we're in syscall processing context + if (in_interrupt() || rcu_read_lock_held()) { + // Defer the unregistration + deferred = kmalloc(sizeof(*deferred), GFP_ATOMIC); + if (!deferred) { + mem_region->header.op = HYPER_RESP_READ_FAIL; + return; + } + + deferred->hook = hook_ptr; + spin_lock(&deferred_unregister_lock); + list_add_tail(&deferred->list, &deferred_unregister_list); + spin_unlock(&deferred_unregister_lock); + + // Schedule work to process deferred unregistrations + schedule_work(&deferred_unregister_work); + mem_region->header.op = HYPER_RESP_READ_NUM; + mem_region->header.size = (unsigned long)0; + return; + } + + // Safe to unregister immediately + do_unregister_syscall_hook(hook_ptr); + mem_region->header.op = HYPER_RESP_READ_NUM; + mem_region->header.size = (unsigned long)0; +}