Skip to content
Merged
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
11 changes: 11 additions & 0 deletions src/hooks/sock_hc.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/kallsyms.h>
#include <linux/version.h>
#include "igloo_hypercall_consts.h"
#include "portal/scope.h"


#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0)
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/syscalls_hc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <linux/kallsyms.h>
#include <linux/list.h>
Expand Down Expand Up @@ -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];
Expand Down
9 changes: 8 additions & 1 deletion src/hooks/syscalls_hc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
4 changes: 4 additions & 0 deletions src/igloo_hc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/portal/portal_op_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
46 changes: 46 additions & 0 deletions src/portal/scope.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "portal_internal.h"
#include <linux/sched.h>
#include <linux/nsproxy.h>
#include <linux/utsname.h>
#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;
}
30 changes: 30 additions & 0 deletions src/portal/scope.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef __IGLOO_SCOPE_H__
#define __IGLOO_SCOPE_H__

#include <linux/sched.h>
#include <linux/types.h>

/*
* 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__ */
Loading