diff --git a/contrib/tester-progs/Makefile b/contrib/tester-progs/Makefile index 05bb223bea3..1b7c7ab4fff 100644 --- a/contrib/tester-progs/Makefile +++ b/contrib/tester-progs/Makefile @@ -15,7 +15,8 @@ PROGS = sigkill-tester \ uprobe-test-1 \ uprobe-test-2 \ lseek-pipe \ - threads-tester + threads-tester \ + killer-tester all: $(PROGS) diff --git a/contrib/tester-progs/killer-tester.c b/contrib/tester-progs/killer-tester.c new file mode 100644 index 00000000000..cb95fc68366 --- /dev/null +++ b/contrib/tester-progs/killer-tester.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main(void) +{ + prctl(0xffff, 0, 0, 0, 0); + return errno; +} diff --git a/pkg/sensors/tracing/killer_test.go b/pkg/sensors/tracing/killer_test.go new file mode 100644 index 00000000000..2546037ef66 --- /dev/null +++ b/pkg/sensors/tracing/killer_test.go @@ -0,0 +1,174 @@ +package tracing + +import ( + "context" + "os" + "os/exec" + "sync" + "syscall" + "testing" + + ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker" + "github.com/cilium/tetragon/pkg/jsonchecker" + lc "github.com/cilium/tetragon/pkg/matchers/listmatcher" + "github.com/cilium/tetragon/pkg/observer/observertesthelper" + "github.com/cilium/tetragon/pkg/testutils" + tus "github.com/cilium/tetragon/pkg/testutils/sensors" + "github.com/stretchr/testify/assert" +) + +func TestKillerOverride(t *testing.T) { + test := testutils.RepoRootPath("contrib/tester-progs/killer-tester") + configHook := ` +apiVersion: cilium.io/v1alpha1 +kind: TracingPolicy +metadata: + name: "kill-syscalls" +spec: + lists: + - name: "mine" + type: "syscalls" + values: + - "sys_prctl" + killers: + - syscalls: + - "list:mine" + tracepoints: + - subsystem: "raw_syscalls" + event: "sys_enter" + args: + - index: 4 + type: "uint64" + selectors: + - matchArgs: + - index: 0 + operator: "InMap" + values: + - "list:mine" + matchBinaries: + - operator: "In" + values: + - "` + test + `" + matchActions: + - action: "NotifyKiller" + argError: -17 # EEXIST +` + + tpChecker := ec.NewProcessTracepointChecker(""). + WithArgs(ec.NewKprobeArgumentListMatcher(). + WithOperator(lc.Ordered). + WithValues( + ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL), + )) + + checker := ec.NewUnorderedEventChecker(tpChecker) + + var doneWG, readyWG sync.WaitGroup + defer doneWG.Wait() + + ctx, cancel := context.WithTimeout(context.Background(), tus.Conf().CmdWaitTime) + defer cancel() + + err := os.WriteFile(testConfigFile, []byte(configHook), 0644) + if err != nil { + t.Fatalf("writeFile(%s): err %s", testConfigFile, err) + } + + obs, err := observertesthelper.GetDefaultObserverWithFile(t, ctx, testConfigFile, tus.Conf().TetragonLib, observertesthelper.WithMyPid()) + if err != nil { + t.Fatalf("GetDefaultObserverWithFile error: %s", err) + } + observertesthelper.LoopEvents(ctx, t, &doneWG, &readyWG, obs) + readyWG.Wait() + + cmd := exec.Command(test) + err = cmd.Run() + + if cmd.ProcessState.ExitCode() != int(syscall.EEXIST) { + t.Fatalf("Wrong exit code %d expected %d", cmd.ProcessState.ExitCode(), int(syscall.EEXIST)) + } + + err = jsonchecker.JsonTestCheck(t, checker) + assert.NoError(t, err) + + cmd.Process.Kill() + cmd.Process.Wait() +} + +func TestKillerSignal(t *testing.T) { + test := testutils.RepoRootPath("contrib/tester-progs/killer-tester") + configHook := ` +apiVersion: cilium.io/v1alpha1 +kind: TracingPolicy +metadata: + name: "kill-syscalls" +spec: + lists: + - name: "mine" + type: "syscalls" + values: + - "sys_prctl" + killers: + - syscalls: + - "list:mine" + tracepoints: + - subsystem: "raw_syscalls" + event: "sys_enter" + args: + - index: 4 + type: "uint64" + selectors: + - matchArgs: + - index: 0 + operator: "InMap" + values: + - "list:mine" + matchBinaries: + - operator: "In" + values: + - "` + test + `" + matchActions: + - action: "NotifyKiller" + argSig: 9 # SIGKILL +` + + tpChecker := ec.NewProcessTracepointChecker(""). + WithArgs(ec.NewKprobeArgumentListMatcher(). + WithOperator(lc.Ordered). + WithValues( + ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL), + )) + + checker := ec.NewUnorderedEventChecker(tpChecker) + + var doneWG, readyWG sync.WaitGroup + defer doneWG.Wait() + + ctx, cancel := context.WithTimeout(context.Background(), tus.Conf().CmdWaitTime) + defer cancel() + + err := os.WriteFile(testConfigFile, []byte(configHook), 0644) + if err != nil { + t.Fatalf("writeFile(%s): err %s", testConfigFile, err) + } + + obs, err := observertesthelper.GetDefaultObserverWithFile(t, ctx, testConfigFile, tus.Conf().TetragonLib, observertesthelper.WithMyPid()) + if err != nil { + t.Fatalf("GetDefaultObserverWithFile error: %s", err) + } + observertesthelper.LoopEvents(ctx, t, &doneWG, &readyWG, obs) + readyWG.Wait() + + cmd := exec.Command(test) + err = cmd.Run() + + if err.Error() != "signal: killed" { + t.Fatalf("Wrong error '%v' expected 'killed'", err) + } + + err = jsonchecker.JsonTestCheck(t, checker) + assert.NoError(t, err) + + cmd.Process.Kill() + cmd.Process.Wait() +}