diff --git a/src/hooks/sock_hc.c b/src/hooks/sock_hc.c index 04f1dc5..cc4780b 100644 --- a/src/hooks/sock_hc.c +++ b/src/hooks/sock_hc.c @@ -14,6 +14,7 @@ #include #include #include "igloo_hypercall_consts.h" +#include "portal/scope.h" #if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0) @@ -37,6 +38,11 @@ void igloo_sock_bind(struct socket *sock, struct sockaddr_storage *address){ char buffer[32]; int hrv = 1; int i; + // Only report binds from the firmware-under-analysis subtree, not from + // Penguin infrastructure (vpnguin/console/etc.) that stays in the initial ns. + if (!igloo_in_scope(current)) { + return; + } mutex_lock(&bind_mutex); if (address->ss_family == AF_INET) { @@ -83,6 +89,11 @@ void igloo_sock_bind(struct socket *sock, struct sockaddr_storage *address){ */ void igloo_sock_release(struct socket *sock){ struct sock *sk = sock->sk; + // Mirror the bind gate: skip releases outside the firmware subtree so we + // don't emit release events for infra binds we never reported. + if (!igloo_in_scope(current)) { + return; + } mutex_lock(&release_mutex); if (sk) { diff --git a/src/hooks/syscalls_hc.c b/src/hooks/syscalls_hc.c index 7f8ce52..4f899cd 100644 --- a/src/hooks/syscalls_hc.c +++ b/src/hooks/syscalls_hc.c @@ -17,6 +17,7 @@ #include "syscalls_hc.h" #include "args.h" #include "portal/portal.h" +#include "portal/scope.h" #include "igloo_hypercall_consts.h" #include #include @@ -312,6 +313,9 @@ static inline bool hook_matches_syscall(struct kernel_syscall_hook *hook, return false; } } + if (hook->hook.scope_filter_enabled && !igloo_in_scope(current)) { + return false; + } // Unrolled argument filter checks for IGLOO_SYSCALL_MAXARGS == 6 if (argc > 0) { struct value_filter *f = &hook->hook.arg_filters[0]; diff --git a/src/hooks/syscalls_hc.h b/src/hooks/syscalls_hc.h index 521c6c4..d48b264 100644 --- a/src/hooks/syscalls_hc.h +++ b/src/hooks/syscalls_hc.h @@ -64,7 +64,14 @@ struct syscall_hook { /* Process filtering */ bool comm_filter_enabled; /* Enable process name filtering */ char comm_filter[TASK_COMM_LEN]; /* Process name to match */ - + + /* Analysis scoping: when set, this hook only fires for the + * firmware-under-analysis process subtree (tasks outside the initial UTS + * namespace), skipping Penguin's own infrastructure. Logging (read-only) + * hooks set this; intervention hooks leave it clear so they still apply + * everywhere. */ + bool scope_filter_enabled; + /* Argument filtering with complex comparisons */ struct value_filter arg_filters[IGLOO_SYSCALL_MAXARGS]; /* Argument filters */ diff --git a/src/igloo_hc.c b/src/igloo_hc.c index c6e17e6..2f4b233 100644 --- a/src/igloo_hc.c +++ b/src/igloo_hc.c @@ -14,6 +14,7 @@ #include "igloo_hypercall.h" #include "igloo_hypercall_consts.h" #include "hyperfs/hyperfs.h" +#include "portal/scope.h" MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("IGLOO Kernel Inspection/Interventions"); @@ -44,6 +45,9 @@ int init_module(void) { printk(KERN_EMERG "IGLOO: Initializing\n"); report_base_addr(); + /* Capture the initial UTS namespace before init.sh unshares the firmware. */ + igloo_scope_init(); + if ((ret = syscalls_hc_init()) != 0) { printk(KERN_ERR "Failed to register syscalls_hc returning %d\n", ret); return ret; diff --git a/src/portal/portal_op_list.h b/src/portal/portal_op_list.h index 3973549..1087142 100644 --- a/src/portal/portal_op_list.h +++ b/src/portal/portal_op_list.h @@ -46,4 +46,5 @@ X(anonfs_create_file, ANONFS_CREATE_FILE) \ X(sockfs_create_socket, SOCKFS_CREATE_SOCKET) \ X(mtd_nuke, MTD_NUKE) \ - X(mtd_create, MTD_CREATE) + X(mtd_create, MTD_CREATE) \ + X(set_scope_enabled, SET_SCOPE_ENABLED) diff --git a/src/portal/scope.c b/src/portal/scope.c new file mode 100644 index 0000000..6fb7965 --- /dev/null +++ b/src/portal/scope.c @@ -0,0 +1,46 @@ +#include "portal_internal.h" +#include +#include +#include +#include "scope.h" + +static bool igloo_scope_enabled; +static struct uts_namespace *igloo_initial_uts_ns; + +void igloo_scope_init(void) +{ + /* + * Module init runs at boot / preinit, before init.sh unshares anything, + * so current's UTS namespace here is the initial namespace shared by all + * Penguin infrastructure. Capturing the pointer avoids depending on the + * init_uts_ns symbol being exported to modules. + */ + igloo_initial_uts_ns = current->nsproxy ? current->nsproxy->uts_ns : NULL; +} + +void igloo_scope_set_enabled(bool enabled) +{ + WRITE_ONCE(igloo_scope_enabled, enabled); +} +EXPORT_SYMBOL(igloo_scope_set_enabled); + +bool igloo_in_scope(struct task_struct *task) +{ + struct nsproxy *ns; + + if (!READ_ONCE(igloo_scope_enabled)) + return true; + if (!task) + return false; + ns = task->nsproxy; + if (!ns) + return false; + return ns->uts_ns != igloo_initial_uts_ns; +} +EXPORT_SYMBOL(igloo_in_scope); + +void handle_op_set_scope_enabled(portal_region *mem_region) +{ + igloo_scope_set_enabled(mem_region->header.addr != 0); + mem_region->header.op = HYPER_RESP_WRITE_OK; +} diff --git a/src/portal/scope.h b/src/portal/scope.h new file mode 100644 index 0000000..c0946e8 --- /dev/null +++ b/src/portal/scope.h @@ -0,0 +1,30 @@ +#ifndef __IGLOO_SCOPE_H__ +#define __IGLOO_SCOPE_H__ + +#include +#include + +/* + * Analysis scoping. + * + * Penguin's own infrastructure (boot machinery, the backgrounded vpnguin/ + * console/guesthopper helpers, and anything spawned via call_usermodehelper) + * stays in the kernel's initial UTS namespace. At handoff init.sh unshares a + * fresh UTS namespace for the real guest init, so the firmware-under-analysis + * process subtree lives outside the initial namespace. Analysis emission is + * gated on igloo_in_scope() so only the firmware subtree is captured. + */ + +/* Capture the initial UTS namespace. Call once at module init (before any + * unshare), while current is still Penguin's boot context. */ +void igloo_scope_init(void); + +/* Enable/disable gating. Default disabled, so a driver paired with a Penguin + * that never enables scoping behaves exactly as before (captures everything). */ +void igloo_scope_set_enabled(bool enabled); + +/* True if task's analysis events should be emitted. When gating is disabled + * this is always true. */ +bool igloo_in_scope(struct task_struct *task); + +#endif /* __IGLOO_SCOPE_H__ */