Skip to content

Commit ea11896

Browse files
authored
Run integration test triggers in own PID (#2323)
This is a change to the integration tests so that the commands which are meant to trigger events that the tests look for, are actually picked up by tracee. In order for this to happen, the events can't be the same PID as tracee. This is accomplished using syscall.ForkExec() which runs functions in a shell script. Signed-off-by: grantseltzer <[email protected]>
1 parent 380070e commit ea11896

File tree

2 files changed

+81
-55
lines changed

2 files changed

+81
-55
lines changed

tests/integration/integration_test.go

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package integration
22

33
import (
44
"context"
5+
"io/ioutil"
56
"os"
6-
"os/exec"
77
"strings"
8+
"syscall"
89
"testing"
910
"time"
1011

@@ -16,49 +17,23 @@ import (
1617
"github.com/stretchr/testify/require"
1718
)
1819

19-
// // small set of actions to trigger a magic write event
20-
// func checkMagicwrite(t *testing.T, gotOutput *[]trace.Event) {
21-
// // create a temp dir for testing
22-
// d, err := ioutil.TempDir("", "Test_MagicWrite-dir-*")
23-
// require.NoError(t, err)
24-
25-
// // cp a file to trigger
26-
// f, err := os.CreateTemp(d, "Test_MagicWrite-file-*")
27-
// require.NoError(t, err)
28-
// defer func() {
29-
// os.Remove(d)
30-
// }()
31-
32-
// f.WriteString(`foo.bar.baz`)
33-
// f.Close()
34-
35-
// cpCmd := exec.Command("cp", f.Name(), filepath.Join(d+filepath.Base(f.Name())+"-new"))
36-
// fmt.Println("executing: ", cpCmd.String())
37-
// cpCmd.Stdout = os.Stdout
38-
// assert.NoError(t, cpCmd.Run())
39-
40-
// waitForTraceeOutput(t, gotOutput, time.Now(), true)
41-
42-
// // check tracee output
43-
// expect := []byte{102, 111, 111, 46, 98, 97, 114, 46, 98, 97, 122}
44-
// fail := true
45-
// for _, evt := range *gotOutput {
46-
// arg := events.GetArg(&evt, "bytes")
47-
// argVal, ok := arg.Value.([]byte)
48-
// require.Equal(t, true, ok)
49-
// ok = assert.ElementsMatch(t, argVal, expect)
50-
// if ok {
51-
// fail = false
52-
// }
53-
// }
54-
// if fail {
55-
// t.Fail()
56-
// }
57-
// }
20+
// small set of actions to trigger a magic write event
21+
func checkMagicwrite(t *testing.T, gotOutput *[]trace.Event) {
22+
23+
_, err := forkAndExecFunction(doMagicWrite)
24+
require.NoError(t, err)
25+
26+
waitForTraceeOutput(t, gotOutput, time.Now(), true)
27+
28+
// check tracee output
29+
for _, evt := range *gotOutput {
30+
assert.Equal(t, []byte(evt.EventName), []byte("magic_write"))
31+
}
32+
}
5833

5934
// execute a ls command
6035
func checkExeccommand(t *testing.T, gotOutput *[]trace.Event) {
61-
err := exec.Command("/usr/bin/ls").Run()
36+
_, err := forkAndExecFunction(doLs)
6237
require.NoError(t, err)
6338

6439
waitForTraceeOutput(t, gotOutput, time.Now(), true)
@@ -77,8 +52,7 @@ func checkExeccommand(t *testing.T, gotOutput *[]trace.Event) {
7752
func checkPidnew(t *testing.T, gotOutput *[]trace.Event) {
7853
traceePid := os.Getpid()
7954

80-
// run a command
81-
err := exec.Command("/usr/bin/ls").Run()
55+
_, err := forkAndExecFunction(doLs)
8256
require.NoError(t, err)
8357

8458
waitForTraceeOutput(t, gotOutput, time.Now(), true)
@@ -97,7 +71,7 @@ func checkPidnew(t *testing.T, gotOutput *[]trace.Event) {
9771

9872
// only capture uids of 0 that are run by comm ls
9973
func checkUidZero(t *testing.T, gotOutput *[]trace.Event) {
100-
err := exec.Command("/usr/bin/ls").Run()
74+
_, err := forkAndExecFunction(doLs)
10175
require.NoError(t, err)
10276

10377
waitForTraceeOutput(t, gotOutput, time.Now(), true)
@@ -117,7 +91,7 @@ func checkUidZero(t *testing.T, gotOutput *[]trace.Event) {
11791

11892
// trigger ls from uid 0 (tests run as root) and check if empty
11993
func checkUidNonZero(t *testing.T, gotOutput *[]trace.Event) {
120-
err := exec.Command("/usr/bin/ls").Run()
94+
_, err := forkAndExecFunction(doLs)
12195
require.NoError(t, err)
12296

12397
waitForTraceeOutput(t, gotOutput, time.Now(), false)
@@ -128,7 +102,7 @@ func checkUidNonZero(t *testing.T, gotOutput *[]trace.Event) {
128102

129103
// check that execve event is called
130104
func checkExecve(t *testing.T, gotOutput *[]trace.Event) {
131-
err := exec.Command("/usr/bin/ls").Run()
105+
_, err := forkAndExecFunction(doLs)
132106
require.NoError(t, err)
133107

134108
waitForTraceeOutput(t, gotOutput, time.Now(), true)
@@ -150,7 +124,7 @@ func checkExecve(t *testing.T, gotOutput *[]trace.Event) {
150124

151125
// check for filesystem set when ls is invoked
152126
func checkSetFs(t *testing.T, gotOutput *[]trace.Event) {
153-
err := exec.Command("/usr/bin/ls").Run()
127+
_, err := forkAndExecFunction(doLs)
154128
require.NoError(t, err)
155129

156130
waitForTraceeOutput(t, gotOutput, time.Now(), true)
@@ -171,11 +145,9 @@ func checkSetFs(t *testing.T, gotOutput *[]trace.Event) {
171145
}
172146

173147
func checkNewContainers(t *testing.T, gotOutput *[]trace.Event) {
174-
containerIdBytes, err := exec.Command("docker", "run", "-d", "--rm", "alpine").Output()
148+
containerIdBytes, err := forkAndExecFunction(doDockerRun)
175149
require.NoError(t, err)
176-
177150
containerId := strings.TrimSuffix(string(containerIdBytes), "\n")
178-
179151
containerIds := []string{}
180152
for _, evt := range *gotOutput {
181153
containerIds = append(containerIds, evt.ContainerID)
@@ -202,11 +174,11 @@ func Test_EventFilters(t *testing.T) {
202174
filterArgs []string
203175
eventFunc func(*testing.T, *[]trace.Event)
204176
}{
205-
// {
206-
// name: "do a file write",
207-
// filterArgs: []string{"event=magic_write"},
208-
// eventFunc: checkMagicwrite,
209-
// },
177+
{
178+
name: "do a file write",
179+
filterArgs: []string{"event=magic_write"},
180+
eventFunc: checkMagicwrite,
181+
},
210182
{
211183
name: "execute a command",
212184
filterArgs: []string{"comm=ls"},
@@ -291,3 +263,37 @@ func Test_EventFilters(t *testing.T) {
291263
})
292264
}
293265
}
266+
267+
type testFunc string
268+
269+
const (
270+
doMagicWrite testFunc = "do_magic_write"
271+
doLs testFunc = "do_ls"
272+
doDockerRun testFunc = "do_docker_run"
273+
)
274+
275+
// forkAndExecFunction runs a function in `tester.sh` in it's own system process.
276+
// This is so Tracee running in the current pid can pick the command up.
277+
// It returns the output of the process and a possible error.
278+
func forkAndExecFunction(funcName testFunc) ([]byte, error) {
279+
tmpFile, err := os.CreateTemp("/tmp", "tracee-test*")
280+
if err != nil {
281+
return nil, err
282+
}
283+
_, err = syscall.ForkExec("./tester.sh", []string{"./tester.sh", string(funcName), tmpFile.Name()},
284+
&syscall.ProcAttr{
285+
Files: []uintptr{0, 1, 2, tmpFile.Fd()},
286+
})
287+
if err != nil {
288+
return nil, err
289+
}
290+
291+
// ForkExec doesn't block, wait for output
292+
time.Sleep(time.Second)
293+
294+
output, err := ioutil.ReadAll(tmpFile)
295+
if err != nil {
296+
return nil, err
297+
}
298+
return output, nil
299+
}

tests/integration/tester.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
3+
do_magic_write() {
4+
tmpFileName=$1
5+
echo "AAAAA" > $tmpFileName
6+
}
7+
8+
do_ls() {
9+
ls > /dev/null
10+
}
11+
12+
do_docker_run() {
13+
outputFileName=$1
14+
output=$(docker run -d --rm alpine)
15+
$(echo $output > $outputFileName)
16+
}
17+
18+
# $1 is the function to call
19+
# $2 is the temp file to optionally output to
20+
$1 $2

0 commit comments

Comments
 (0)