diff --git a/bpf/process/pfilter.h b/bpf/process/pfilter.h index 4bd630d05a3..ed35fe9871c 100644 --- a/bpf/process/pfilter.h +++ b/bpf/process/pfilter.h @@ -342,15 +342,19 @@ selector_match(__u32 *f, struct selector_filter *sel, four: res4 = process_filter(sel, f, enter, &msg->ns, &msg->caps); index = next_pid_value(index, f, ty); + sel->index = index; three: res3 = process_filter(sel, f, enter, &msg->ns, &msg->caps); index = next_pid_value(index, f, ty); + sel->index = index; two: res2 = process_filter(sel, f, enter, &msg->ns, &msg->caps); index = next_pid_value(index, f, ty); + sel->index = index; one: res1 = process_filter(sel, f, enter, &msg->ns, &msg->caps); index = next_pid_value(index, f, ty); + sel->index = index; if (ty == op_filter_notin) return res1 & res2 & res3 & res4; diff --git a/bpf/tests/Makefile b/bpf/tests/Makefile index 53447ee06ca..7c9db843f69 100644 --- a/bpf/tests/Makefile +++ b/bpf/tests/Makefile @@ -1,6 +1,6 @@ include ../Makefile.defs -TESTS = prepend_name_test.o +TESTS = prepend_name_test.o pid_match_test.o OBJSDIR := objs/ OBJS := $(addprefix $(OBJSDIR),$(TESTS)) diff --git a/bpf/tests/pid_match_test.c b/bpf/tests/pid_match_test.c new file mode 100644 index 00000000000..a9c1cf231c7 --- /dev/null +++ b/bpf/tests/pid_match_test.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright Authors of Cilium */ + +//go:build ignore + +#include "vmlinux.h" +#include "compiler.h" +#include "bpf_core_read.h" +#include "bpf_helpers.h" +#include "process/retprobe_map.h" + +#include "process/types/basic.h" +#include "process/generic_calls.h" +#include "process/pfilter.h" + +char _license[] __attribute__((section("license"), used)) = "Dual BSD/GPL"; + +struct filter_map_value { + unsigned char buf[FILTER_SIZE]; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct filter_map_value); +} test_filter_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, int); +} test_result_map SEC(".maps"); + +__attribute__((section("raw_tracepoint/test"), used)) int +test_pid_match() +{ + int zero = 0; + __u32 *f = map_lookup_elem(&test_filter_map, &zero); + if (!f) { + return 0; + } + struct pid_filter *pid; + int index = 0; + struct execve_map_value *enter; + pid = (struct pid_filter *)((u64)f + index); + index += sizeof(struct pid_filter); + struct selector_filter sel = { + .index = index, + .ty = pid->op, + .flags = pid->flags, + .len = pid->len, + }; + + enter = map_lookup_elem(&execve_map, &zero); + if (!enter) { + return 0; + } + int res = selector_match(f, &sel, enter, NULL, &process_filter_pid); + map_update_elem(&test_result_map, &zero, &res, BPF_ANY); + return 0; +} diff --git a/bpf/tests/pid_match_test.go b/bpf/tests/pid_match_test.go new file mode 100644 index 00000000000..3cfeedefd18 --- /dev/null +++ b/bpf/tests/pid_match_test.go @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Tetragon + +package bpf + +import ( + "errors" + "testing" + + "github.com/cilium/ebpf" + "github.com/cilium/tetragon/pkg/api/processapi" + "github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1" + "github.com/cilium/tetragon/pkg/selectors" + "github.com/cilium/tetragon/pkg/sensors/exec/execvemap" + "github.com/stretchr/testify/assert" +) + +const ( + programNamePidMatch = "test_pid_match" +) + +func Test_PidMatch(t *testing.T) { + coll, err := ebpf.LoadCollection("objs/pid_match_test.o") + if err != nil { + var ve *ebpf.VerifierError + if errors.As(err, &ve) { + t.Fatalf("verifier error: %+v\n", ve) + } + t.Fatal(err) + } + defer coll.Close() + + prog, ok := coll.Programs[programNamePidMatch] + assert.True(t, ok, "program %s not found", programNamePidMatch) + + execvMap, ok := coll.Maps["execve_map"] + assert.True(t, ok, "execve_map not found") + + resultMap, ok := coll.Maps["test_result_map"] + assert.True(t, ok, "test_result_map not found") + + runProg := func(selfPid uint32) { + err := execvMap.Update(uint32(0), &execvemap.ExecveValue{ + Process: processapi.MsgExecveKey{Pid: selfPid}, + }, 0) + assert.NoError(t, err) + prog.Run(&ebpf.RunOptions{}) + } + getResult := func() int32 { + var res int32 + err = resultMap.Lookup(uint32(0), &res) + assert.NoError(t, err) + return res + } + + initKernelStatedata := func(pids []uint32) { + k := &selectors.KernelSelectorState{} + err := selectors.ParseMatchPid(k, + &v1alpha1.PIDSelector{ + Operator: "In", + Values: pids, + IsNamespacePID: false, + FollowForks: false}) + assert.NoError(t, err) + filterMap, ok := coll.Maps["test_filter_map"] + assert.True(t, ok, "test_filter_map not found") + err = filterMap.Update(uint32(0), k.Buffer(), 0) + assert.NoError(t, err) + } + + resetResult := func() { + err := resultMap.Update(uint32(0), int32(-1), 0) + assert.NoError(t, err) + } + + t.Run("Match_1_PID", func(t *testing.T) { + resetResult() + initKernelStatedata([]uint32{1}) + runProg(1) + result := getResult() + assert.Equal(t, int32(1), result) + }) + t.Run("Match_2_PID", func(t *testing.T) { + resetResult() + initKernelStatedata([]uint32{1, 2}) + runProg(2) + result := getResult() + assert.Equal(t, int32(1), result) + }) + t.Run("Match_2_PID_NOT_IN_LIST", func(t *testing.T) { + resetResult() + initKernelStatedata([]uint32{1, 2}) + runProg(3) + result := getResult() + assert.Equal(t, int32(0), result) + }) + + t.Run("Match_4_PID", func(t *testing.T) { + resetResult() + initKernelStatedata([]uint32{1, 2, 3, 4}) + runProg(4) + result := getResult() + assert.Equal(t, int32(1), result) + }) + t.Run("Match_4_PID_NOT_IN_LIST", func(t *testing.T) { + initKernelStatedata([]uint32{1, 2, 3, 4}) + resetResult() + runProg(5) + result := getResult() + assert.Equal(t, int32(0), result) + }) +}