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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ COPY gadgets gadgets

# Build gadgets
RUN mkdir -p build/gadgets && \
for gadget in fs-restrict cap-restrict ptrace-restrict binary-attestation; do \
for gadget in fs-restrict cap-restrict ptrace-restrict socket-restrict binary-attestation; do \
echo "Building gadget: $gadget" && \
ig image build \
--local \
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ GOARCHS := amd64 arm64
LDFLAGS := -X github.com/inspektor-gadget/inspektor-gadget/internal/version.version=v0.47.0 \
-X main.Version=$(IMAGE_TAG) \
-w -s -extldflags "-static"
GADGETS := fs-restrict cap-restrict ptrace-restrict binary-attestation
GADGETS := fs-restrict cap-restrict ptrace-restrict socket-restrict binary-attestation
CONFORM_VERSION ?= v0.1.0-alpha.30

# This version number must be kept in sync with CI workflow lint one.
Expand Down Expand Up @@ -89,6 +89,10 @@ run-fs-restrict:
run-cap-restrict:
sudo -E ig run $(CONTAINER_REPO)/cap-restrict:$(IMAGE_TAG) $$PARAMS

.PHONY: run-socket-restrict
run-socket-restrict:
sudo -E ig run $(CONTAINER_REPO)/socket-restrict:$(IMAGE_TAG) $$PARAMS

.PHONY: push
push:
for gadget in $(GADGETS); do \
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Today, Micromize attaches eBPF programs to LSM hooks and enforces:
- **Strict container boundaries** — blocks filesystem escapes and host access
- **Capability restriction** — prevents privilege escalation via `unshare`/`clone`/`setns`
- **Ptrace blocking** — eliminates ptrace-based debugging/injection attacks
- **Socket restriction** — blocks `AF_ALG` (kernel crypto userspace API) socket usage in containers, mitigating CVE-2026-31431 and related attack surface
- **Execution integrity** — SBOM + runtime hash validation via `bpf_ima_file_hash`

Policies are loaded before container start and enforced at execution time. No runtime replacement. No learning mode. Kernel-native enforcement.
Expand Down
3 changes: 3 additions & 0 deletions cmd/micromize/embeds.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ var capRestrictGadgetBytes []byte
//go:embed build/ptrace-restrict.tar
var ptraceRestrictGadgetBytes []byte

//go:embed build/socket-restrict.tar
var socketRestrictGadgetBytes []byte

//go:embed build/binary-attestation.tar
var binaryAttestationGadgetBytes []byte
1 change: 1 addition & 0 deletions cmd/micromize/embeds_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ package main
var fsRestrictGadgetBytes []byte
var capRestrictGadgetBytes []byte
var ptraceRestrictGadgetBytes []byte
var socketRestrictGadgetBytes []byte
var binaryAttestationGadgetBytes []byte
7 changes: 7 additions & 0 deletions cmd/micromize/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
fsRestrictGadgetImageRepo = "ghcr.io/micromize-dev/micromize/fs-restrict"
capRestrictGadgetImageRepo = "ghcr.io/micromize-dev/micromize/cap-restrict"
ptraceRestrictGadgetImageRepo = "ghcr.io/micromize-dev/micromize/ptrace-restrict"
socketRestrictGadgetImageRepo = "ghcr.io/micromize-dev/micromize/socket-restrict"
binaryAttestationGadgetImageRepo = "ghcr.io/micromize-dev/micromize/binary-attestation"
)

Expand Down Expand Up @@ -161,6 +162,12 @@ func run(ctx context.Context) error {
Params: commonParams,
})

registry.Register("socket-restrict", &gadget.GadgetConfig{
Bytes: socketRestrictGadgetBytes,
ImageName: fmt.Sprintf("%s:%s", socketRestrictGadgetImageRepo, Version),
Params: commonParams,
})

registry.Register("binary-attestation", &gadget.GadgetConfig{
Bytes: binaryAttestationGadgetBytes,
ImageName: fmt.Sprintf("%s:%s", binaryAttestationGadgetImageRepo, Version),
Expand Down
27 changes: 27 additions & 0 deletions gadgets/socket-restrict/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# socket-restrict

Restrict dangerous socket primitives in containers.

This gadget blocks all `AF_ALG` (kernel crypto userspace API) socket usage
inside containers. `AF_ALG` is rarely needed in containerized production
workloads — most TLS, SSH, and dm-crypt use cases never touch it — and
blocking it eliminates a class of kernel attack surface from the container
boundary.

The initial motivation is CVE-2026-31431 (Copy Fail), a Linux kernel local
privilege escalation in `algif_aead` that can be triggered via `AF_ALG`
sockets. This gadget blocks the entire killchain at socket creation time,
before any vulnerable kernel path is reached.

## Hooks

| Hook | Purpose |
|---|---|
| `lsm/socket_create` | Block `AF_ALG` socket creation (main choke point) |
| `lsm/socket_bind` | Defense-in-depth: block `AF_ALG` bind if a socket FD exists from before policy load. Preserves `alg_type`/`alg_name` for visibility. |

Comment thread
dorser marked this conversation as resolved.
Comment thread
dorser marked this conversation as resolved.
## Getting Started

```bash
sudo ig run ghcr.io/micromize-dev/micromize/gadgets/socket-restrict:latest
```
55 changes: 55 additions & 0 deletions gadgets/socket-restrict/gadget.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: socket-restrict
description: Restrict dangerous socket primitives in containers
homepageURL: https://github.com/micromize-dev/micromize/tree/main/gadgets/socket-restrict
documentationURL: https://github.com/micromize-dev/micromize/tree/main/gadgets/socket-restrict
sourceURL: https://github.com/micromize-dev/micromize/tree/main/gadgets/socket-restrict
datasources:
socket_restrict:
fields:
alg_name:
annotations:
description: The AF_ALG algorithm name requested by the process
alg_type:
annotations:
description: The AF_ALG algorithm type requested by the process
event_type:
annotations:
description: Numeric event type identifier
family:
annotations:
description: Socket address family
process:
annotations:
description: The process attempting a restricted socket operation
reason:
annotations:
description: Human-readable reason for the event
timestamp_raw:
annotations:
description: Timestamp of the event
params:
ebpf:
enforce:
key: enforce
defaultValue: "true"
description: Enforce the restriction (block) or just audit
targ_comm:
key: targ_comm
defaultValue: ""
description: Process name (comm)
targ_gid:
key: targ_gid
defaultValue: ""
description: Group ID
targ_pid:
key: targ_pid
defaultValue: ""
description: Process ID
targ_tid:
key: targ_tid
defaultValue: ""
description: Thread ID
targ_uid:
key: targ_uid
defaultValue: ""
description: User ID
106 changes: 106 additions & 0 deletions gadgets/socket-restrict/program.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/* Copyright (c) 2024 micromize-Authors */

#include "program.bpf.h"

#include <vmlinux.h>

#include <gadget/buffer.h>
#include <gadget/filter.h>
#include <gadget/macros.h>

const volatile int enforce = 1;
GADGET_PARAM(enforce);

GADGET_TRACER_MAP(events, 1024 * 256);

GADGET_TRACER(socket_restrict, events, event);

// Block AF_ALG socket creation — main choke point.
SEC("lsm/socket_create")
int BPF_PROG(micromize_socket_create, int family, int type, int protocol,
int kern) {
if (kern)
return 0;

if (gadget_should_discard_data_current())
return 0;

if (family != AF_ALG)
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_SOCKET_AF_ALG_CREATE;
event->family = AF_ALG;
event->alg_type[0] = '\0';
event->alg_name[0] = '\0';

gadget_submit_buf(ctx, &events, event, sizeof(*event));

if (enforce)
return -EPERM;

return 0;
}

// Defense-in-depth: block AF_ALG bind if a socket FD exists from before
// policy load. Preserves alg_type/alg_name for visibility.
SEC("lsm/socket_bind")
int BPF_PROG(micromize_socket_bind, struct socket *sock,
struct sockaddr *address, int addrlen) {
(void)sock;
Comment thread
dorser marked this conversation as resolved.

if (gadget_should_discard_data_current())
return 0;

if (!address || addrlen < SOCKADDR_ALG_TYPE_END)
return 0;

__u16 family = 0;
bpf_probe_read_kernel(&family, sizeof(family), address);
if (family != AF_ALG)
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_SOCKET_AF_ALG_BIND;
event->family = family;

bpf_probe_read_kernel(event->alg_type, SOCKADDR_ALG_TYPE_LEN,
(const char *)address + SOCKADDR_ALG_TYPE_OFFSET);
event->alg_type[SOCKADDR_ALG_TYPE_LEN] = '\0';

if (addrlen >= SOCKADDR_ALG_MIN_LEN) {
bpf_probe_read_kernel(event->alg_name, SOCKADDR_ALG_NAME_LEN,
(const char *)address + SOCKADDR_ALG_NAME_OFFSET);
event->alg_name[SOCKADDR_ALG_NAME_LEN - 1] = '\0';
Comment thread
dorser marked this conversation as resolved.
} else {
event->alg_name[0] = '\0';
}

gadget_submit_buf(ctx, &events, event, sizeof(*event));

if (enforce)
return -EPERM;

return 0;
}

char LICENSE[] SEC("license") = "GPL";
32 changes: 32 additions & 0 deletions gadgets/socket-restrict/program.bpf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/* Copyright (c) 2024 micromize-Authors */

#include <gadget/common.h>
#include <micromize/event_types.h>

#ifndef EPERM
#define EPERM 1
#endif

#ifndef AF_ALG
#define AF_ALG 38
#endif

#define SOCKADDR_ALG_TYPE_OFFSET 2
#define SOCKADDR_ALG_TYPE_LEN 14
#define SOCKADDR_ALG_TYPE_END (SOCKADDR_ALG_TYPE_OFFSET + SOCKADDR_ALG_TYPE_LEN)

#define SOCKADDR_ALG_NAME_OFFSET 24
#define SOCKADDR_ALG_NAME_LEN 64
#define SOCKADDR_ALG_MIN_LEN (SOCKADDR_ALG_NAME_OFFSET + SOCKADDR_ALG_NAME_LEN)

#define EVENT_ALG_TYPE_LEN (SOCKADDR_ALG_TYPE_LEN + 1)

struct event {
gadget_timestamp timestamp_raw;
struct gadget_process process;
__u32 event_type;
__u32 family;
char alg_type[EVENT_ALG_TYPE_LEN];
char alg_name[SOCKADDR_ALG_NAME_LEN];
};
4 changes: 4 additions & 0 deletions include/micromize/event_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ enum micromize_event_type {
EVENT_TYPE_HASH_MISMATCH = 8,
EVENT_TYPE_UNATTESTED_SHARED_OBJECT = 9,
EVENT_TYPE_SHARED_OBJECT_HASH_MISMATCH = 10,

// socket-restrict
EVENT_TYPE_SOCKET_AF_ALG_CREATE = 11,
EVENT_TYPE_SOCKET_AF_ALG_BIND = 12,
};

#endif /* __MICROMIZE_EVENT_TYPES_H */
4 changes: 4 additions & 0 deletions internal/operators/operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ const (
eventTypeHashMismatch = 8
eventTypeUnattestedSharedObject = 9
eventTypeSharedObjectHashMismatch = 10
eventTypeSocketAFAlgCreate = 11
eventTypeSocketAFAlgBind = 12
)

var eventTypeNames = map[uint32]string{
Expand All @@ -321,6 +323,8 @@ var eventTypeNames = map[uint32]string{
eventTypeHashMismatch: "hash_mismatch",
eventTypeUnattestedSharedObject: "unattested_shared_object",
eventTypeSharedObjectHashMismatch: "shared_object_hash_mismatch",
eventTypeSocketAFAlgCreate: "af_alg_socket_create",
eventTypeSocketAFAlgBind: "af_alg_socket_bind",
}

// NewEventTypeOperator creates an operator that enriches events with a
Expand Down
14 changes: 14 additions & 0 deletions internal/operators/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ var eventDescriptions = map[uint32]string{
eventTypeHashMismatch: "Binary hash mismatch detected",
eventTypeUnattestedSharedObject: "Unattested shared object loaded",
eventTypeSharedObjectHashMismatch: "Shared object hash mismatch detected",
eventTypeSocketAFAlgCreate: "AF_ALG socket creation blocked",
eventTypeSocketAFAlgBind: "AF_ALG socket bind blocked",
}

var eventEmojis = map[uint32]string{}
Expand Down Expand Up @@ -73,6 +75,10 @@ type eventFields struct {
// Cap-restrict specific
cap datasource.FieldAccessor
syscall datasource.FieldAccessor

// socket-restrict specific
algType datasource.FieldAccessor
algName datasource.FieldAccessor
}

var (
Expand Down Expand Up @@ -173,6 +179,8 @@ func collectEventFields(ds datasource.DataSource, etField datasource.FieldAccess

f.cap = ds.GetField("cap")
f.syscall = ds.GetField("syscall")
f.algType = ds.GetField("alg_type")
f.algName = ds.GetField("alg_name")

return f
}
Expand Down Expand Up @@ -205,6 +213,12 @@ func formatAndPrintEvent(f *eventFields, data datasource.Data) {
if filename := fieldStr(f.filename, data); filename != "" {
fmt.Fprintf(&sb, ". Filename: %s", filename)
}
if algType := fieldStr(f.algType, data); algType != "" {
fmt.Fprintf(&sb, ". AF_ALG type: %s", algType)
if algName := fieldStr(f.algName, data); algName != "" {
fmt.Fprintf(&sb, ". Algorithm: %s", algName)
}
}

// Show image name only for Docker (non-k8s) environments
if fieldStr(f.k8sNamespace, data) == "" {
Expand Down
Loading
Loading