1
// Copyright 2022-2023 The Inspektor Gadget authors
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
29
"golang.org/x/sys/unix"
31
utilstest "github.com/inspektor-gadget/inspektor-gadget/internal/test"
32
"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/open/tracer"
33
"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/open/types"
34
eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
37
func TestOpenTracerCreate(t *testing.T) {
40
utilstest.RequireRoot(t)
42
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
44
t.Fatal("Returned tracer was nil")
48
func TestOpenTracerStopIdempotent(t *testing.T) {
51
utilstest.RequireRoot(t)
53
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
55
// Check that a double stop doesn't cause issues
61
t *testing.T, config *tracer.Config, callback func(*types.Event),
65
tracer, err := tracer.NewTracer(config, nil, callback)
67
t.Fatalf("Error creating tracer: %s", err)
69
t.Cleanup(tracer.Stop)
74
func generateRelativePathForAbsolutePath(t *testing.T, fileName string) string {
75
// If the filename is relative, return it as is
76
if !filepath.IsAbs(fileName) {
80
cwd, err := os.Getwd()
82
t.Errorf("Error getting current working directory: %s", err)
85
relPath, err := filepath.Rel(cwd, fileName)
87
t.Errorf("Error getting relative path: %s", err)
93
func generateLongDirPath(t *testing.T) string {
96
slice := make([]string, size)
97
for i := 0; i < size; i++ {
100
return path.Join("/tmp", path.Join(slice...))
103
func TestOpenTracer(t *testing.T) {
106
utilstest.RequireRoot(t)
108
const unprivilegedUID = int(1435)
109
const unprivilegedGID = int(6789)
111
type testDefinition struct {
112
getTracerConfig func(info *utilstest.RunnerInfo) *tracer.Config
113
runnerConfig *utilstest.RunnerConfig
114
generateEvent func() (int, error)
115
validateEvent func(*testing.T, *utilstest.RunnerInfo, int, []types.Event)
118
for name, test := range map[string]testDefinition{
119
"captures_all_events_with_no_filters_configured": {
120
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
121
return &tracer.Config{}
123
generateEvent: generateEvent,
124
validateEvent: utilstest.ExpectAtLeastOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
126
Event: eventtypes.Event{
127
Type: eventtypes.NORMAL,
129
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
130
Pid: uint32(info.Pid),
131
Uid: uint32(info.Uid),
137
Flags: []string{"O_RDONLY"},
142
"captures_no_events_with_no_matching_filter": {
143
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
144
return &tracer.Config{
145
MountnsMap: utilstest.CreateMntNsFilterMap(t, 0),
148
generateEvent: generateEvent,
149
validateEvent: utilstest.ExpectNoEvent[types.Event, int],
151
"captures_events_with_matching_filter": {
152
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
153
return &tracer.Config{
154
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
157
generateEvent: generateEvent,
158
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
160
Event: eventtypes.Event{
161
Type: eventtypes.NORMAL,
163
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
164
Pid: uint32(info.Pid),
165
Uid: uint32(info.Uid),
172
Flags: []string{"O_RDONLY"},
177
"test_flags_and_mode": {
178
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
179
return &tracer.Config{
180
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
183
generateEvent: func() (int, error) {
184
filename := "/tmp/test_flags_and_mode"
185
fd, err := unix.Open(filename, unix.O_CREAT|unix.O_RDWR, unix.S_IRWXU|unix.S_IRGRP|unix.S_IWGRP|unix.S_IXOTH)
187
return 0, fmt.Errorf("opening file: %w", err)
190
defer os.Remove(filename)
196
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
198
Event: eventtypes.Event{
199
Type: eventtypes.NORMAL,
201
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
202
Pid: uint32(info.Pid),
203
Uid: uint32(info.Uid),
208
Path: "/tmp/test_flags_and_mode",
210
Flags: []string{"O_RDWR", "O_CREAT"},
211
FlagsRaw: unix.O_CREAT | unix.O_RDWR,
213
ModeRaw: unix.S_IRWXU | unix.S_IRGRP | unix.S_IWGRP | unix.S_IXOTH,
217
"test_relative_path": {
218
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
219
return &tracer.Config{
220
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
224
generateEvent: func() (int, error) {
225
relPath := generateRelativePathForAbsolutePath(t, "/tmp/test_relative_path")
226
fd, err := unix.Open(relPath, unix.O_CREAT|unix.O_RDWR, unix.S_IRWXU|unix.S_IRGRP|unix.S_IWGRP|unix.S_IXOTH)
228
return 0, fmt.Errorf("opening file: %w", err)
231
defer os.Remove(relPath)
237
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
238
relPath := generateRelativePathForAbsolutePath(t, "/tmp/test_relative_path")
240
Event: eventtypes.Event{
241
Type: eventtypes.NORMAL,
243
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
244
Pid: uint32(info.Pid),
245
Uid: uint32(info.Uid),
251
FullPath: "/tmp/test_relative_path",
252
Flags: []string{"O_RDWR", "O_CREAT"},
253
FlagsRaw: unix.O_CREAT | unix.O_RDWR,
255
ModeRaw: unix.S_IRWXU | unix.S_IRGRP | unix.S_IWGRP | unix.S_IXOTH,
259
"test_symbolic_links": {
260
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
261
return &tracer.Config{
262
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
266
generateEvent: func() (int, error) {
267
// Create a symbolic link to /dev/null
268
err := os.Symlink("/dev/null", "/tmp/test_symbolic_links")
270
return 0, fmt.Errorf("creating symbolic link: %w", err)
272
defer os.Remove("/tmp/test_symbolic_links")
274
// Open the symbolic link
275
fd, err := unix.Open("/tmp/test_symbolic_links", unix.O_RDONLY, 0)
277
return 0, fmt.Errorf("opening file: %w", err)
283
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
285
Event: eventtypes.Event{
286
Type: eventtypes.NORMAL,
288
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
289
Pid: uint32(info.Pid),
290
Uid: uint32(info.Uid),
295
Path: "/tmp/test_symbolic_links",
296
FullPath: "/dev/null",
297
Flags: []string{"O_RDONLY"},
303
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
304
return &tracer.Config{
305
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
309
generateEvent: func() (int, error) {
310
dirPath := generateLongDirPath(t)
311
err := os.MkdirAll(generateLongDirPath(t), 0o755)
313
return 0, fmt.Errorf("creating directory: %w", err)
315
fd, err := unix.Open(path.Join(dirPath, "test_long_path"), unix.O_CREAT|unix.O_RDWR, unix.S_IRWXU|unix.S_IRGRP|unix.S_IWGRP|unix.S_IXOTH)
317
return 0, fmt.Errorf("opening file: %w", err)
320
defer os.RemoveAll(path.Join(dirPath, "test_long_path"))
326
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
327
longPath := path.Join(generateLongDirPath(t), "test_long_path")
329
Event: eventtypes.Event{
330
Type: eventtypes.NORMAL,
332
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
333
Pid: uint32(info.Pid),
334
Uid: uint32(info.Uid),
339
Path: longPath[:254],
341
Flags: []string{"O_RDWR", "O_CREAT"},
342
FlagsRaw: unix.O_CREAT | unix.O_RDWR,
344
ModeRaw: unix.S_IRWXU | unix.S_IRGRP | unix.S_IWGRP | unix.S_IXOTH,
348
"test_prefix_on_directory": {
349
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
350
return &tracer.Config{
351
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
352
Prefixes: []string{"/tmp/foo"},
355
generateEvent: func() (int, error) {
356
err := os.Mkdir("/tmp/foo", 0o750)
358
return 0, fmt.Errorf("creating directory: %w", err)
360
defer os.RemoveAll("/tmp/foo")
362
fd, err := unix.Open("/tmp/foo/bar.test", unix.O_RDONLY|unix.O_CREAT, 0)
364
return 0, fmt.Errorf("opening file: %w", err)
368
badfd, err := unix.Open("/tmp/quux.test", unix.O_RDONLY|unix.O_CREAT, 0)
370
return 0, fmt.Errorf("opening file: %w", err)
372
defer unix.Close(badfd)
376
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
378
Event: eventtypes.Event{
379
Type: eventtypes.NORMAL,
381
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
382
Pid: uint32(info.Pid),
383
Uid: uint32(info.Uid),
388
Path: "/tmp/foo/bar.test",
389
Flags: []string{"O_RDONLY", "O_CREAT"},
390
FlagsRaw: unix.O_RDONLY | unix.O_CREAT,
395
"test_prefix_on_file": {
396
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
397
return &tracer.Config{
398
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
399
Prefixes: []string{"/tmp/foo.test"},
402
generateEvent: func() (int, error) {
403
fd, err := unix.Open("/tmp/foo.test", unix.O_RDONLY|unix.O_CREAT, 0)
405
return 0, fmt.Errorf("opening file: %w", err)
409
badfd, err := unix.Open("/tmp/quux.test", unix.O_RDONLY|unix.O_CREAT, 0)
411
return 0, fmt.Errorf("opening file: %w", err)
413
defer unix.Close(badfd)
417
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, fd int) *types.Event {
419
Event: eventtypes.Event{
420
Type: eventtypes.NORMAL,
422
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
423
Pid: uint32(info.Pid),
424
Uid: uint32(info.Uid),
429
Path: "/tmp/foo.test",
430
Flags: []string{"O_RDONLY", "O_CREAT"},
431
FlagsRaw: unix.O_RDONLY | unix.O_CREAT,
436
"event_has_UID_and_GID_of_user_generating_event": {
437
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
438
return &tracer.Config{
439
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
442
runnerConfig: &utilstest.RunnerConfig{
443
Uid: unprivilegedUID,
444
Gid: unprivilegedGID,
446
generateEvent: generateEvent,
447
validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, _ int, events []types.Event) {
448
if len(events) != 1 {
449
t.Fatalf("One event expected")
452
utilstest.Equal(t, uint32(info.Uid), events[0].Uid,
453
"Captured event has bad UID")
455
utilstest.Equal(t, uint32(info.Gid), events[0].Gid,
456
"Captured event event has bad GID")
459
"event_has_correct_error": {
460
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
461
return &tracer.Config{
462
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
465
generateEvent: func() (int, error) {
466
_, err := unix.Open("non-existing-file", 0, 0)
468
return 0, fmt.Errorf("error was expected")
473
validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, _ int, events []types.Event) {
474
if len(events) != 1 {
475
t.Fatalf("One event expected")
478
utilstest.Equal(t, int(unix.ENOENT), events[0].Err,
479
"Captured event has bad Err")
482
"event_has_correct_ret_on_error": {
483
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
484
return &tracer.Config{
485
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
488
generateEvent: func() (int, error) {
489
_, err := unix.Open("non-existing-file", 0, 0)
491
return 0, fmt.Errorf("error was expected")
496
validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, _ int, events []types.Event) {
497
if len(events) != 1 {
498
t.Fatalf("One event expected")
501
utilstest.Equal(t, -int(unix.ENOENT), events[0].Ret,
502
"Captured event has bad Ret")
508
t.Run(name, func(t *testing.T) {
511
events := []types.Event{}
512
eventCallback := func(event *types.Event) {
516
events = append(events, *event)
519
runner := utilstest.NewRunnerWithTest(t, test.runnerConfig)
521
createTracer(t, test.getTracerConfig(runner.Info), eventCallback)
525
utilstest.RunWithRunner(t, runner, func() error {
527
fd, err = test.generateEvent()
531
// Give some time for the tracer to capture the events
532
time.Sleep(100 * time.Millisecond)
534
test.validateEvent(t, runner.Info, fd, events)
540
func TestOpenTracerMultipleMntNsIDsFilter(t *testing.T) {
543
utilstest.RequireRoot(t)
545
events := []types.Event{}
546
eventCallback := func(event *types.Event) {
547
events = append(events, *event)
550
// struct with only fields we want to check on this test
551
type expectedEvent struct {
557
runners := make([]*utilstest.Runner, n)
558
expectedEvents := make([]expectedEvent, n)
559
mntNsIDs := make([]uint64, n)
561
for i := 0; i < n; i++ {
562
runners[i] = utilstest.NewRunnerWithTest(t, nil)
563
mntNsIDs[i] = runners[i].Info.MountNsID
564
expectedEvents[i].mntNsID = runners[i].Info.MountNsID
567
// Filter events from all runners but last one
568
config := &tracer.Config{
569
MountnsMap: utilstest.CreateMntNsFilterMap(t, mntNsIDs[:n-1]...),
572
createTracer(t, config, eventCallback)
574
for i := 0; i < n; i++ {
575
utilstest.RunWithRunner(t, runners[i], func() error {
577
expectedEvents[i].fd, err = generateEvent()
582
// Give some time for the tracer to capture the events
583
time.Sleep(100 * time.Millisecond)
585
if len(events) != n-1 {
586
t.Fatalf("%d events were expected, %d found", n-1, len(events))
589
// Pop last event since it shouldn't have been captured
590
expectedEvents = expectedEvents[:n-1]
592
// Order or events is not guaranteed, then we need to sort before comparing
593
sort.Slice(expectedEvents, func(i, j int) bool {
594
return expectedEvents[i].mntNsID < expectedEvents[j].mntNsID
596
sort.Slice(events, func(i, j int) bool {
597
return events[i].WithMountNsID.MountNsID < events[j].WithMountNsID.MountNsID
600
for i := 0; i < n-1; i++ {
601
utilstest.Equal(t, expectedEvents[i].mntNsID, events[i].WithMountNsID.MountNsID,
602
"Captured event has bad MountNsID")
604
utilstest.Equal(t, expectedEvents[i].fd, events[i].Fd,
605
"Captured event has bad fd")
609
// Function to generate an event used most of the times.
610
// Returns fd of opened file.
611
func generateEvent() (int, error) {
612
fd, err := unix.Open("/dev/null", 0, 0)
614
return 0, fmt.Errorf("opening file: %w", err)