Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion src/hooks/syscalls_hc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -570,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;
}
Expand All @@ -581,6 +596,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);

Expand Down
59 changes: 59 additions & 0 deletions src/hooks/syscalls_hc.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/hashtable.h>
#include <linux/uaccess.h>

#include "igloo_syscall_macros.h"

Expand All @@ -22,6 +23,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 */
Expand All @@ -32,6 +37,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 */
Expand Down Expand Up @@ -89,6 +96,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)
{
Expand Down
4 changes: 1 addition & 3 deletions src/portal/portal_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
10 changes: 6 additions & 4 deletions src/portal/portal_osi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 {
Expand All @@ -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';
Expand All @@ -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';
Expand Down