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.
28
"github.com/stretchr/testify/require"
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/signal/tracer"
33
"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/signal/types"
34
eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
37
func TestSignalTracerCreate(t *testing.T) {
40
utilstest.RequireRoot(t)
42
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
43
require.NotNil(t, tracer, "Returned tracer was nil")
46
func TestSignalTracerStopIdempotent(t *testing.T) {
49
utilstest.RequireRoot(t)
51
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
53
// Check that a double stop doesn't cause issues
58
func TestSignalTracer(t *testing.T) {
61
utilstest.RequireRoot(t)
63
const unprivilegedUID = int(1435)
64
const unprivilegedGID = int(6789)
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)
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),
81
signalToSend: syscall.SIGKILL,
82
generateEvent: generateEvent,
83
validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, childPid uint32) *types.Event {
85
Event: eventtypes.Event{
86
Type: eventtypes.NORMAL,
88
Pid: uint32(info.Pid),
89
Comm: path.Base(os.Args[0]),
90
Signal: unix.SignalName(syscall.SIGKILL),
93
Uid: uint32(info.Uid),
94
Gid: uint32(info.Gid),
95
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
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),
105
runnerConfig: &utilstest.RunnerConfig{
106
Uid: unprivilegedUID,
107
Gid: unprivilegedGID,
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")
119
for sig := syscall.SIGABRT; sig <= syscall.SIGXFSZ; 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),
127
signalToSend: signal,
128
generateEvent: generateEvent,
129
validateEvent: utilstest.ExpectAtLeastOneEvent(func(info *utilstest.RunnerInfo, childPid uint32) *types.Event {
131
Event: eventtypes.Event{
132
Type: eventtypes.NORMAL,
134
Pid: uint32(info.Pid),
135
Comm: path.Base(os.Args[0]),
136
Signal: unix.SignalName(signal),
139
Uid: uint32(info.Uid),
140
Gid: uint32(info.Gid),
141
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
147
for name, test := range tests {
150
t.Run(name, func(t *testing.T) {
153
events := []types.Event{}
154
eventCallback := func(event *types.Event) {
158
events = append(events, *event)
161
runner := utilstest.NewRunnerWithTest(t, test.runnerConfig)
163
createTracer(t, test.getTracerConfig(runner.Info), eventCallback)
167
utilstest.RunWithRunner(t, runner, func() error {
169
childPid, err = test.generateEvent(test.signalToSend)
173
// Give some time for the tracer to capture the events
174
time.Sleep(100 * time.Millisecond)
176
test.validateEvent(t, runner.Info, childPid, events)
182
t *testing.T, config *tracer.Config, callback func(*types.Event),
186
tracer, err := tracer.NewTracer(config, nil, callback)
187
require.Nil(t, err, "Error creating tracer: %s", err)
188
t.Cleanup(tracer.Stop)
193
func generateEvent(signal syscall.Signal) (uint32, error) {
194
childPid, err := syscall.ForkExec("/bin/sleep", []string{"inf"}, nil)
196
return 0, fmt.Errorf("spawning child process: %w", err)
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)
203
return 0, fmt.Errorf("sending signal %d to process %d: %w", signal, childPid, err)
206
return uint32(childPid), nil