From 88ac808171c52231ced7bdb82f495ddd4d078f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Tue, 7 Feb 2023 18:55:48 -0300 Subject: [PATCH] chore: mscope: make scopes tests more robust - add checkEvents generic function to check if all events are received - add common.go with execCommand function that ensures execution of a command in the same cpu - add waitForTraceeOutputEvents function to wait for tracee output events until buffer fills with certain number of events or timeout occurs - remove do_ls_uname tester.sh function as a start to concentrate all scopes tests in scopes_test.go - create syscaller tool to easily generate syscalls from the command line --- .gitignore | 3 +- Makefile | 15 +- tests/integration/common.go | 49 +++ tests/integration/integration_test.go | 79 ---- tests/integration/scopes_test.go | 358 ++++++++++++++++++ tests/integration/syscaller/syscaller.go | 83 ++++ tests/integration/syscaller/syscaller_test.go | 45 +++ tests/integration/tester.sh | 5 - tests/integration/tracee.go | 17 + 9 files changed, 568 insertions(+), 86 deletions(-) create mode 100644 tests/integration/common.go create mode 100644 tests/integration/scopes_test.go create mode 100644 tests/integration/syscaller/syscaller.go create mode 100644 tests/integration/syscaller/syscaller_test.go diff --git a/.gitignore b/.gitignore index eccd8913857e..f41897472601 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ compile_commands.json .vagrant # binaries and build files -dist \ No newline at end of file +dist +syscaller \ No newline at end of file diff --git a/Makefile b/Makefile index 584b928e42c2..9a6b5af67400 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ CMD_CAT ?= cat CMD_MD5 ?= md5sum CMD_OPA ?= opa CMD_STATICCHECK ?= staticcheck +CMD_SYSCALLER ?= ./tests/integration/syscaller/syscaller .check_%: # @@ -705,9 +706,20 @@ test-types: \ -coverprofile=coverage.txt \ ./... +# +# syscaller (required for integration tests) +# + +.PHONY: $(CMD_SYSCALLER) +$(CMD_SYSCALLER): \ + | .check_$(CMD_GO) +# + $(CMD_GO) build -o $(CMD_SYSCALLER) $(dir $(CMD_SYSCALLER)) + .PHONY: test-integration test-integration: \ .checkver_$(CMD_GO) \ + $(CMD_SYSCALLER) \ tracee-ebpf # $(GO_ENV_EBPF) \ @@ -813,4 +825,5 @@ clean: $(CMD_RM) -rf $(OUTPUT_DIR) $(CMD_RM) -f .*.md5 $(CMD_RM) -f .check* - $(CMD_RM) -f .*-pkgs* \ No newline at end of file + $(CMD_RM) -f .*-pkgs* + $(CMD_RM) -f $(CMD_SYSCALLER) \ No newline at end of file diff --git a/tests/integration/common.go b/tests/integration/common.go new file mode 100644 index 000000000000..5bf015e01484 --- /dev/null +++ b/tests/integration/common.go @@ -0,0 +1,49 @@ +package integration + +import ( + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + + "golang.org/x/sys/unix" +) + +const cpuID = 0 // CPU to pin the process to + +// execCommand executes a command pinning it to a specific CPU and returns the process and its stdout +func execCommand(fullCmd string) (*os.Process, []byte, error) { + vals := strings.Split(fullCmd, " ") + + cmd := vals[0] // as separator is a space, split will always return at least one element + cmd, err := exec.LookPath(cmd) + if err != nil { + return nil, nil, err + } + if !filepath.IsAbs(cmd) { + cmd, err = filepath.Abs(cmd) + if err != nil { + return nil, nil, err + } + } + + args := []string{} + if len(vals) > 1 { + args = vals[1:] + } + + // set the affinity of the thread to a specific CPU, + // making sure that the events will be generated in order + cpuMask := unix.CPUSet{} + cpuMask.Set(cpuID) + unix.SchedSetaffinity(0, &cpuMask) + runtime.LockOSThread() // also wire the calling goroutine to the same CPU + + c := exec.Command(cmd, args...) + stdout, err := c.Output() + + runtime.UnlockOSThread() + + return c.Process, stdout, err +} diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 3c37fd059a39..f94323c7c6ce 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -15,7 +15,6 @@ import ( "github.com/aquasecurity/tracee/pkg/cmd/flags" tracee "github.com/aquasecurity/tracee/pkg/ebpf" "github.com/aquasecurity/tracee/pkg/events" - "github.com/aquasecurity/tracee/signatures/helpers" "github.com/aquasecurity/tracee/types/trace" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -199,48 +198,6 @@ func checkSecurityFileOpenExecve(t *testing.T, gotOutput *[]trace.Event) { } } -func checkScope42SecurityFileOpenLs(t *testing.T, gotOutput *[]trace.Event) { - _, err := forkAndExecFunction(doLs) - require.NoError(t, err) - - waitForTraceeOutput(t, gotOutput, time.Now(), true) - - for _, evt := range *gotOutput { - // ls - scope 42 - assert.Equal(t, "ls", evt.ProcessName) - assert.Equal(t, uint64(1<<41), evt.MatchedScopes) - arg, err := helpers.GetTraceeArgumentByName(evt, "pathname", helpers.GetArgOps{DefaultArgs: false}) - require.NoError(t, err) - assert.Contains(t, arg.Value, "integration") - } -} - -// checkExecveOnScopes4And2 demands an ordered events submission -func checkExecveOnScopes4And2(t *testing.T, gotOutput *[]trace.Event) { - _, err := forkAndExecFunction(doLsUname) - require.NoError(t, err) - - waitForTraceeOutput(t, gotOutput, time.Now(), true) - - // check output length - require.Len(t, *gotOutput, 2) - var evts [2]trace.Event - - // output should only have events with event name of execve - for i, evt := range *gotOutput { - assert.Equal(t, "sched_process_exit", evt.EventName) - evts[i] = evt - } - - // ls - scope 4 - assert.Equal(t, evts[0].ProcessName, "ls") - assert.Equal(t, uint64(1<<3), evts[0].MatchedScopes, "MatchedScopes") - - // uname - scope 2 - assert.Equal(t, evts[1].ProcessName, "uname") - assert.Equal(t, uint64(1<<1), evts[1].MatchedScopes, "MatchedScopes") -} - func checkDockerdBinaryFilter(t *testing.T, gotOutput *[]trace.Event) { dockerdPidBytes, err := forkAndExecFunction(getDockerdPid) require.NoError(t, err) @@ -259,23 +216,6 @@ func checkDockerdBinaryFilter(t *testing.T, gotOutput *[]trace.Event) { assert.Contains(t, processIds, int(dockerdPid)) } -func checkLsAndWhichBinaryFilterWithScopes(t *testing.T, gotOutput *[]trace.Event) { - var err error - _, err = forkAndExecFunction(doLs) - require.NoError(t, err) - _, err = forkAndExecFunction(doWhichLs) - require.NoError(t, err) - - waitForTraceeOutput(t, gotOutput, time.Now(), true) - - for _, evt := range *gotOutput { - procName := evt.ProcessName - if procName != "ls" && procName != "which" { - t.Fail() - } - } -} - func Test_EventFilters(t *testing.T) { testCases := []struct { name string @@ -337,19 +277,6 @@ func Test_EventFilters(t *testing.T) { filterArgs: []string{"container=new", "event!=container_create,container_remove"}, eventFunc: checkNewContainers, }, - { - name: "trace event set in a specific scope", - filterArgs: []string{"42:comm=ls", "42:event=security_file_open", "42:security_file_open.args.pathname=*integration"}, - eventFunc: checkScope42SecurityFileOpenLs, - }, - { - name: "trace events set in two specific scope", - filterArgs: []string{ - "4:event=sched_process_exit", "4:comm=ls", - "2:event=sched_process_exit", "2:comm=uname", - }, - eventFunc: checkExecveOnScopes4And2, - }, { name: "trace only security_file_open from \"execve\" syscall", filterArgs: []string{"event=security_file_open", "security_file_open.context.syscall=execve"}, @@ -360,11 +287,6 @@ func Test_EventFilters(t *testing.T) { filterArgs: []string{"bin=/usr/bin/dockerd"}, eventFunc: checkDockerdBinaryFilter, }, - { - name: "trace events from ls and which binary in separate scopes", - filterArgs: []string{"1:bin=/usr/bin/ls", "2:bin=/usr/bin/which"}, - eventFunc: checkLsAndWhichBinaryFilterWithScopes, - }, } for _, tc := range testCases { @@ -405,7 +327,6 @@ type testFunc string const ( doMagicWrite testFunc = "do_magic_write" doLs testFunc = "do_ls" - doLsUname testFunc = "do_ls_uname" doDockerRun testFunc = "do_docker_run" doFileOpen testFunc = "do_file_open" getDockerdPid testFunc = "get_dockerd_pid" diff --git a/tests/integration/scopes_test.go b/tests/integration/scopes_test.go new file mode 100644 index 000000000000..7b22a767f50d --- /dev/null +++ b/tests/integration/scopes_test.go @@ -0,0 +1,358 @@ +package integration + +import ( + "context" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/aquasecurity/tracee/pkg/cmd/flags" + tracee "github.com/aquasecurity/tracee/pkg/ebpf" + "github.com/aquasecurity/tracee/pkg/events" + "github.com/aquasecurity/tracee/pkg/utils" + "github.com/aquasecurity/tracee/signatures/helpers" + "github.com/aquasecurity/tracee/types/trace" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// expectArg is a helper function to create a trace.Argument with the name and value fields set +// If value has a star as wildcard, the value must be passed as it is due to runCmdAndCheckEvents logic +func expectArg(name, value string) trace.Argument { + return trace.Argument{ + ArgMeta: trace.ArgMeta{ + Name: name, + }, + Value: value, + } +} + +// orScopes is a helper function to create a bit mask of +// the given scopes +func orScopes(scopes ...uint) uint64 { + var res uint64 + for _, scope := range scopes { + utils.SetBit(&res, scope-1) + } + + return res +} + +// cmdEvents is a struct to hold the command to run +// and the expected events +type cmdEvents struct { + runCmd string + evts []trace.Event +} + +// newCmdEvents is a helper function to create a cmdEvents +func newCmdEvents(runCmd string, evts []trace.Event) cmdEvents { + return cmdEvents{ + runCmd: runCmd, + evts: evts, + } +} + +// expectEvent is a helper function to create a trace.Event +func expectEvent(comm string, eventID events.ID, scopes uint64, args ...trace.Argument) trace.Event { + return trace.Event{ + ProcessorID: cpuID, + ProcessName: comm, + EventID: int(eventID), + MatchedScopes: scopes, + Args: args, + } +} + +// Test_Scopes tests a variety of trace event filters +// with different combinations of scopes +func Test_Scopes(t *testing.T) { + // test table + tt := []struct { + name string + filterArgs []string + cmdEvents []cmdEvents + syscaller bool + test func(t *testing.T, syscaller bool, cmdEvents []cmdEvents, actual *[]trace.Event) + }{ + // events matched in single scopes - detached workloads + { + name: "comm: event: trace events from ping command in a single scope", + filterArgs: []string{ + "comm=ping", "event=sched_process_exec,sched_process_exit", // without prefix, scope is 1 + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ping -c1 0.0.0.0", + []trace.Event{ + expectEvent("ping", events.SchedProcessExec, orScopes(1)), + expectEvent("ping", events.SchedProcessExit, orScopes(1)), + }), + }, + syscaller: false, + test: runCmdAndCheckEvents, + }, + + { + name: "comm: event: trace events from program1 command in a single scope", + filterArgs: []string{ + "comm=program1", "event=read,write", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("program1", + []trace.Event{ + expectEvent("program1", events.Read, orScopes(1)), + expectEvent("program1", events.Write, orScopes(1)), + }), + }, + syscaller: true, + test: runCmdAndCheckEvents, + }, + + { + name: "comm: event: trace events from ping command in a single scope", + filterArgs: []string{ + "5:comm=ping", "5:event=net_packet_icmp", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ping -c1 0.0.0.0", + []trace.Event{ + expectEvent("ping", events.NetPacketICMP, orScopes(5)), + expectEvent("ping", events.NetPacketICMP, orScopes(5)), + }), + }, + syscaller: false, + test: runCmdAndCheckEvents, + }, + { + name: "comm: event: args: trace event set in a specific scope with args from ls command", + filterArgs: []string{"42:comm=ls", "42:event=security_file_open", "42:security_file_open.args.pathname=*integration"}, + cmdEvents: []cmdEvents{ + newCmdEvents("ls", + []trace.Event{ + expectEvent("ls", events.SecurityFileOpen, orScopes(42), expectArg("pathname", "*integration")), + }), + }, + test: runCmdAndCheckEvents, + }, + { + name: "comm: event: trace events set in two specific scopes from ls and uname commands", + filterArgs: []string{ + "4:comm=ls", "4:event=sched_process_exit", + "2:comm=uname", "2:event=sched_process_exit", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ls", + []trace.Event{ + expectEvent("ls", events.SchedProcessExit, orScopes(4)), + }), + newCmdEvents("uname", + []trace.Event{ + expectEvent("uname", events.SchedProcessExit, orScopes(2)), + }), + }, + test: runCmdAndCheckEvents, + }, + { + name: "bin: trace events from who and uname binary in separate scopes", + filterArgs: []string{ + "1:bin=/usr/bin/who", + "2:bin=/usr/bin/uname", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("who", + []trace.Event{ + expectEvent("who", events.SchedProcessExec, orScopes(1)), + }), + newCmdEvents("uname", + []trace.Event{ + expectEvent("uname", events.SchedProcessExec, orScopes(2)), + }), + }, + test: runCmdAndCheckEvents, + }, + + // TODO: add tests using signature events + // This is currently not possible since signature events are dynamically + // created and an event like anti_debugging is not known in advance. + // { + // name: "comm: event: sign: trace sys events + signature events in separte scopes", + // filterArgs: []string{ + // "3:comm=ping", "3:event=net_packet_icmp", + // "5:event=ptrace", "5:ptrace.args.pid=0", + // "9:event=anti_debugging", + // }, + // cmdEvents: []cmdEvents{ + // newCmdEvents("ping -c1 0.0.0.0", + // []trace.Event{ + // expectEvent("ping", events.NetPacketICMP, orScopes(3)), + // expectEvent("ping", events.NetPacketICMP, orScopes(3)), + // }), + // newCmdEvents("strace ls", + // []trace.Event{ + // expectEvent("strace", events.Ptrace, orScopes(5)), + // expectEvent("strace", events.anti_debugging, orScopes(9)), + // }), + // }, + // test: runCmdAndCheckEvents, + // }, + + // events matched in multiple scopes - intertwined workloads + { + name: "comm: event: trace events from ping command in separate scopes", + filterArgs: []string{ + "3:comm=ping", "3:event=net_packet_icmp", + "5:comm=ping", "5:event=net_packet_icmp", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ping -c1 0.0.0.0", + []trace.Event{ + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5)), + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5)), + }), + }, + test: runCmdAndCheckEvents, + }, + { + name: "comm: event: trace events from ping command in separate scopes", + filterArgs: []string{ + "3:comm=ping", "3:event=net_packet_icmp", + "5:comm=ping", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ping -c1 0.0.0.0", + []trace.Event{ + expectEvent("ping", events.SchedProcessExec, orScopes(5)), + expectEvent("ping", events.Setuid, orScopes(5)), + expectEvent("ping", events.SecuritySocketConnect, orScopes(5)), + + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5)), + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5)), + }), + }, + test: runCmdAndCheckEvents, + }, + { + name: "comm: event: trace events from ping command in separate scopes", + filterArgs: []string{ + "3:comm=ping", "3:event=net_packet_icmp", + "5:comm=ping", "5:event=net_packet_icmp", + "7:comm=ping", "7:event=sched_process_exec", + "9:comm=ping", + }, + cmdEvents: []cmdEvents{ + newCmdEvents("ping -c1 0.0.0.0", + []trace.Event{ + expectEvent("ping", events.SchedProcessExec, orScopes(7, 9)), + + expectEvent("ping", events.Setuid, orScopes(9)), + expectEvent("ping", events.SecuritySocketConnect, orScopes(9)), + + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5, 9)), + expectEvent("ping", events.NetPacketICMP, orScopes(3, 5, 9)), + }), + }, + test: runCmdAndCheckEvents, + }, + } + + // run tests cases + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + filterScopes, err := flags.PrepareFilterScopes(tc.filterArgs) + require.NoError(t, err) + + eventChan := make(chan trace.Event, 1000) + config := tracee.Config{ + ChanEvents: eventChan, + Capabilities: &tracee.CapabilitiesConfig{ + BypassCaps: true, + }, + } + config.FilterScopes = filterScopes + eventOutput := []trace.Event{} + + go func() { + for evt := range eventChan { + eventOutput = append(eventOutput, evt) + } + }() + + trc := startTracee(t, config, nil, nil, ctx) + + waitforTraceeStart(t, trc, time.Now()) + + tc.test(t, tc.syscaller, tc.cmdEvents, &eventOutput) + + cancel() + }) + } +} + +// runCmds executes given commands and checks total number of events +func runCmds(t *testing.T, cmdEvents []cmdEvents, actual *[]trace.Event) []*os.Process { + var ( + procs = make([]*os.Process, 0) + totalEvents int + ) + + for _, cmd := range cmdEvents { + p, _, err := execCommand(cmd.runCmd) + require.NoError(t, err) + procs = append(procs, p) + totalEvents += len(cmd.evts) + } + + waitForTraceeOutputEvents(t, totalEvents, actual, time.Now(), true) + require.Len(t, *actual, totalEvents) + + return procs +} + +// formatCmdEvents formats given commands to be executed by syscaller helper tool +func formatCmdEvents(cmdEvents []cmdEvents) { + // iterate using index to persist changes + for i := range cmdEvents { + cmdEvents[i].runCmd = fmt.Sprintf("./syscaller/syscaller %s", cmdEvents[i].runCmd) + for _, evt := range cmdEvents[i].evts { + cmdEvents[i].runCmd = fmt.Sprintf("%s %d", cmdEvents[i].runCmd, evt.EventID) + } + } +} + +// runCmdAndCheckEvents executes given commands and checks that expected events are generated +func runCmdAndCheckEvents(t *testing.T, syscaller bool, cmdEvents []cmdEvents, actual *[]trace.Event) { + // first stage: run commands + if syscaller { + formatCmdEvents(cmdEvents) + } + procs := runCmds(t, cmdEvents, actual) + + // second stage: check events + for cmdIdx, exp := range cmdEvents { + for evtIdx, expEvt := range exp.evts { + // this must pass since we compare the expected events with the actual events in the same order + actEvt := (*actual)[cmdIdx*len(exp.evts)+evtIdx] + assert.Equal(t, cpuID, actEvt.ProcessorID) + assert.Equal(t, procs[cmdIdx].Pid, actEvt.ProcessID) + + assert.Equal(t, expEvt.MatchedScopes, actEvt.MatchedScopes) + assert.Equal(t, expEvt.ProcessName, actEvt.ProcessName) + assert.Equal(t, expEvt.EventID, actEvt.EventID) + + // check args + for _, expArg := range expEvt.Args { + actArg, err := helpers.GetTraceeArgumentByName(actEvt, expArg.Name, helpers.GetArgOps{DefaultArgs: false}) + require.NoError(t, err) + if strings.Contains(expArg.Value.(string), "*") { + expArg.Value = strings.ReplaceAll(expArg.Value.(string), "*", "") + assert.Contains(t, actArg.Value, expArg.Value) + } else { + assert.Equal(t, expArg.Value, actArg.Value) + } + } + } + } +} diff --git a/tests/integration/syscaller/syscaller.go b/tests/integration/syscaller/syscaller.go new file mode 100644 index 000000000000..d0a4d0888c6f --- /dev/null +++ b/tests/integration/syscaller/syscaller.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "os" + "runtime" + "strconv" + "syscall" + "unsafe" +) + +// sysArgs is a struct containing the arguments to be passed to a syscall. +type sysArgs struct { + arg1 uintptr + arg2 uintptr + arg3 uintptr + arg4 uintptr + arg5 uintptr + arg6 uintptr +} + +// syscallMap is a map of syscall numbers to the arguments they should be +// called with. If the syscall number is not found in the map, the syscall +// is called with arguments set to 0. +var syscallMap = map[int]sysArgs{ + syscall.SYS_READ: {0, 0, 0, 0, 0, 0}, +} + +// changeOwnComm changes the comm of the current process to the given string. +func changeOwnComm(comm string) error { + bytes := append([]byte(comm), 0) + ptr := unsafe.Pointer(&bytes[0]) + + if _, _, errno := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_NAME, uintptr(ptr), 0, 0, 0, 0); errno != 0 { + return syscall.Errno(errno) + } + + return nil +} + +// callsys calls the given syscalls in order. +func callsys(syscalls []int) []error { + errs := make([]error, 0) + for _, sysNum := range syscalls { + var err syscall.Errno + if s, found := syscallMap[sysNum]; found { + _, _, err = syscall.RawSyscall6(uintptr(sysNum), s.arg1, s.arg2, s.arg3, s.arg4, s.arg5, s.arg6) + } else { + _, _, err = syscall.RawSyscall6(uintptr(sysNum), 0, 0, 0, 0, 0, 0) + } + errs = append(errs, syscall.Errno(err)) + } + + return errs +} + +func main() { + runtime.GOMAXPROCS(1) // stick to a sing OS thread, assuring the comm is the one set by us + if len(os.Args) < 3 { + fmt.Println("usage: syscaller caller_comm sycall_number[...]") + os.Exit(0) + } + + callerComm := os.Args[1] + syscallsToCall := make([]int, 0) + for _, arg := range os.Args[2:] { + syscallNum, err := strconv.Atoi(arg) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid syscall number: %s\n", arg) + os.Exit(1) + } + syscallsToCall = append(syscallsToCall, syscallNum) + } + + err := changeOwnComm(callerComm) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + + // do the magic + _ = callsys(syscallsToCall) +} diff --git a/tests/integration/syscaller/syscaller_test.go b/tests/integration/syscaller/syscaller_test.go new file mode 100644 index 000000000000..faf2d370668f --- /dev/null +++ b/tests/integration/syscaller/syscaller_test.go @@ -0,0 +1,45 @@ +package main + +import ( + "io/ioutil" + "runtime" + "syscall" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestCallsys tests the callsys function. +func TestCallsys(t *testing.T) { + // SYS_READ and SYS_CLOSE are syscalls that, considering this environment, + // should not return an error when called with zeroed arguments. + syscalls := []int{syscall.SYS_READ, syscall.SYS_CLOSE} + errs := callsys(syscalls) + for _, err := range errs { + assert.Equal(t, syscall.Errno(0), err) + } + + // SYS_WRITE is a syscall that, considering this environment, + // should return an error when called with zeroed arguments. + syscalls = []int{syscall.SYS_WRITE} + err := callsys(syscalls)[0] + assert.Equal(t, syscall.Errno(9), err) +} + +// TestChangeOwnComm tests the changeOwnComm function. +func TestChangeOwnComm(t *testing.T) { + runtime.GOMAXPROCS(1) // stick to a sing OS thread, assuring the comm is the one set by us + // Test changing the comm to a valid string + err := changeOwnComm("test-comm") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // double check that the comm was changed + comm, err := ioutil.ReadFile("/proc/self/comm") + comm = comm[:len(comm)-1] // remove the trailing newline + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + assert.Equal(t, "test-comm", string(comm)) +} diff --git a/tests/integration/tester.sh b/tests/integration/tester.sh index d4df14357ba0..d7215d3cb93e 100755 --- a/tests/integration/tester.sh +++ b/tests/integration/tester.sh @@ -13,11 +13,6 @@ do_which_ls() { which ls > /dev/nul } -do_ls_uname() { - # run on the same core to ensure event order - taskset -c 0 ls; uname -} > /dev/null - do_docker_run() { outputFileName=$1 output=$(docker run -d --rm alpine) diff --git a/tests/integration/tracee.go b/tests/integration/tracee.go index 86ebcd090bc1..93b634c13a77 100644 --- a/tests/integration/tracee.go +++ b/tests/integration/tracee.go @@ -99,3 +99,20 @@ func waitforTraceeStart(t *testing.T, trc *tracee.Tracee, now time.Time) { } } } + +// wait for tracee buffer to fill up to a specific number of events or timeout to occur, whichever comes first +func waitForTraceeOutputEvents(t *testing.T, totalEvents int, gotOutput *[]trace.Event, now time.Time, failOnTimeout bool) { + const CheckTimeout = 5 * time.Second + for { + if len(*gotOutput) >= totalEvents { + break + } + if time.Since(now) > CheckTimeout { + if failOnTimeout { + t.Logf("timed out on output\n") + t.FailNow() + } + break + } + } +}