github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/signal/tracer/tracer_test.go (about) 1 // Copyright 2022-2023 The Inspektor Gadget authors 2 // 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 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 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. 14 15 //go:build linux 16 // +build linux 17 18 package tracer_test 19 20 import ( 21 "fmt" 22 "os" 23 "path" 24 "syscall" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/require" 29 "golang.org/x/sys/unix" 30 31 utilstest "github.com/inspektor-gadget/inspektor-gadget/internal/test" 32 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/signal/tracer" 33 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/signal/types" 34 eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 35 ) 36 37 func TestSignalTracerCreate(t *testing.T) { 38 t.Parallel() 39 40 utilstest.RequireRoot(t) 41 42 tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {}) 43 require.NotNil(t, tracer, "Returned tracer was nil") 44 } 45 46 func TestSignalTracerStopIdempotent(t *testing.T) { 47 t.Parallel() 48 49 utilstest.RequireRoot(t) 50 51 tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {}) 52 53 // Check that a double stop doesn't cause issues 54 tracer.Stop() 55 tracer.Stop() 56 } 57 58 func TestSignalTracer(t *testing.T) { 59 t.Parallel() 60 61 utilstest.RequireRoot(t) 62 63 const unprivilegedUID = int(1435) 64 const unprivilegedGID = int(6789) 65 66 type testDefinition struct { 67 getTracerConfig func(info *utilstest.RunnerInfo) *tracer.Config 68 runnerConfig *utilstest.RunnerConfig 69 signalToSend syscall.Signal 70 generateEvent func(syscall.Signal) (uint32, error) 71 validateEvent func(t *testing.T, info *utilstest.RunnerInfo, childPid uint32, events []types.Event) 72 } 73 74 tests := map[string]testDefinition{ 75 "captures_events_with_matching_filter": { 76 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 77 return &tracer.Config{ 78 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 79 } 80 }, 81 signalToSend: syscall.SIGKILL, 82 generateEvent: generateEvent, 83 validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, childPid uint32) *types.Event { 84 return &types.Event{ 85 Event: eventtypes.Event{ 86 Type: eventtypes.NORMAL, 87 }, 88 Pid: uint32(info.Pid), 89 Comm: path.Base(os.Args[0]), 90 Signal: unix.SignalName(syscall.SIGKILL), 91 TargetPid: childPid, 92 Retval: 0, 93 Uid: uint32(info.Uid), 94 Gid: uint32(info.Gid), 95 WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID}, 96 } 97 }), 98 }, 99 "event_has_UID_and_GID_of_user_generating_event": { 100 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 101 return &tracer.Config{ 102 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 103 } 104 }, 105 runnerConfig: &utilstest.RunnerConfig{ 106 Uid: unprivilegedUID, 107 Gid: unprivilegedGID, 108 }, 109 signalToSend: syscall.SIGKILL, 110 generateEvent: generateEvent, 111 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, _ uint32, events []types.Event) { 112 require.Len(t, events, 1, "One event expected") 113 require.Equal(t, uint32(info.Uid), events[0].Uid, "Event has bad UID") 114 require.Equal(t, uint32(info.Gid), events[0].Gid, "Event has bad GID") 115 }, 116 }, 117 } 118 119 for sig := syscall.SIGABRT; sig <= syscall.SIGXFSZ; sig++ { 120 signal := sig 121 tests[fmt.Sprintf("send_%s", unix.SignalName(signal))] = testDefinition{ 122 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 123 return &tracer.Config{ 124 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 125 } 126 }, 127 signalToSend: signal, 128 generateEvent: generateEvent, 129 validateEvent: utilstest.ExpectAtLeastOneEvent(func(info *utilstest.RunnerInfo, childPid uint32) *types.Event { 130 return &types.Event{ 131 Event: eventtypes.Event{ 132 Type: eventtypes.NORMAL, 133 }, 134 Pid: uint32(info.Pid), 135 Comm: path.Base(os.Args[0]), 136 Signal: unix.SignalName(signal), 137 TargetPid: childPid, 138 Retval: 0, 139 Uid: uint32(info.Uid), 140 Gid: uint32(info.Gid), 141 WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID}, 142 } 143 }), 144 } 145 } 146 147 for name, test := range tests { 148 test := test 149 150 t.Run(name, func(t *testing.T) { 151 t.Parallel() 152 153 events := []types.Event{} 154 eventCallback := func(event *types.Event) { 155 // normalize 156 event.Timestamp = 0 157 158 events = append(events, *event) 159 } 160 161 runner := utilstest.NewRunnerWithTest(t, test.runnerConfig) 162 163 createTracer(t, test.getTracerConfig(runner.Info), eventCallback) 164 165 var childPid uint32 166 167 utilstest.RunWithRunner(t, runner, func() error { 168 var err error 169 childPid, err = test.generateEvent(test.signalToSend) 170 return err 171 }) 172 173 // Give some time for the tracer to capture the events 174 time.Sleep(100 * time.Millisecond) 175 176 test.validateEvent(t, runner.Info, childPid, events) 177 }) 178 } 179 } 180 181 func createTracer( 182 t *testing.T, config *tracer.Config, callback func(*types.Event), 183 ) *tracer.Tracer { 184 t.Helper() 185 186 tracer, err := tracer.NewTracer(config, nil, callback) 187 require.Nil(t, err, "Error creating tracer: %s", err) 188 t.Cleanup(tracer.Stop) 189 190 return tracer 191 } 192 193 func generateEvent(signal syscall.Signal) (uint32, error) { 194 childPid, err := syscall.ForkExec("/bin/sleep", []string{"inf"}, nil) 195 if err != nil { 196 return 0, fmt.Errorf("spawning child process: %w", err) 197 } 198 199 // We only test kill and not tkill or tgkill as this is a pain to deal with 200 // pthread in golang. 201 err = syscall.Kill(childPid, signal) 202 if err != nil { 203 return 0, fmt.Errorf("sending signal %d to process %d: %w", signal, childPid, err) 204 } 205 206 return uint32(childPid), nil 207 }