From aff5e3a597eef2861392aba391c3fbd9195a7749 Mon Sep 17 00:00:00 2001 From: Dor Serero Date: Thu, 30 Apr 2026 21:34:42 +0000 Subject: [PATCH] feat: block kernel module auto-loading from containers Signed-off-by: Dor Serero --- gadgets/cap-restrict/gadget.yaml | 3 +++ gadgets/cap-restrict/program.bpf.c | 30 ++++++++++++++++++++++++++++++ gadgets/cap-restrict/program.bpf.h | 3 +++ include/micromize/event_types.h | 1 + internal/operators/operators.go | 2 ++ internal/operators/output.go | 8 ++++++++ 6 files changed, 47 insertions(+) diff --git a/gadgets/cap-restrict/gadget.yaml b/gadgets/cap-restrict/gadget.yaml index b866b3e..42d2101 100644 --- a/gadgets/cap-restrict/gadget.yaml +++ b/gadgets/cap-restrict/gadget.yaml @@ -15,6 +15,9 @@ datasources: flags: annotations: description: Flags associated with the operation (e.g., unshare flags) + module_name: + annotations: + description: Name of the kernel module requested for auto-loading process: annotations: description: The process triggering the event diff --git a/gadgets/cap-restrict/program.bpf.c b/gadgets/cap-restrict/program.bpf.c index 1e7ce9d..988dc8b 100644 --- a/gadgets/cap-restrict/program.bpf.c +++ b/gadgets/cap-restrict/program.bpf.c @@ -124,6 +124,36 @@ int BPF_PROG(micromize_capable, const struct cred *cred, event->event_type = (cap == CAP_SYS_MODULE) ? EVENT_TYPE_CAP_MODULE_LOAD : EVENT_TYPE_CAP_NAMESPACE_CREATION; + event->module_name[0] = '\0'; + + gadget_submit_buf(ctx, &events, event, sizeof(*event)); + + if (enforce) + return -EPERM; + + return 0; +} + +SEC("lsm/kernel_module_request") +int BPF_PROG(micromize_kernel_module_request, char *kmod_name) { + if (gadget_should_discard_data_current()) + return 0; + + struct event *event; + event = gadget_reserve_buf(&events, sizeof(*event)); + if (!event) { + if (enforce) + return -EPERM; + return 0; + } + + gadget_process_populate(&event->process); + event->timestamp_raw = bpf_ktime_get_boot_ns(); + event->event_type = EVENT_TYPE_CAP_MODULE_AUTOLOAD; + event->cap = 0; + event->flags = 0; + event->syscall = 0; + bpf_probe_read_kernel_str(event->module_name, MODULE_NAME_LEN, kmod_name); gadget_submit_buf(ctx, &events, event, sizeof(*event)); diff --git a/gadgets/cap-restrict/program.bpf.h b/gadgets/cap-restrict/program.bpf.h index 4cb8c77..f3e534d 100644 --- a/gadgets/cap-restrict/program.bpf.h +++ b/gadgets/cap-restrict/program.bpf.h @@ -44,6 +44,8 @@ #define SYSCALL_SETNS 268 #endif +#define MODULE_NAME_LEN 64 + struct cap_info { unsigned long flags; int syscall; @@ -56,6 +58,7 @@ struct event { int cap; unsigned long flags; int syscall; + char module_name[MODULE_NAME_LEN]; }; struct { diff --git a/include/micromize/event_types.h b/include/micromize/event_types.h index 1197916..90011ee 100644 --- a/include/micromize/event_types.h +++ b/include/micromize/event_types.h @@ -14,6 +14,7 @@ enum micromize_event_type { // cap-restrict EVENT_TYPE_CAP_NAMESPACE_CREATION = 3, EVENT_TYPE_CAP_MODULE_LOAD = 4, + EVENT_TYPE_CAP_MODULE_AUTOLOAD = 13, // ptrace-restrict EVENT_TYPE_PTRACE_ACCESS = 5, diff --git a/internal/operators/operators.go b/internal/operators/operators.go index c76deb2..c1b79ea 100644 --- a/internal/operators/operators.go +++ b/internal/operators/operators.go @@ -309,6 +309,7 @@ const ( eventTypeSharedObjectHashMismatch = 10 eventTypeSocketAFAlgCreate = 11 eventTypeSocketAFAlgBind = 12 + eventTypeCapModuleAutoload = 13 ) var eventTypeNames = map[uint32]string{ @@ -325,6 +326,7 @@ var eventTypeNames = map[uint32]string{ eventTypeSharedObjectHashMismatch: "shared_object_hash_mismatch", eventTypeSocketAFAlgCreate: "af_alg_socket_create", eventTypeSocketAFAlgBind: "af_alg_socket_bind", + eventTypeCapModuleAutoload: "module_autoload", } // NewEventTypeOperator creates an operator that enriches events with a diff --git a/internal/operators/output.go b/internal/operators/output.go index d9392fa..a55416d 100644 --- a/internal/operators/output.go +++ b/internal/operators/output.go @@ -41,6 +41,7 @@ var eventDescriptions = map[uint32]string{ eventTypeSharedObjectHashMismatch: "Shared object hash mismatch detected", eventTypeSocketAFAlgCreate: "AF_ALG socket creation blocked", eventTypeSocketAFAlgBind: "AF_ALG socket bind blocked", + eventTypeCapModuleAutoload: "Kernel module auto-load blocked", } var eventEmojis = map[uint32]string{} @@ -79,6 +80,9 @@ type eventFields struct { // socket-restrict specific algType datasource.FieldAccessor algName datasource.FieldAccessor + + // cap-restrict module autoload + moduleName datasource.FieldAccessor } var ( @@ -181,6 +185,7 @@ func collectEventFields(ds datasource.DataSource, etField datasource.FieldAccess f.syscall = ds.GetField("syscall") f.algType = ds.GetField("alg_type") f.algName = ds.GetField("alg_name") + f.moduleName = ds.GetField("module_name") return f } @@ -219,6 +224,9 @@ func formatAndPrintEvent(f *eventFields, data datasource.Data) { fmt.Fprintf(&sb, ". Algorithm: %s", algName) } } + if modName := fieldStr(f.moduleName, data); modName != "" { + fmt.Fprintf(&sb, ". Module: %s", modName) + } // Show image name only for Docker (non-k8s) environments if fieldStr(f.k8sNamespace, data) == "" {