From 38eac000a68508aff107dee83e3aab1062214298 Mon Sep 17 00:00:00 2001 From: Kornilios Kourtis Date: Fri, 11 Oct 2024 13:45:32 +0200 Subject: [PATCH] enforcer: implement CleanupEnforcerNotification This allows to specify an action (CleanupEnforcerNotification) that checks whether the enforcer notification succeeded. For example, the following policy: ``` apiVersion: cilium.io/v1alpha1 kind: TracingPolicy metadata: name: "kill-syscalls" spec: enforcers: - calls: - "sys_swapoff" # - "sys_getcpu" tracepoints: - subsystem: "raw_syscalls" event: "sys_enter" args: - index: 4 type: "syscall64" selectors: - matchArgs: - index: 0 operator: "InMap" values: - 309 # getcpu - 168 # swapoff matchActions: - action: "NotifyEnforcer" argError: -1 argSig: 9 - subsystem: "raw_syscalls" event: "sys_exit" selectors: - matchActions: - action: "CleanupEnforcerNotification" - action: "NoPost" ``` Detects missing notifications by adding such a function in the raw_syscalls/sys_exit tracepoint. This means that missed enforcements can be detected even if there is no other notifcation for the same thread. The metric output in this case would be: tetragon_enforcer_missed_notifications_total{info="getcpu",policy="kill-syscalls",reason="no_action"} 3 Signed-off-by: Kornilios Kourtis --- bpf/process/bpf_enforcer.h | 16 ++++ bpf/process/types/basic.h | 3 + pkg/api/tracingapi/client_kprobe.go | 27 +++--- pkg/grpc/tracing/tracing.go | 2 + .../enforcermetrics/enforcermetrics.go | 2 + pkg/selectors/kernel.go | 84 ++++++++++--------- 6 files changed, 81 insertions(+), 53 deletions(-) diff --git a/bpf/process/bpf_enforcer.h b/bpf/process/bpf_enforcer.h index f71107870ae..2686c383e5c 100644 --- a/bpf/process/bpf_enforcer.h +++ b/bpf/process/bpf_enforcer.h @@ -28,6 +28,7 @@ struct { enum enforcer_missed_reason { ENFORCER_MISSED_OVERWRITTEN = 1, + ENFORCER_MISSED_NOACTION = 2, }; struct enforcer_missed_key { @@ -67,6 +68,21 @@ enforcer_update_missed_notifications(struct enforcer_missed_key *key) } } +FUNC_INLINE void do_enforcer_cleanup(void) +{ + struct enforcer_data *ptr; + __u64 id = get_current_pid_tgid(); + + ptr = map_lookup_elem(&enforcer_data, &id); + if (ptr) { + struct enforcer_missed_key missed_key = { + .act_info = ptr->act_info, + .reason = ENFORCER_MISSED_NOACTION, + }; + enforcer_update_missed_notifications(&missed_key); + } +} + FUNC_INLINE void do_enforcer_action(int error, int signal, struct enforcer_act_info act_info) { __u64 id = get_current_pid_tgid(); diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index c76192c969a..dea49981378 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -109,6 +109,7 @@ enum { ACTION_TRACKSOCK = 10, ACTION_UNTRACKSOCK = 11, ACTION_NOTIFY_ENFORCER = 12, + ACTION_CLEANUP_ENFORCER_NOTIFICATION = 13, }; enum { @@ -2281,6 +2282,8 @@ do_action(void *ctx, __u32 i, struct selector_action *actions, argi = actions->act[++i]; do_action_notify_enforcer(e, error, signal, argi); break; + case ACTION_CLEANUP_ENFORCER_NOTIFICATION: + do_enforcer_cleanup(); default: break; } diff --git a/pkg/api/tracingapi/client_kprobe.go b/pkg/api/tracingapi/client_kprobe.go index f8a609484e2..67d0f15a154 100644 --- a/pkg/api/tracingapi/client_kprobe.go +++ b/pkg/api/tracingapi/client_kprobe.go @@ -12,19 +12,20 @@ const ( ) const ( - ActionPost = 0 - ActionFollowFd = 1 - ActionSigKill = 2 - ActionUnfollowFd = 3 - ActionOverride = 4 - ActionCopyFd = 5 - ActionGetUrl = 6 - ActionLookupDns = 7 - ActionNoPost = 8 - ActionSignal = 9 - ActionTrackSock = 10 - ActionUntrackSock = 11 - ActionNotifyEnforcer = 12 + ActionPost = 0 + ActionFollowFd = 1 + ActionSigKill = 2 + ActionUnfollowFd = 3 + ActionOverride = 4 + ActionCopyFd = 5 + ActionGetUrl = 6 + ActionLookupDns = 7 + ActionNoPost = 8 + ActionSignal = 9 + ActionTrackSock = 10 + ActionUntrackSock = 11 + ActionNotifyEnforcer = 12 + ActionCleanupEnforcerNotification = 13 ) const ( diff --git a/pkg/grpc/tracing/tracing.go b/pkg/grpc/tracing/tracing.go index 052b957659c..e0176435df7 100644 --- a/pkg/grpc/tracing/tracing.go +++ b/pkg/grpc/tracing/tracing.go @@ -63,6 +63,8 @@ func kprobeAction(act uint64) tetragon.KprobeAction { return tetragon.KprobeAction_KPROBE_ACTION_UNTRACKSOCK case tracingapi.ActionNotifyEnforcer: return tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER + case tracingapi.ActionCleanupEnforcerNotification: + return tetragon.KprobeAction_KPROBE_ACTION_CLEANUPENFORCERNOTIFICATION default: return tetragon.KprobeAction_KPROBE_ACTION_UNKNOWN } diff --git a/pkg/metrics/enforcermetrics/enforcermetrics.go b/pkg/metrics/enforcermetrics/enforcermetrics.go index 2bf93496eac..5c038bcf251 100644 --- a/pkg/metrics/enforcermetrics/enforcermetrics.go +++ b/pkg/metrics/enforcermetrics/enforcermetrics.go @@ -85,6 +85,8 @@ func (mk *enforcerMissedMapKey) reason() string { switch mk.Reason { case 1: return "overwritten" + case 2: + return "no_action" default: return "unspecified" } diff --git a/pkg/selectors/kernel.go b/pkg/selectors/kernel.go index bd3b39fffdd..7d4f02d8740 100644 --- a/pkg/selectors/kernel.go +++ b/pkg/selectors/kernel.go @@ -22,52 +22,54 @@ import ( ) const ( - ActionTypeInvalid = -1 - ActionTypePost = 0 - ActionTypeFollowFd = 1 - ActionTypeSigKill = 2 - ActionTypeUnfollowFd = 3 - ActionTypeOverride = 4 - ActionTypeCopyFd = 5 - ActionTypeGetUrl = 6 - ActionTypeDnsLookup = 7 - ActionTypeNoPost = 8 - ActionTypeSignal = 9 - ActionTypeTrackSock = 10 - ActionTypeUntrackSock = 11 - ActionTypeNotifyEnforcer = 12 + ActionTypeInvalid = -1 + ActionTypePost = 0 + ActionTypeFollowFd = 1 + ActionTypeSigKill = 2 + ActionTypeUnfollowFd = 3 + ActionTypeOverride = 4 + ActionTypeCopyFd = 5 + ActionTypeGetUrl = 6 + ActionTypeDnsLookup = 7 + ActionTypeNoPost = 8 + ActionTypeSignal = 9 + ActionTypeTrackSock = 10 + ActionTypeUntrackSock = 11 + ActionTypeNotifyEnforcer = 12 + ActionTypeCleanupEnforcerNotification = 13 ) var actionTypeTable = map[string]uint32{ - "post": ActionTypePost, - "followfd": ActionTypeFollowFd, - "unfollowfd": ActionTypeUnfollowFd, - "sigkill": ActionTypeSigKill, - "override": ActionTypeOverride, - "copyfd": ActionTypeCopyFd, - "geturl": ActionTypeGetUrl, - "dnslookup": ActionTypeDnsLookup, - "nopost": ActionTypeNoPost, - "signal": ActionTypeSignal, - "tracksock": ActionTypeTrackSock, - "untracksock": ActionTypeUntrackSock, - "notifyenforcer": ActionTypeNotifyEnforcer, + "post": ActionTypePost, + "followfd": ActionTypeFollowFd, + "unfollowfd": ActionTypeUnfollowFd, + "sigkill": ActionTypeSigKill, + "override": ActionTypeOverride, + "copyfd": ActionTypeCopyFd, + "geturl": ActionTypeGetUrl, + "dnslookup": ActionTypeDnsLookup, + "nopost": ActionTypeNoPost, + "signal": ActionTypeSignal, + "tracksock": ActionTypeTrackSock, + "untracksock": ActionTypeUntrackSock, + "notifyenforcer": ActionTypeNotifyEnforcer, + "cleanupenforcernotification": ActionTypeCleanupEnforcerNotification, } var actionTypeStringTable = map[uint32]string{ - ActionTypePost: "post", - ActionTypeFollowFd: "followfd", - ActionTypeUnfollowFd: "unfollowfd", - ActionTypeSigKill: "sigkill", - ActionTypeOverride: "override", - ActionTypeCopyFd: "copyfd", - ActionTypeGetUrl: "geturl", - ActionTypeDnsLookup: "dnslookup", - ActionTypeNoPost: "nopost", - ActionTypeSignal: "signal", - ActionTypeTrackSock: "tracksock", - ActionTypeUntrackSock: "untracksock", - ActionTypeNotifyEnforcer: "notifyenforcer", + ActionTypePost: "post", + ActionTypeFollowFd: "followfd", + ActionTypeUnfollowFd: "unfollowfd", + ActionTypeSigKill: "sigkill", + ActionTypeOverride: "override", + ActionTypeCopyFd: "copyfd", + ActionTypeGetUrl: "geturl", + ActionTypeDnsLookup: "dnslookup", + ActionTypeNoPost: "nopost", + ActionTypeSignal: "signal", + ActionTypeTrackSock: "tracksock", + ActionTypeUntrackSock: "untracksock", + ActionTypeCleanupEnforcerNotification: "cleanupenforcernotification", } const ( @@ -981,6 +983,8 @@ func ParseMatchAction(k *KernelSelectorState, action *v1alpha1.ActionSelector, a actionArgIndex = *(action.EnforcerNotifyActionArgIndex) } WriteSelectorUint32(&k.data, actionArgIndex) + case ActionTypeCleanupEnforcerNotification: + // no arguments default: return fmt.Errorf("ParseMatchAction: act %d (%s) is missing a handler", act, actionTypeStringTable[act]) }