Skip to content

Commit f6621ae

Browse files
committed
chore: add test for long args, set truncated
1 parent 0b78a82 commit f6621ae

File tree

3 files changed

+96
-9
lines changed

3 files changed

+96
-9
lines changed

tracer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ type Event struct {
5757
// (which is equal to `filepath.Base(e.Filename)` in most circumstances).
5858
Argv []string `json:"argv"`
5959
// Truncated is true if we were unable to read all process arguments into
60-
// Argv because there were more than ARGLEN arguments.
60+
// Argv because there were more than 32 arguments, or if one of the
61+
// arguments was greater than or equal to 1023 bytes in length.
62+
//
63+
// It may indicate that the user or process is trying to hide arguments from
64+
// the tracer.
6165
Truncated bool `json:"truncated"`
6266

6367
// These values are of the new process. Keep in mind that the exec call may

tracer_linux.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ func (t *tracer) Read() (*Event, error) {
232232
}
233233
for i := 0; i < argc; i++ {
234234
str := unix.ByteSliceToString(rawEvent.Argv[i][:])
235+
// The copy in the eBPF code only copies 1023 bytes.
236+
if len(str) >= argsize-1 {
237+
ev.Truncated = true
238+
// Set final 3 bytes to "..." to indicate truncation.
239+
str = str[:argsize-3] + "..."
240+
}
235241
if strings.TrimSpace(str) != "" {
236242
ev.Argv = append(ev.Argv, str)
237243
}

tracer_linux_test.go

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package exectrace_test
55

66
import (
77
"context"
8+
"fmt"
89
"io"
910
"os"
1011
"os/exec"
@@ -40,11 +41,11 @@ func TestExectrace(t *testing.T) {
4041

4142
// Launch processes.
4243
const (
43-
expected = "hello exectrace test 1"
44+
expected = "hello exectrace basic test"
4445
uid = 1000
4546
gid = 2000
4647
)
47-
var args = []string{"sh", "-c", "# " + expected}
48+
args := []string{"sh", "-c", "# " + expected}
4849
filename, err := exec.LookPath(args[0])
4950
require.NoError(t, err)
5051
processDone := spamProcess(ctx, t, args, func(cmd *exec.Cmd) {
@@ -76,6 +77,82 @@ func TestExectrace(t *testing.T) {
7677
<-processDone
7778
}
7879

80+
func TestExectraceTruncatedArgs(t *testing.T) {
81+
// This test must be run as root so we can start exectrace.
82+
if os.Geteuid() != 0 {
83+
t.Fatal("must be run as root")
84+
}
85+
86+
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
87+
defer cancel()
88+
89+
tracer, err := exectrace.New(&exectrace.TracerOpts{
90+
LogFn: func(uid, gid, pid uint32, logLine string) {
91+
t.Errorf("tracer error log (uid=%v, gid=%v, pid=%v): %s", uid, gid, pid, logLine)
92+
},
93+
})
94+
require.NoError(t, err)
95+
defer tracer.Close()
96+
97+
const expected = "hello exectrace overflow test"
98+
args := []string{"echo", expected}
99+
100+
// Exectrace only captures the first 32 arguments of each process.
101+
for i := 0; i < 30; i++ {
102+
args = append(args, fmt.Sprint(i))
103+
}
104+
args = append(args, "final")
105+
require.Len(t, args, 33)
106+
107+
// Launch processes.
108+
processDone := spamProcess(ctx, t, args, nil)
109+
event := getLogEntry(ctx, t, tracer, expected)
110+
111+
// Should only hold the first 32 args, and truncated should be true.
112+
require.Len(t, event.Argv, 32)
113+
require.Equal(t, args[:32], event.Argv, "event.Argv")
114+
require.True(t, event.Truncated, "event.Truncated is false")
115+
116+
cancel()
117+
<-processDone
118+
}
119+
120+
func TestExectraceTruncatedLongArg(t *testing.T) {
121+
// This test must be run as root so we can start exectrace.
122+
if os.Geteuid() != 0 {
123+
t.Fatal("must be run as root")
124+
}
125+
126+
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
127+
defer cancel()
128+
129+
tracer, err := exectrace.New(&exectrace.TracerOpts{
130+
LogFn: func(uid, gid, pid uint32, logLine string) {
131+
t.Errorf("tracer error log (uid=%v, gid=%v, pid=%v): %s", uid, gid, pid, logLine)
132+
},
133+
})
134+
require.NoError(t, err)
135+
defer tracer.Close()
136+
137+
// We only record the first 1024 bytes of each argument, so use an arg
138+
// that's longer.
139+
const expected = "hello exectrace arg length test"
140+
args := []string{"echo", expected, strings.Repeat("a", 1025), "final"}
141+
142+
// Launch processes.
143+
processDone := spamProcess(ctx, t, args, nil)
144+
event := getLogEntry(ctx, t, tracer, expected)
145+
146+
// Should only hold the first 1021 chars of the long arg with a trailing
147+
// "...".
148+
args[2] = args[2][:1021] + "..."
149+
require.Equal(t, args, event.Argv, "event.Argv")
150+
require.True(t, event.Truncated, "event.Truncated is false")
151+
152+
cancel()
153+
<-processDone
154+
}
155+
79156
//nolint:paralleltest
80157
func TestExectracePIDNS(t *testing.T) {
81158
// This test must be run as root so we can start exectrace.
@@ -100,8 +177,8 @@ func TestExectracePIDNS(t *testing.T) {
100177
defer tracer.Close()
101178

102179
// Launch processes.
103-
const expected = "hello exectrace test 2"
104-
var args = []string{"sh", "-c", "# " + expected}
180+
const expected = "hello exectrace pidns test same"
181+
args := []string{"sh", "-c", "# " + expected}
105182
processDone := spamProcess(ctx, t, args, nil)
106183

107184
_ = getLogEntry(ctx, t, tracer, expected)
@@ -127,8 +204,8 @@ func TestExectracePIDNS(t *testing.T) {
127204
defer tracer.Close()
128205

129206
// Launch processes.
130-
const expected = "hello exectrace test 3"
131-
var args = []string{"sh", "-c", "# " + expected}
207+
const expected = "hello exectrace pidns test child"
208+
args := []string{"sh", "-c", "# " + expected}
132209
processDone := spamProcess(ctx, t, args, func(cmd *exec.Cmd) {
133210
cmd.SysProcAttr = &syscall.SysProcAttr{
134211
// Subprocess will be in a child PID namespace.
@@ -159,8 +236,8 @@ func TestExectracePIDNS(t *testing.T) {
159236
defer tracer.Close()
160237

161238
// Launch processes.
162-
const expected = "hello exectrace test 3"
163-
var args = []string{"sh", "-c", "# " + expected}
239+
const expected = "hello exectrace pidns test different"
240+
args := []string{"sh", "-c", "# " + expected}
164241
processDone := spamProcess(ctx, t, args, nil)
165242

166243
// We should not see any events. Read events for up to 5 seconds.

0 commit comments

Comments
 (0)