inspektor-gadget

Форк
0
270 строк · 6.8 Кб
1
// Copyright 2019-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 !withoutebpf
16

17
package tracer
18

19
import (
20
	"errors"
21
	"fmt"
22
	"os"
23
	"path/filepath"
24
	"strconv"
25
	"syscall"
26
	"unsafe"
27

28
	"github.com/cilium/ebpf"
29
	"github.com/cilium/ebpf/link"
30

31
	containerutils "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils"
32
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
33
	processcollectortypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/snapshot/process/types"
34
	eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
35
	bpfiterns "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/bpf-iter-ns"
36
	"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
37
)
38

39
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -cc clang -cflags ${CFLAGS} -type process_entry processCollector ./bpf/process-collector.bpf.c -- -Werror -O2 -g -c -x c
40

41
type Config struct {
42
	MountnsMap  *ebpf.Map
43
	ShowThreads bool
44
}
45

46
func RunCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
47
	events, err := runeBPFCollector(config, enricher)
48
	if err == nil {
49
		return events, nil
50
	}
51

52
	if !errors.Is(err, ebpf.ErrNotSupported) {
53
		return nil, fmt.Errorf("running ebpf iterator: %w", err)
54
	}
55

56
	events, err = runProcfsCollector(config, enricher)
57
	if err != nil {
58
		return nil, fmt.Errorf("running procfs collector: %w", err)
59
	}
60

61
	return events, err
62
}
63

64
func runeBPFCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
65
	spec, err := loadProcessCollector()
66
	if err != nil {
67
		return nil, fmt.Errorf("loading ebpf program: %w", err)
68
	}
69

70
	consts := map[string]interface{}{
71
		"show_threads": config.ShowThreads,
72
	}
73
	objs := processCollectorObjects{}
74

75
	if err := gadgets.LoadeBPFSpec(config.MountnsMap, spec, consts, &objs); err != nil {
76
		return nil, fmt.Errorf("loading ebpf spec: %w", err)
77
	}
78

79
	defer objs.Close()
80

81
	dumpTaskIter, err := link.AttachIter(link.IterOptions{
82
		Program: objs.IgSnapProc,
83
	})
84
	if err != nil {
85
		return nil, fmt.Errorf("attaching BPF iterator: %w", err)
86
	}
87
	defer dumpTaskIter.Close()
88

89
	buf, err := bpfiterns.Read(dumpTaskIter)
90
	if err != nil {
91
		return nil, fmt.Errorf("reading iterator: %w", err)
92
	}
93

94
	events := []*processcollectortypes.Event{}
95

96
	entrySize := int(unsafe.Sizeof(processCollectorProcessEntry{}))
97

98
	for i := 0; i < len(buf)/entrySize; i++ {
99
		entry := (*processCollectorProcessEntry)(unsafe.Pointer(&buf[i*entrySize]))
100

101
		event := processcollectortypes.Event{
102
			Event: eventtypes.Event{
103
				Type: eventtypes.NORMAL,
104
			},
105
			Pid:           int(entry.Tgid),
106
			Tid:           int(entry.Pid),
107
			Uid:           entry.Uid,
108
			Gid:           entry.Gid,
109
			Command:       gadgets.FromCString(entry.Comm[:]),
110
			ParentPid:     int(entry.ParentPid),
111
			WithMountNsID: eventtypes.WithMountNsID{MountNsID: entry.MntnsId},
112
		}
113

114
		if enricher != nil {
115
			enricher.EnrichByMntNs(&event.CommonData, event.MountNsID)
116
		}
117

118
		events = append(events, &event)
119
	}
120

121
	return events, nil
122
}
123

124
func getTidEvent(config *Config, enricher gadgets.DataEnricherByMntNs, pid, tid int) (*processcollectortypes.Event, error) {
125
	var val uint32
126

127
	comm := host.GetProcComm(tid)
128
	mntnsid, err := containerutils.GetMntNs(tid)
129
	if err != nil {
130
		return nil, err
131
	}
132

133
	if config.MountnsMap != nil {
134
		// TODO: This would be more efficient to store these elements in user space to avoid
135
		// performing systemcalls to lookup in the eBPF map
136
		err := config.MountnsMap.Lookup(&mntnsid, &val)
137
		if err != nil {
138
			return nil, err
139
		}
140
	}
141

142
	taskPath := filepath.Join(host.HostProcFs, fmt.Sprint(pid), "task", fmt.Sprint(tid))
143
	info, err := os.Lstat(taskPath)
144
	if err != nil {
145
		return nil, fmt.Errorf("getting user of process: %w", err)
146
	}
147

148
	stat := info.Sys().(*syscall.Stat_t)
149

150
	event := &processcollectortypes.Event{
151
		Event: eventtypes.Event{
152
			Type: eventtypes.NORMAL,
153
		},
154
		Tid:           tid,
155
		Pid:           pid,
156
		Uid:           stat.Uid,
157
		Gid:           stat.Gid,
158
		Command:       comm,
159
		WithMountNsID: eventtypes.WithMountNsID{MountNsID: mntnsid},
160
	}
161

162
	if enricher != nil {
163
		enricher.EnrichByMntNs(&event.CommonData, event.WithMountNsID.MountNsID)
164
	}
165

166
	return event, nil
167
}
168

169
func getPidEvents(config *Config, enricher gadgets.DataEnricherByMntNs, pid int) ([]*processcollectortypes.Event, error) {
170
	var events []*processcollectortypes.Event
171

172
	taskPath := filepath.Join(host.HostProcFs, fmt.Sprint(pid), "task")
173
	items, err := os.ReadDir(taskPath)
174
	if err != nil {
175
		return nil, err
176
	}
177

178
	for _, item := range items {
179
		if !item.IsDir() {
180
			continue
181
		}
182

183
		tid, err := strconv.ParseInt(item.Name(), 10, strconv.IntSize)
184
		if err != nil {
185
			continue
186
		}
187

188
		event, err := getTidEvent(config, enricher, pid, int(tid))
189
		if err != nil {
190
			continue
191
		}
192

193
		events = append(events, event)
194
	}
195

196
	return events, nil
197
}
198

199
func runProcfsCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
200
	items, err := os.ReadDir(host.HostProcFs)
201
	if err != nil {
202
		return nil, err
203
	}
204

205
	events := []*processcollectortypes.Event{}
206

207
	for _, item := range items {
208
		if !item.IsDir() {
209
			continue
210
		}
211

212
		pid, err := strconv.ParseInt(item.Name(), 10, strconv.IntSize)
213
		if err != nil {
214
			continue
215
		}
216

217
		if config.ShowThreads {
218
			pidEvents, err := getPidEvents(config, enricher, int(pid))
219
			if err != nil {
220
				continue
221
			}
222
			events = append(events, pidEvents...)
223
		} else {
224
			event, err := getTidEvent(config, enricher, int(pid), int(pid))
225
			if err != nil {
226
				continue
227
			}
228
			events = append(events, event)
229
		}
230
	}
231

232
	return events, nil
233
}
234

235
// ---
236

237
type Tracer struct {
238
	config       *Config
239
	eventHandler func(ev []*processcollectortypes.Event)
240
}
241

242
func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) {
243
	tracer := &Tracer{
244
		config: &Config{},
245
	}
246
	return tracer, nil
247
}
248

249
func (t *Tracer) SetEventHandlerArray(handler any) {
250
	nh, ok := handler.(func(ev []*processcollectortypes.Event))
251
	if !ok {
252
		panic("event handler invalid")
253
	}
254
	t.eventHandler = nh
255
}
256

257
func (t *Tracer) SetMountNsMap(mntnsMap *ebpf.Map) {
258
	t.config.MountnsMap = mntnsMap
259
}
260

261
func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error {
262
	t.config.ShowThreads = gadgetCtx.GadgetParams().Get(ParamThreads).AsBool()
263

264
	processes, err := RunCollector(t.config, nil)
265
	if err != nil {
266
		return fmt.Errorf("running snapshotter: %w", err)
267
	}
268
	t.eventHandler(processes)
269
	return nil
270
}
271

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.