diff --git a/internal/pkg/daemon/bpfrecorder/bpf/recorder.bpf.c b/internal/pkg/daemon/bpfrecorder/bpf/recorder.bpf.c index 4e996016bd..7ef00880dc 100644 --- a/internal/pkg/daemon/bpfrecorder/bpf/recorder.bpf.c +++ b/internal/pkg/daemon/bpfrecorder/bpf/recorder.bpf.c @@ -20,6 +20,7 @@ #define EVENT_TYPE_APPARMOR_FILE 2 #define EVENT_TYPE_APPARMOR_SOCKET 3 #define EVENT_TYPE_APPARMOR_CAP 4 +#define EVENT_TYPE_CLEAR_MNTNS 5 #define FLAG_READ 0x1 #define FLAG_WRITE 0x2 @@ -51,6 +52,8 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; #define unlikely(x) __builtin_expect((x), 0) #endif +#define trace_hook(...) bpf_printk(__VA_ARGS__) + // Track syscalls for each mtnns struct { __uint(type, BPF_MAP_TYPE_HASH); @@ -93,6 +96,7 @@ typedef struct __attribute__((__packed__)) event_data { const volatile char filter_name[MAX_COMM_LEN] = {}; const volatile u32 exclude_mntns = 0; +static const char RUNC_DONE[] = "runc:[2:INIT]"; static const bool TRUE = true; static inline bool has_filter(); static inline bool matches_filter(char * comm); @@ -322,6 +326,36 @@ int BPF_KPROBE(cap_capable) return 0; } +SEC("tracepoint/sched/sched_prepare_exec") +int sched_prepare_exec(struct trace_event_raw_sched_process_exec * ctx) +{ + u32 mntns = get_mntns(); + if (!mntns) + return 0; + char comm[TASK_COMM_LEN] = {}; + bpf_get_current_comm(comm, sizeof(comm)); + // trace_hook("sched_prepare_exec mntns=%u comm=%s", mntns, comm); + + for (int i = 0; i < sizeof(RUNC_DONE); i++) { + if (comm[i] != RUNC_DONE[i]) { + return 0; + } + } + + trace_hook("clearing mount namespace: %u", mntns); + + bpf_map_delete_elem(&mntns_syscalls, &mntns); + event_data_t * event = bpf_ringbuf_reserve(&events, sizeof(event_data_t), 0); + if (event) { + event->pid = bpf_get_current_pid_tgid() >> 32; + event->mntns = mntns; + event->type = EVENT_TYPE_CLEAR_MNTNS; + bpf_ringbuf_submit(event, 0); + } + + return 0; +} + SEC("tracepoint/sched/sched_process_exec") int sched_process_exec(struct trace_event_raw_sched_process_exec * ctx) { diff --git a/internal/pkg/daemon/bpfrecorder/bpfrecorder.go b/internal/pkg/daemon/bpfrecorder/bpfrecorder.go index 2235702ea3..baba82af29 100644 --- a/internal/pkg/daemon/bpfrecorder/bpfrecorder.go +++ b/internal/pkg/daemon/bpfrecorder/bpfrecorder.go @@ -71,6 +71,7 @@ const ( eventTypeAppArmorFile int = 2 eventTypeAppArmorSocket int = 3 eventTypeAppArmorCap int = 4 + eventTypeClearMntns int = 5 ) // BpfRecorder is the main structure of this package. @@ -409,6 +410,7 @@ func (b *BpfRecorder) getMntnsForProfile(profile string) (uint32, bool) { var baseHooks = []string{ "sys_enter", + "sched_prepare_exec", "sched_process_exec", "sched_process_exit", } @@ -662,6 +664,8 @@ func (b *BpfRecorder) handleEvent(eventBytes []byte) { b.AppArmor.handleSocketEvent(&event) case uint8(eventTypeAppArmorCap): b.AppArmor.handleCapabilityEvent(&event) + case uint8(eventTypeClearMntns): + b.AppArmor.clearMntns(&event) } } diff --git a/internal/pkg/daemon/bpfrecorder/bpfrecorder_apparmor.go b/internal/pkg/daemon/bpfrecorder/bpfrecorder_apparmor.go index 20b7b1ccdc..7022191568 100644 --- a/internal/pkg/daemon/bpfrecorder/bpfrecorder_apparmor.go +++ b/internal/pkg/daemon/bpfrecorder/bpfrecorder_apparmor.go @@ -203,6 +203,27 @@ func (b *AppArmorRecorder) handleCapabilityEvent(capEvent *bpfEvent) { b.recordedCapabilities[mid] = append(b.recordedCapabilities[mid], requestedCap) } +// Delete all data recorded for a particular mount namespace. +// +// The recorder triggers this after container initialization to make sure that +// permissions needed for setup are not included in the final profile. +func (b *AppArmorRecorder) clearMntns(event *bpfEvent) { + // Everything we captured so far is container initialization. + // Let's get rid of it. + b.lockRecordedFiles.Lock() + defer b.lockRecordedFiles.Unlock() + b.lockRecordedCapabilities.Lock() + defer b.lockRecordedCapabilities.Unlock() + b.lockRecordedSocketsUse.Lock() + defer b.lockRecordedSocketsUse.Unlock() + + mntns := mntnsID(event.Mntns) + log.Printf("Clearing mntns: %d\n", mntns) + delete(b.recordedFiles, mntns) + delete(b.recordedCapabilities, mntns) + delete(b.recordedSocketsUse, mntns) +} + func (b *AppArmorRecorder) GetKnownMntns() []mntnsID { b.lockRecordedFiles.Lock() defer b.lockRecordedFiles.Unlock()