From 2ed771ee51efa9e4427e7bf1f3e9ff8dda54b30c Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 12 Dec 2025 17:06:57 -0500 Subject: [PATCH 1/5] syscalls_hc: add --- src/hooks/syscalls_hc.c | 25 +++++++++++++++++- src/hooks/syscalls_hc.h | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/hooks/syscalls_hc.c b/src/hooks/syscalls_hc.c index 086867c..653b2ed 100644 --- a/src/hooks/syscalls_hc.c +++ b/src/hooks/syscalls_hc.c @@ -165,7 +165,21 @@ static inline bool value_matches_filter(long value, const struct value_filter *f case SYSCALLS_HC_FILTER_BITMASK_CLEAR: return (value & filter->bitmask) == 0; - + case SYSCALLS_HC_FILTER_STR_EXACT: + if (!value || !filter->pattern) return false; + return check_str_exact(value, filter->pattern, filter->pattern_len); + + case SYSCALLS_HC_FILTER_STR_STARTSWITH: + if (!value || !filter->pattern) return false; + return check_str_startswith(value, filter->pattern, filter->pattern_len); + + case SYSCALLS_HC_FILTER_STR_ENDSWITH: + if (!value || !filter->pattern) return false; + return check_str_endswith(value, filter->pattern, filter->pattern_len); + + case SYSCALLS_HC_FILTER_STR_CONTAINS: + if (!value || !filter->pattern) return false; + return check_str_contains(value, filter->pattern, filter->pattern_len); default: // Unknown filter type, assume no match return false; @@ -581,6 +595,15 @@ static int do_unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr) spin_unlock(&syscall_hook_lock); + for (i = 0; i < IGLOO_SYSCALL_MAXARGS; i++) { + if (hook_ptr->hook.arg_filters[i].pattern) { + kfree(hook_ptr->hook.arg_filters[i].pattern); + } + } + if (hook_ptr->hook.retval_filter.pattern) { + kfree(hook_ptr->hook.retval_filter.pattern); + } + kfree_rcu(hook_ptr, rcu); atomic_dec(&global_syscall_hook_count); diff --git a/src/hooks/syscalls_hc.h b/src/hooks/syscalls_hc.h index c333597..4dc85ad 100644 --- a/src/hooks/syscalls_hc.h +++ b/src/hooks/syscalls_hc.h @@ -22,6 +22,10 @@ enum value_filter_type { SYSCALLS_HC_FILTER_ERROR, /* < 0 (error, for return values) */ SYSCALLS_HC_FILTER_BITMASK_SET, /* All specified bits are set */ SYSCALLS_HC_FILTER_BITMASK_CLEAR, /* All specified bits are clear */ + SYSCALLS_HC_FILTER_STR_EXACT, /* Exact string match */ + SYSCALLS_HC_FILTER_STR_CONTAINS, /* String contains substring */ + SYSCALLS_HC_FILTER_STR_STARTSWITH, /* String starts with prefix */ + SYSCALLS_HC_FILTER_STR_ENDSWITH, /* String ends with suffix */ }; /* Value filter structure for complex comparisons */ @@ -32,6 +36,8 @@ struct value_filter { long min_value; /* Minimum value for range filter */ long max_value; /* Maximum value for range filter */ unsigned long bitmask; /* Bitmask for bit operations */ + char *pattern; /* String value for string comparisons */ + u32 pattern_len; /* Length of string pattern */ }; /* Syscall hook structure */ @@ -89,6 +95,58 @@ int unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr); int syscalls_hc_init(void); +/* Helper for chunked comparison to avoid large stack buffers */ +#define CMP_CHUNK_SIZE 64 + +static inline bool check_str_startswith(long user_ptr, const char *pattern, u32 len) { + char buf[CMP_CHUNK_SIZE]; + u32 offset = 0; + long ret; + + while (offset < len) { + int chunk = (len - offset > CMP_CHUNK_SIZE) ? CMP_CHUNK_SIZE : (len - offset); + ret = strncpy_from_user(buf, (const char __user *)(user_ptr + offset), chunk); + if (ret < chunk) return false; // EFAULT or hit null too early + if (memcmp(buf, pattern + offset, chunk) != 0) return false; + offset += chunk; + } + return true; +} + +static inline bool check_str_exact(long user_ptr, const char *pattern, u32 len) { + char buf[1]; + // Check prefix match + if (!check_str_startswith(user_ptr, pattern, len)) return false; + // Verify null termination at len + if (strncpy_from_user(buf, (const char __user *)(user_ptr + len), 1) != 1) return false; + return buf[0] == '\0'; +} + +static inline bool check_str_endswith(long user_ptr, const char *pattern, u32 pat_len) { + long str_len = strnlen_user((const char __user *)user_ptr, 32768); // Soft limit 32KB + if (str_len <= 0 || str_len - 1 < pat_len) return false; + return check_str_startswith(user_ptr + (str_len - 1 - pat_len), pattern, pat_len); +} + +static inline bool check_str_contains(long user_ptr, const char *pattern, u32 pat_len) { + // Naive scanning implementation + char buf[CMP_CHUNK_SIZE]; + long str_len = strnlen_user((const char __user *)user_ptr, 32768); + long i; + + if (str_len <= 0 || str_len - 1 < pat_len) return false; + + // Optimization: find first char then check prefix + for (i = 0; i <= str_len - 1 - pat_len; i++) { + long ret = strncpy_from_user(buf, (const char __user *)(user_ptr + i), 1); + if (ret != 1) return false; + if (buf[0] == pattern[0]) { + if (check_str_startswith(user_ptr + i, pattern, pat_len)) return true; + } + } + return false; +} + /* Normalize syscall names by removing common prefixes like 'sys_', '_sys_', 'compat_sys_' */ static inline const char *normalize_syscall_name(const char *name) { From 3bd58cc038c807dd33da817661c9efb7642ca968 Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 12 Dec 2025 17:52:21 -0500 Subject: [PATCH 2/5] fixup missing value --- src/hooks/syscalls_hc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/syscalls_hc.c b/src/hooks/syscalls_hc.c index 653b2ed..4c5fe2f 100644 --- a/src/hooks/syscalls_hc.c +++ b/src/hooks/syscalls_hc.c @@ -584,6 +584,7 @@ static DECLARE_WORK(deferred_unregister_work, process_deferred_unregisters); static int do_unregister_syscall_hook(struct kernel_syscall_hook *hook_ptr) { + int i; if (!hook_ptr) { return -EINVAL; } From e5389fea378fc4a0c1a289c6163ea24d58945e6e Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 12 Dec 2025 17:56:09 -0500 Subject: [PATCH 3/5] portal_mem: make compiler happy --- src/portal/portal_mem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/portal/portal_mem.c b/src/portal/portal_mem.c index 1586fa0..8e8999a 100644 --- a/src/portal/portal_mem.c +++ b/src/portal/portal_mem.c @@ -366,12 +366,10 @@ void handle_op_copy_buf_guest(portal_region *mem_region) region_header *req = &mem_region->header; void * data = PORTAL_DATA(mem_region); void * buf; - int copy_size = min(req->size, sizeof(mem_region->raw)); - igloo_pr_debug("igloo: Handling COPY_BUF_GUEST for size %lu\n", req->size); + uint64_t copy_size = min_t(size_t, req->size, sizeof(mem_region->raw)); buf = kzalloc(req->size, GFP_KERNEL); if (!buf) { - igloo_pr_debug("igloo: kzalloc failed for size %lu\n", req->size); mem_region->header.op = HYPER_RESP_READ_FAIL; return; } From 62135c844000cddfb176dff5addf7ccd5f391e4e Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 12 Dec 2025 17:56:18 -0500 Subject: [PATCH 4/5] syscalls_hc: add import --- src/hooks/syscalls_hc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/syscalls_hc.h b/src/hooks/syscalls_hc.h index 4dc85ad..b4f2919 100644 --- a/src/hooks/syscalls_hc.h +++ b/src/hooks/syscalls_hc.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "igloo_syscall_macros.h" From 1320c033ae910d218bcf9810b62339674b9ca2e9 Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 12 Dec 2025 17:56:29 -0500 Subject: [PATCH 5/5] portal_osi: make compiler happy --- src/portal/portal_osi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/portal/portal_osi.c b/src/portal/portal_osi.c index ec2fedd..f98f2e0 100644 --- a/src/portal/portal_osi.c +++ b/src/portal/portal_osi.c @@ -37,6 +37,8 @@ static inline void *portal_anon_vma_name(struct vm_area_struct *vma) static void portal_get_vma_name(struct vm_area_struct *vma, char *buf, size_t buf_size) { struct mm_struct *mm = vma->vm_mm; + const char *arch_name, *name; + char *path_buf, *path; // Only declare anon_name on kernels that support it (5.17+) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) @@ -57,9 +59,9 @@ static void portal_get_vma_name(struct vm_area_struct *vma, char *buf, size_t bu #endif // Standard file path (Compiles on all versions) - char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL); + path_buf = kmalloc(PATH_MAX, GFP_KERNEL); if (path_buf) { - char *path = d_path(&vma->vm_file->f_path, path_buf, PATH_MAX); + path = d_path(&vma->vm_file->f_path, path_buf, PATH_MAX); if (!IS_ERR(path)) { strncpy(buf, path, buf_size - 1); } else { @@ -73,7 +75,7 @@ static void portal_get_vma_name(struct vm_area_struct *vma, char *buf, size_t bu // 2. Specific VMA Operations if (vma->vm_ops && vma->vm_ops->name) { - const char *name = vma->vm_ops->name(vma); + name = vma->vm_ops->name(vma); if (name) { strncpy(buf, name, buf_size - 1); buf[buf_size - 1] = '\0'; @@ -82,7 +84,7 @@ static void portal_get_vma_name(struct vm_area_struct *vma, char *buf, size_t bu } // 3. Architecture specific - const char *arch_name = arch_vma_name(vma); + arch_name = arch_vma_name(vma); if (arch_name) { strncpy(buf, arch_name, buf_size - 1); buf[buf_size - 1] = '\0';