From a0f27b83adb636c0b69b044a485bdc394db2f90c Mon Sep 17 00:00:00 2001 From: Jianlin Lv Date: Sun, 28 Jan 2024 21:28:12 -0700 Subject: [PATCH] bpf & pkg: Add selectors for audit ids This commits introduces the "matchLoginUids" selectors, support filtering based on the audit id of process. A process is given an audit ID on user login, that is the loginuid. This ID set during user authentication and handed down to any child process started by the initial process of the user, even when the user's identity changes. the `matchLoginUids` filter supports defining up to four operators, - `Equal` - `NotEqual` - `GreaterThan` - `LessThan` which are logically `AND` together. The loginuid is used to track user's activity. For example, the following matchLoginUids filter allow to follow operation performed by user id 1000. ``` - matchLoginUids: - operator: "Equal" values: - 1000 ``` Signed-off-by: Jianlin Lv --- bpf/lib/process.h | 2 +- bpf/process/bpf_execve_event.c | 1 + bpf/process/bpf_exit.h | 5 +- bpf/process/bpf_generic_retkprobe.c | 5 +- bpf/process/generic_calls.h | 5 - bpf/process/pfilter.h | 118 +++++++++++++++++- bpf/process/types/basic.h | 2 + .../docs/concepts/tracing-policy/selectors.md | 24 ++++ pkg/api/processapi/processapi.go | 2 +- pkg/grpc/exec/exec_test_helper.go | 12 +- .../v1alpha1/cilium.io_tracingpolicies.yaml | 69 ++++++++++ .../cilium.io_tracingpoliciesnamespaced.yaml | 69 ++++++++++ pkg/k8s/apis/cilium.io/v1alpha1/types.go | 11 ++ pkg/k8s/apis/cilium.io/v1alpha1/version.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 28 +++++ pkg/selectors/kernel.go | 40 ++++++ pkg/selectors/kernel_test.go | 77 +++++++++++- .../v1alpha1/cilium.io_tracingpolicies.yaml | 69 ++++++++++ .../cilium.io_tracingpoliciesnamespaced.yaml | 69 ++++++++++ .../pkg/k8s/apis/cilium.io/v1alpha1/types.go | 11 ++ .../k8s/apis/cilium.io/v1alpha1/version.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 28 +++++ 22 files changed, 621 insertions(+), 30 deletions(-) diff --git a/bpf/lib/process.h b/bpf/lib/process.h index bdadea67115..9594b721447 100644 --- a/bpf/lib/process.h +++ b/bpf/lib/process.h @@ -151,7 +151,7 @@ struct msg_execve_key { __u32 pid; // Process TGID - __u8 pad[4]; + __u32 auid; // loginuid __u64 ktime; }; // All fields aligned so no 'packed' attribute. diff --git a/bpf/process/bpf_execve_event.c b/bpf/process/bpf_execve_event.c index a00ae3a115f..3542d33812b 100644 --- a/bpf/process/bpf_execve_event.c +++ b/bpf/process/bpf_execve_event.c @@ -283,6 +283,7 @@ execve_send(struct sched_execve_args *ctx) #endif curr->key.pid = p->pid; curr->key.ktime = p->ktime; + curr->key.auid = p->auid; curr->nspid = p->nspid; curr->pkey = event->parent; if (curr->flags & EVENT_COMMON_FLAG_CLONE) { diff --git a/bpf/process/bpf_exit.h b/bpf/process/bpf_exit.h index b683bac7a5d..7292d04e2bd 100644 --- a/bpf/process/bpf_exit.h +++ b/bpf/process/bpf_exit.h @@ -50,10 +50,7 @@ static inline __attribute__((always_inline)) void event_exit_send(void *ctx, __u exit->common.ktime = ktime_get_ns(); exit->current.pid = tgid; - exit->current.pad[0] = 0; - exit->current.pad[1] = 0; - exit->current.pad[2] = 0; - exit->current.pad[3] = 0; + exit->current.auid = enter->key.auid; exit->current.ktime = enter->key.ktime; /** diff --git a/bpf/process/bpf_generic_retkprobe.c b/bpf/process/bpf_generic_retkprobe.c index f5b9bca0b9a..ee65c51a08e 100644 --- a/bpf/process/bpf_generic_retkprobe.c +++ b/bpf/process/bpf_generic_retkprobe.c @@ -150,12 +150,9 @@ BPF_KRETPROBE(generic_retkprobe_event, unsigned long ret) if (enter) { e->current.pid = enter->key.pid; + e->current.auid = enter->key.auid; e->current.ktime = enter->key.ktime; } - e->current.pad[0] = 0; - e->current.pad[1] = 0; - e->current.pad[2] = 0; - e->current.pad[3] = 0; e->func_id = config->func_id; e->common.size = size; diff --git a/bpf/process/generic_calls.h b/bpf/process/generic_calls.h index d23ac848fbc..9dda93968e6 100644 --- a/bpf/process/generic_calls.h +++ b/bpf/process/generic_calls.h @@ -105,11 +105,6 @@ generic_process_init(struct msg_generic_kprobe *e, u8 op, struct event_config *c e->common.size = 0; e->common.ktime = ktime_get_ns(); - e->current.pad[0] = 0; - e->current.pad[1] = 0; - e->current.pad[2] = 0; - e->current.pad[3] = 0; - e->action = 0; /** diff --git a/bpf/process/pfilter.h b/bpf/process/pfilter.h index d8daf84c237..e0ed98047eb 100644 --- a/bpf/process/pfilter.h +++ b/bpf/process/pfilter.h @@ -135,6 +135,52 @@ process_filter_pid(__u32 i, __u32 off, __u32 *f, __u64 ty, __u64 flags, return __process_filter_pid(ty, flags, sel, pid, enter); } +static inline __attribute__((always_inline)) int +__process_filter_loginuid(__u32 ty, __u32 sel, struct execve_map_value *enter) +{ + __u32 auid; + + auid = enter->key.auid; + + switch (ty) { + case op_filter_lt: + if (sel > auid) + return PFILTER_ACCEPT; + break; + case op_filter_gt: + if (sel < auid) + return PFILTER_ACCEPT; + break; + case op_filter_eq: + if (sel == auid) + return PFILTER_ACCEPT; + break; + case op_filter_neq: + if (sel != auid) + return PFILTER_ACCEPT; + break; + default: + return PFILTER_REJECT; + } + return PFILTER_REJECT; +} + +static inline __attribute__((always_inline)) int +process_filter_loginuid(__u32 i, __u32 off, __u32 *f, __u64 ty, __u64 flags, + struct execve_map_value *enter, struct msg_ns *n, + struct msg_capabilities *c) +{ + __u32 sel; + __u32 o = off; + + o = o / 4; + asm volatile("%[o] &= 0x3ff;\n" ::[o] "+r"(o) + :); + sel = f[o]; + + return __process_filter_loginuid(ty, sel, enter); +} + static inline __attribute__((always_inline)) int process_filter_namespace(__u32 i, __u32 off, __u32 *f, __u64 ty, __u64 nsid, struct execve_map_value *enter, struct msg_ns *n, @@ -310,7 +356,7 @@ selector_match(__u32 *f, __u32 index, __u64 ty, __u64 flags, __u64 len, int res1 = 0, res2 = 0, res3 = 0, res4 = 0; /* For NotIn op we AND results so default to 1 so we fallthru open */ - if (ty == op_filter_notin) + if (ty == op_filter_notin || ty == op_filter_neq) res1 = res2 = res3 = res4 = 1; /* Unrolling this loop was problematic for clang so rather @@ -342,7 +388,7 @@ selector_match(__u32 *f, __u32 index, __u64 ty, __u64 flags, __u64 len, res1 = process_filter(0, index, f, ty, flags, enter, n, c); index = next_pid_value(index, f, ty); - if (ty == op_filter_notin) + if (ty == op_filter_notin || ty == op_filter_neq) return res1 & res2 & res3 & res4; else return res1 | res2 | res3 | res4; @@ -374,6 +420,12 @@ struct nc_filter { u32 value; /* contains all namespaces to monitor (i.e. bit 0 is for ns_uts, bit 1 for ns_ipc etc.) */ } __attribute__((packed)); +struct loginuid_filter { + u32 op; + u32 len; /* number of values */ + u32 val[]; /* values */ +} __attribute__((packed)); + #define VALUES_MASK 0x1f /* max 4 values with 4 bytes each | 0x1f == 31 */ /* If you update the value of NUM_NS_FILTERS_SMALL below you should @@ -381,6 +433,48 @@ struct nc_filter { */ #define NUM_NS_FILTERS_SMALL 4 +static inline __attribute__((always_inline)) int +__process_filter_loginuids(__u32 *f, __u32 *index, struct execve_map_value *enter) +{ + int res = PFILTER_ACCEPT; + struct loginuid_filter *loginuid; + + loginuid = (struct loginuid_filter *)((u64)f + (*index & INDEX_MASK)); + *index += sizeof(struct loginuid_filter); /* 4: op */ + res = selector_match(f, *index, loginuid->op, 0, loginuid->len, + enter, NULL, NULL, &process_filter_loginuid); + + *index += ((loginuid->len * sizeof(loginuid->val[0])) & VALUES_MASK); + + if (res == PFILTER_REJECT) + return res; + + return res; +} + +static inline __attribute__((always_inline)) int +process_filter_loginuids(__u32 *f, __u32 index, struct execve_map_value *enter, int len) +{ + int i = 0; + int loginuid_len = 0; + int res = PFILTER_ACCEPT; + struct loginuid_filter *loginuid; + +#pragma unroll + for (i = 0; i < 4; i++) { + loginuid = (struct loginuid_filter *)((u64)f + (index & INDEX_MASK)); + index += sizeof(struct loginuid_filter); /* 4: op */ + res = selector_match(f, index, loginuid->op, 0, loginuid->len, enter, NULL, NULL, &process_filter_loginuid); + + index += ((loginuid->len * sizeof(loginuid->val[0])) & VALUES_MASK); + loginuid_len += sizeof(struct loginuid_filter) + ((loginuid->len * sizeof(loginuid->val[0])) & VALUES_MASK); + + if (res == PFILTER_REJECT || loginuid_len >= len) + return res; + } + return res; +} + static inline __attribute__((always_inline)) int selector_process_filter(__u32 *f, __u32 index, struct execve_map_value *enter, struct msg_selector_data *sel, struct msg_ns *n, @@ -408,6 +502,10 @@ selector_process_filter(__u32 *f, __u32 index, struct execve_map_value *enter, /* selector section offset by reading the relative offset in the array */ index += *(__u32 *)((__u64)f + (index & INDEX_MASK)); index &= INDEX_MASK; + + len = *(__u32 *)((__u64)f + + (index & + INDEX_MASK)); index += 4; /* skip selector size field */ /* matchPid */ @@ -513,6 +611,22 @@ selector_process_filter(__u32 *f, __u32 index, struct execve_map_value *enter, return res; #endif + /* matchLoginuids */ + len = *(__u32 *)((__u64)f + + (index & + INDEX_MASK)); /* (sizeof(LoginUid1) + sizeof(LoginUid2) + ... + 4) */ + index += 4; /* 4: LoginUid1 header */ + len -= 4; + + if (len > 0) { + res = process_filter_loginuids(f, index, enter, len); + if (res == PFILTER_REJECT) + return res; + + index += (len & VALUES_MASK); + } + if (res == PFILTER_REJECT) + return res; return res; } diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index fb4c1433cd3..5f310d1afb2 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -1768,6 +1768,8 @@ selector_arg_offset(__u8 *f, struct msg_generic_kprobe *e, __u32 selidx, seloff += *(__u32 *)((__u64)f + (seloff & INDEX_MASK)); /* skip the matchCapabilityChanges by reading its length */ seloff += *(__u32 *)((__u64)f + (seloff & INDEX_MASK)); + /* skip the matchLoginuids by reading its length */ + seloff += *(__u32 *)((__u64)f + (seloff & INDEX_MASK)); } /* Making binary selectors fixes size helps on some kernels */ diff --git a/docs/content/en/docs/concepts/tracing-policy/selectors.md b/docs/content/en/docs/concepts/tracing-policy/selectors.md index f1a8ee74483..331b603c2d6 100644 --- a/docs/content/en/docs/concepts/tracing-policy/selectors.md +++ b/docs/content/en/docs/concepts/tracing-policy/selectors.md @@ -19,6 +19,7 @@ A `TracingPolicy` can contain from 0 to 5 selectors. A selector is composed of - [`matchCapabilityChanges`](#capability-changes-filter): filter on Linux capabilities changes. - [`matchActions`](#actions-filter): apply an action on selector matching. - [`matchReturnActions`](#return-actions-filter): apply an action on return selector matching. +- [`matchLoginUids`](#auid-filter): filter on audit ID. ## Arguments filter @@ -1541,3 +1542,26 @@ exist. Return actions filters are a list of actions that execute when an return selector matches. They are defined under `matchReturnActions` and currently support all the [Actions filter](#actions-filter) `action` types. + +## Auid filter + +Auids filters can be specified under the `matchLoginUids` field and provide filtering +based on the value of audit id of the process. For example, the following +`matchLoginUids` filter tells the BPF code that observe only hooks for which the +audit id is not equal to `-1`: + +```yaml +- matchLoginUids: + - operator: "NotEqual" + values: + - 4294967295 +``` + +The available operators for `matchLoginUids` are: +- `Equal` +- `NotEqual` +- `GreaterThan` +- `LessThan` + +In a selector, the `matchLoginUids` filter supports defining up to four operators, +which are logically `AND` together. diff --git a/pkg/api/processapi/processapi.go b/pkg/api/processapi/processapi.go index dffcec3da15..ba0180d6e0d 100644 --- a/pkg/api/processapi/processapi.go +++ b/pkg/api/processapi/processapi.go @@ -63,7 +63,7 @@ type MsgExec struct { type MsgExecveKey struct { Pid uint32 `align:"pid"` - Pad uint32 `align:"pad"` + Auid uint32 `align:"auid"` Ktime uint64 `align:"ktime"` } diff --git a/pkg/grpc/exec/exec_test_helper.go b/pkg/grpc/exec/exec_test_helper.go index d0a0376288e..e5cf3e34ec8 100644 --- a/pkg/grpc/exec/exec_test_helper.go +++ b/pkg/grpc/exec/exec_test_helper.go @@ -99,7 +99,7 @@ func CreateEvents[EXEC notify.Message, EXIT notify.Message](Pid uint32, Ktime ui }, Parent: tetragonAPI.MsgExecveKey{ Pid: 0, - Pad: 0, + Auid: 0, Ktime: 0, }, ParentFlags: 0, @@ -140,7 +140,7 @@ func CreateEvents[EXEC notify.Message, EXIT notify.Message](Pid uint32, Ktime ui }, Parent: tetragonAPI.MsgExecveKey{ Pid: 1, - Pad: 0, + Auid: 0, Ktime: 0, }, ParentFlags: 0, @@ -181,7 +181,7 @@ func CreateEvents[EXEC notify.Message, EXIT notify.Message](Pid uint32, Ktime ui }, Parent: tetragonAPI.MsgExecveKey{ Pid: ParentPid, - Pad: 0, + Auid: 0, Ktime: ParentKtime, }, ParentFlags: 0, @@ -215,7 +215,7 @@ func CreateEvents[EXEC notify.Message, EXIT notify.Message](Pid uint32, Ktime ui }, ProcessKey: tetragonAPI.MsgExecveKey{ Pid: Pid, - Pad: 0, + Auid: 0, Ktime: Ktime, }, Info: tetragonAPI.MsgExitInfo{ @@ -241,7 +241,7 @@ func CreateCloneEvents[CLONE notify.Message, EXIT notify.Message](Pid uint32, Kt }, Parent: tetragonAPI.MsgExecveKey{ Pid: ParentPid, - Pad: 0, + Auid: 0, Ktime: ParentKtime, }, PID: Pid, @@ -263,7 +263,7 @@ func CreateCloneEvents[CLONE notify.Message, EXIT notify.Message](Pid uint32, Kt }, ProcessKey: tetragonAPI.MsgExecveKey{ Pid: Pid, - Pad: 0, + Auid: 0, Ktime: Ktime, }, Info: tetragonAPI.MsgExitInfo{ diff --git a/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml b/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml index dc23dfaa56a..aff6150a2bb 100644 --- a/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml +++ b/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml @@ -467,6 +467,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1123,6 +1146,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1680,6 +1726,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: diff --git a/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml b/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml index 8ff37a67567..973379bcd25 100644 --- a/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml +++ b/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml @@ -467,6 +467,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1123,6 +1146,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1680,6 +1726,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: diff --git a/pkg/k8s/apis/cilium.io/v1alpha1/types.go b/pkg/k8s/apis/cilium.io/v1alpha1/types.go index 7a6cc982d23..685527a7d49 100644 --- a/pkg/k8s/apis/cilium.io/v1alpha1/types.go +++ b/pkg/k8s/apis/cilium.io/v1alpha1/types.go @@ -125,6 +125,9 @@ type KProbeSelector struct { // +kubebuilder:validation:Optional // IDs for capabilities changes MatchCapabilityChanges []CapabilitiesSelector `json:"matchCapabilityChanges,omitempty"` + // +kubebuilder:validation:Optional + // A list of login uid filters. + MatchLoginUids []LoginUidSelector `json:"matchLoginUids,omitempty"` } type NamespaceChangesSelector struct { @@ -163,6 +166,14 @@ type CapabilitiesSelector struct { Values []string `json:"values"` } +type LoginUidSelector struct { + // +kubebuilder:validation:Enum=Equal;NotEqual;GreaterThan;LessThan + // LoginUid selector operator. + Operator string `json:"operator"` + // LoginUid to match. + Values []uint32 `json:"values"` +} + type PIDSelector struct { // +kubebuilder:validation:Enum=In;NotIn // PID selector operator. diff --git a/pkg/k8s/apis/cilium.io/v1alpha1/version.go b/pkg/k8s/apis/cilium.io/v1alpha1/version.go index d5703baa3bf..d4655606d64 100644 --- a/pkg/k8s/apis/cilium.io/v1alpha1/version.go +++ b/pkg/k8s/apis/cilium.io/v1alpha1/version.go @@ -7,4 +7,4 @@ package v1alpha1 // Used to determine if CRD needs to be updated in cluster // // Developers: Bump patch for each change in the CRD schema. -const CustomResourceDefinitionSchemaVersion = "1.1.8" +const CustomResourceDefinitionSchemaVersion = "1.1.9" diff --git a/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go b/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go index 78e6da551f3..44fbbe0c922 100644 --- a/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go @@ -198,6 +198,13 @@ func (in *KProbeSelector) DeepCopyInto(out *KProbeSelector) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.MatchLoginUids != nil { + in, out := &in.MatchLoginUids, &out.MatchLoginUids + *out = make([]LoginUidSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -270,6 +277,27 @@ func (in *ListSpec) DeepCopy() *ListSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoginUidSelector) DeepCopyInto(out *LoginUidSelector) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]uint32, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginUidSelector. +func (in *LoginUidSelector) DeepCopy() *LoginUidSelector { + if in == nil { + return nil + } + out := new(LoginUidSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NamespaceChangesSelector) DeepCopyInto(out *NamespaceChangesSelector) { *out = *in diff --git a/pkg/selectors/kernel.go b/pkg/selectors/kernel.go index 9d23d0b4115..8ea5fbac6ad 100644 --- a/pkg/selectors/kernel.go +++ b/pkg/selectors/kernel.go @@ -341,6 +341,41 @@ func ParseMatchPids(k *KernelSelectorState, matchPids []v1alpha1.PIDSelector) er return nil } +func loginuidSelectorValue(loginuid *v1alpha1.LoginUidSelector) ([]byte, uint32) { + b := make([]byte, len(loginuid.Values)*4) + + for i, v := range loginuid.Values { + off := i * 4 + binary.LittleEndian.PutUint32(b[off:], v) + } + return b, uint32(len(b)) +} + +func ParseMatchLoginuid(k *KernelSelectorState, loginuid *v1alpha1.LoginUidSelector) error { + op, err := SelectorOp(loginuid.Operator) + if err != nil { + return fmt.Errorf("matchloginuid error: %w", err) + } + WriteSelectorUint32(&k.data, op) + + value, size := loginuidSelectorValue(loginuid) + WriteSelectorUint32(&k.data, size/4) + WriteSelectorByteArray(&k.data, value, size) + return nil +} + +func ParseMatchLoginuids(k *KernelSelectorState, matchLoginuids []v1alpha1.LoginUidSelector) error { + loff := AdvanceSelectorLength(&k.data) + + for _, p := range matchLoginuids { + if err := ParseMatchLoginuid(k, &p); err != nil { + return err + } + } + WriteSelectorLength(&k.data, loff) + return nil +} + func ActionTypeFromString(action string) int32 { act, ok := actionTypeTable[strings.ToLower(action)] if !ok { @@ -1231,6 +1266,7 @@ func ParseMatchBinaries(k *KernelSelectorState, binarys []v1alpha1.BinarySelecto // [matchCapabilities] // [matchNamespaceChanges] // [matchCapabilityChanges] +// [matchLoginuids] // [matchArgs] // [matchActions] // @@ -1239,6 +1275,7 @@ func ParseMatchBinaries(k *KernelSelectorState, binarys []v1alpha1.BinarySelecto // matchCapabilities := [length][CAx][CAy]...[CAn] // matchNamespaceChanges := [length][NCx][NCy]...[NCn] // matchCapabilityChanges := [length][CAx][CAy]...[CAn] +// matchLoginuids := [length] [LoginUid1][LoginUid2]...[LoginUidn] // matchArgs := [length][ARGx][ARGy]...[ARGn] // PIDn := [op][flags][nValues][v1]...[vn] // Argn := [index][op][valueGen] @@ -1304,6 +1341,9 @@ func InitKernelSelectorState(selectors []v1alpha1.KProbeSelector, args []v1alpha if err := ParseMatchCapabilityChanges(k, selectors.MatchCapabilityChanges); err != nil { return fmt.Errorf("parseMatchCapabilityChanges error: %w", err) } + if err := ParseMatchLoginuids(k, selectors.MatchLoginUids); err != nil { + return fmt.Errorf("parseMatchLoginuids error: %w", err) + } if err := ParseMatchBinaries(k, selectors.MatchBinaries, selIdx); err != nil { return fmt.Errorf("parseMatchBinaries error: %w", err) } diff --git a/pkg/selectors/kernel_test.go b/pkg/selectors/kernel_test.go index 73edf9182a4..06426bd56f0 100644 --- a/pkg/selectors/kernel_test.go +++ b/pkg/selectors/kernel_test.go @@ -380,6 +380,46 @@ func TestParseMatchPid(t *testing.T) { } } +func TestParseMatchLoginuids(t *testing.T) { + loginuids1 := &v1alpha1.LoginUidSelector{Operator: "Equal", Values: []uint32{1, 2, 3}} + k := &KernelSelectorState{data: KernelSelectorData{off: 0}} + d := &k.data + expected1 := []byte{ + 0x03, 0x00, 0x00, 0x00, // op == Equal + 0x03, 0x00, 0x00, 0x00, // length == 0x3 + 0x01, 0x00, 0x00, 0x00, // Values[0] == 1 + 0x02, 0x00, 0x00, 0x00, // Values[1] == 2 + 0x03, 0x00, 0x00, 0x00, // Values[2] == 3 + } + if err := ParseMatchLoginuid(k, loginuids1); err != nil || bytes.Equal(expected1, d.e[0:d.off]) == false { + t.Errorf("ParseMatchLoginuids: error %v expected %v bytes %v parsing %v\n", err, expected1, d.e[0:d.off], loginuids1) + } + + nextloginuids := d.off + loginuids2 := &v1alpha1.LoginUidSelector{Operator: "NotEqual", Values: []uint32{1, 2, 3, 4}} + expected2 := []byte{ + 0x04, 0x00, 0x00, 0x00, // op == NotEqual + 0x04, 0x00, 0x00, 0x00, // length == 0x4 + 0x01, 0x00, 0x00, 0x00, // Values[0] == 1 + 0x02, 0x00, 0x00, 0x00, // Values[1] == 2 + 0x03, 0x00, 0x00, 0x00, // Values[2] == 3 + 0x04, 0x00, 0x00, 0x00, // Values[2] == 3 + } + if err := ParseMatchLoginuid(k, loginuids2); err != nil || bytes.Equal(expected2, d.e[nextloginuids:d.off]) == false { + t.Errorf("ParseMatchLoginuids: error %v expected %v bytes %v parsing %v\n", err, expected2, d.e[nextloginuids:d.off], loginuids2) + } + + length := []byte{48, 0x00, 0x00, 0x00} + expected3 := append(length, expected1[:]...) + expected3 = append(expected3, expected2[:]...) + loginuids3 := []v1alpha1.LoginUidSelector{*loginuids1, *loginuids2} + ks := &KernelSelectorState{data: KernelSelectorData{off: 0}} + d = &ks.data + if err := ParseMatchLoginuids(ks, loginuids3); err != nil || bytes.Equal(expected3, d.e[0:d.off]) == false { + t.Errorf("ParseMatchLoginuids: error %v expected %v bytes %v parsing %v\n", err, expected3, d.e[0:d.off], loginuids3) + } +} + func TestParseMatchNamespaces(t *testing.T) { ns1 := &v1alpha1.NamespaceSelector{Namespace: "Pid", Operator: "In", Values: []string{"1", "2", "3"}} k := &KernelSelectorState{data: KernelSelectorData{off: 0}} @@ -559,8 +599,8 @@ func TestMultipleSelectorsExample(t *testing.T) { // value absolute offset explanation expU32Push(2) // off: 0 number of selectors expU32Push(8) // off: 4 relative ofset of 1st selector (4 + 8 = 12) - expU32Push(100) // off: 8 relative ofset of 2nd selector (8 + 124 = 132) - expU32Push(96) // off: 12 selector1: length (76 + 12 = 96) + expU32Push(104) // off: 8 relative ofset of 2nd selector (8 + 124 = 132) + expU32Push(100) // off: 12 selector1: length (76 + 12 = 96) expU32Push(24) // off: 16 selector1: MatchPIDs: len expU32Push(SelectorOpNotIn) // off: 20 selector1: MatchPIDs[0]: op expU32Push(0) // off: 24 selector1: MatchPIDs[0]: flags @@ -571,6 +611,7 @@ func TestMultipleSelectorsExample(t *testing.T) { expU32Push(4) // off: 44 selector1: MatchCapabilities: len expU32Push(4) // off: 48 selector1: MatchNamespaceChanges: len expU32Push(4) // off: 52 selector1: MatchCapabilityChanges: len + expU32Push(4) // off: 56 selector1: MatchLoginuids: len expU32Push(48) // off: 80 selector1: matchArgs: len expU32Push(24) // off: 84 selector1: matchArgs[0]: offset expU32Push(0) // off: 88 selector1: matchArgs[1]: offset @@ -584,7 +625,7 @@ func TestMultipleSelectorsExample(t *testing.T) { expU32Push(10) // off: 120 selector1: matchArgs: arg0: val0: 10 expU32Push(20) // off: 124 selector1: matchArgs: arg0: val1: 20 expU32Push(4) // off: 128 selector1: matchActions: length - expU32Push(96) // off: 132 selector2: length + expU32Push(100) // off: 132 selector2: length // ... everything else should be the same as selector1 ... if bytes.Equal(expected[:expectedLen], b[:expectedLen]) == false { @@ -601,11 +642,11 @@ func TestInitKernelSelectors(t *testing.T) { } expected_selsize_small := []byte{ - 0x10, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + capabilities + 4 + 0x40, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + capabilities + loginuid + 4 } expected_selsize_large := []byte{ - 0x44, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + namespacesChanges + capabilities + capabilityChanges + 4 + 0x74, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + namespacesChanges + capabilities + capabilityChanges + loginuid + 4 } expected_filters := []byte{ @@ -688,6 +729,26 @@ func TestInitKernelSelectors(t *testing.T) { 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, // Values (uint64) } + expected_loginuid := []byte{ + // loginuid header + 48, 0x00, 0x00, 0x00, // size = sizeof(loginuids1) + sizeof(loginuids2) + 4 + 4 + + //loginuids1 size = 20 + 0x03, 0x00, 0x00, 0x00, // op == Equal + 0x03, 0x00, 0x00, 0x00, // length == 0x3 + 0x01, 0x00, 0x00, 0x00, // Values[0] == 1 + 0x02, 0x00, 0x00, 0x00, // Values[1] == 2 + 0x03, 0x00, 0x00, 0x00, // Values[2] == 3 + + //loginuids2 size = 24 + 0x04, 0x00, 0x00, 0x00, // op == NotEqual + 0x04, 0x00, 0x00, 0x00, // length == 0x4 + 0x01, 0x00, 0x00, 0x00, // Values[0] == 1 + 0x02, 0x00, 0x00, 0x00, // Values[1] == 2 + 0x03, 0x00, 0x00, 0x00, // Values[2] == 3 + 0x04, 0x00, 0x00, 0x00, // Values[2] == 3 + } + expected_last_large := []byte{ // arg header 108, 0x00, 0x00, 0x00, // size = sizeof(arg2) + sizeof(arg1) + 24 @@ -775,11 +836,13 @@ func TestInitKernelSelectors(t *testing.T) { expected = append(expected, expected_selsize_large...) expected = append(expected, expected_filters...) expected = append(expected, expected_changes...) + expected = append(expected, expected_loginuid...) expected = append(expected, expected_last_large...) } else { expected = append(expected, expected_selsize_small...) expected = append(expected, expected_filters...) expected = append(expected, expected_changes_empty...) + expected = append(expected, expected_loginuid...) expected = append(expected, expected_last_small...) } @@ -802,6 +865,9 @@ func TestInitKernelSelectors(t *testing.T) { cc := &v1alpha1.CapabilitiesSelector{Type: "Effective", Operator: "In", IsNamespaceCapability: false, Values: []string{"CAP_SYS_ADMIN", "CAP_NET_RAW"}} matchCapabilityChanges = append(matchCapabilityChanges, *cc) } + loginuids1 := &v1alpha1.LoginUidSelector{Operator: "Equal", Values: []uint32{1, 2, 3}} + loginuids2 := &v1alpha1.LoginUidSelector{Operator: "NotEqual", Values: []uint32{1, 2, 3, 4}} + matchLoginuids := []v1alpha1.LoginUidSelector{*loginuids1, *loginuids2} var matchArgs []v1alpha1.ArgSelector if kernels.EnableLargeProgs() { arg1 := &v1alpha1.ArgSelector{Index: 1, Operator: "Equal", Values: []string{"foobar"}} @@ -824,6 +890,7 @@ func TestInitKernelSelectors(t *testing.T) { MatchCapabilities: matchCapabilities, MatchNamespaceChanges: matchNamespaceChanges, MatchCapabilityChanges: matchCapabilityChanges, + MatchLoginUids: matchLoginuids, MatchArgs: matchArgs, MatchActions: matchActions, }, diff --git a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml index dc23dfaa56a..aff6150a2bb 100644 --- a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml +++ b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpolicies.yaml @@ -467,6 +467,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1123,6 +1146,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1680,6 +1726,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: diff --git a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml index 8ff37a67567..973379bcd25 100644 --- a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml +++ b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/client/crds/v1alpha1/cilium.io_tracingpoliciesnamespaced.yaml @@ -467,6 +467,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1123,6 +1146,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: @@ -1680,6 +1726,29 @@ spec: - values type: object type: array + matchLoginUids: + description: A list of login uid filters. + items: + properties: + operator: + description: LoginUid selector operator. + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + type: string + values: + description: LoginUid to match. + items: + format: int32 + type: integer + type: array + required: + - operator + - values + type: object + type: array matchNamespaceChanges: description: IDs for namespace changes items: diff --git a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/types.go b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/types.go index 7a6cc982d23..685527a7d49 100644 --- a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/types.go +++ b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/types.go @@ -125,6 +125,9 @@ type KProbeSelector struct { // +kubebuilder:validation:Optional // IDs for capabilities changes MatchCapabilityChanges []CapabilitiesSelector `json:"matchCapabilityChanges,omitempty"` + // +kubebuilder:validation:Optional + // A list of login uid filters. + MatchLoginUids []LoginUidSelector `json:"matchLoginUids,omitempty"` } type NamespaceChangesSelector struct { @@ -163,6 +166,14 @@ type CapabilitiesSelector struct { Values []string `json:"values"` } +type LoginUidSelector struct { + // +kubebuilder:validation:Enum=Equal;NotEqual;GreaterThan;LessThan + // LoginUid selector operator. + Operator string `json:"operator"` + // LoginUid to match. + Values []uint32 `json:"values"` +} + type PIDSelector struct { // +kubebuilder:validation:Enum=In;NotIn // PID selector operator. diff --git a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/version.go b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/version.go index d5703baa3bf..d4655606d64 100644 --- a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/version.go +++ b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/version.go @@ -7,4 +7,4 @@ package v1alpha1 // Used to determine if CRD needs to be updated in cluster // // Developers: Bump patch for each change in the CRD schema. -const CustomResourceDefinitionSchemaVersion = "1.1.8" +const CustomResourceDefinitionSchemaVersion = "1.1.9" diff --git a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go index 78e6da551f3..44fbbe0c922 100644 --- a/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1/zz_generated.deepcopy.go @@ -198,6 +198,13 @@ func (in *KProbeSelector) DeepCopyInto(out *KProbeSelector) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.MatchLoginUids != nil { + in, out := &in.MatchLoginUids, &out.MatchLoginUids + *out = make([]LoginUidSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -270,6 +277,27 @@ func (in *ListSpec) DeepCopy() *ListSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LoginUidSelector) DeepCopyInto(out *LoginUidSelector) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]uint32, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginUidSelector. +func (in *LoginUidSelector) DeepCopy() *LoginUidSelector { + if in == nil { + return nil + } + out := new(LoginUidSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NamespaceChangesSelector) DeepCopyInto(out *NamespaceChangesSelector) { *out = *in