1
// Copyright 2019-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.
15
//go:build !withoutebpf
28
"github.com/cilium/ebpf"
29
"github.com/cilium/ebpf/link"
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"
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
46
func RunCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
47
events, err := runeBPFCollector(config, enricher)
52
if !errors.Is(err, ebpf.ErrNotSupported) {
53
return nil, fmt.Errorf("running ebpf iterator: %w", err)
56
events, err = runProcfsCollector(config, enricher)
58
return nil, fmt.Errorf("running procfs collector: %w", err)
64
func runeBPFCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
65
spec, err := loadProcessCollector()
67
return nil, fmt.Errorf("loading ebpf program: %w", err)
70
consts := map[string]interface{}{
71
"show_threads": config.ShowThreads,
73
objs := processCollectorObjects{}
75
if err := gadgets.LoadeBPFSpec(config.MountnsMap, spec, consts, &objs); err != nil {
76
return nil, fmt.Errorf("loading ebpf spec: %w", err)
81
dumpTaskIter, err := link.AttachIter(link.IterOptions{
82
Program: objs.IgSnapProc,
85
return nil, fmt.Errorf("attaching BPF iterator: %w", err)
87
defer dumpTaskIter.Close()
89
buf, err := bpfiterns.Read(dumpTaskIter)
91
return nil, fmt.Errorf("reading iterator: %w", err)
94
events := []*processcollectortypes.Event{}
96
entrySize := int(unsafe.Sizeof(processCollectorProcessEntry{}))
98
for i := 0; i < len(buf)/entrySize; i++ {
99
entry := (*processCollectorProcessEntry)(unsafe.Pointer(&buf[i*entrySize]))
101
event := processcollectortypes.Event{
102
Event: eventtypes.Event{
103
Type: eventtypes.NORMAL,
105
Pid: int(entry.Tgid),
109
Command: gadgets.FromCString(entry.Comm[:]),
110
ParentPid: int(entry.ParentPid),
111
WithMountNsID: eventtypes.WithMountNsID{MountNsID: entry.MntnsId},
115
enricher.EnrichByMntNs(&event.CommonData, event.MountNsID)
118
events = append(events, &event)
124
func getTidEvent(config *Config, enricher gadgets.DataEnricherByMntNs, pid, tid int) (*processcollectortypes.Event, error) {
127
comm := host.GetProcComm(tid)
128
mntnsid, err := containerutils.GetMntNs(tid)
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)
142
taskPath := filepath.Join(host.HostProcFs, fmt.Sprint(pid), "task", fmt.Sprint(tid))
143
info, err := os.Lstat(taskPath)
145
return nil, fmt.Errorf("getting user of process: %w", err)
148
stat := info.Sys().(*syscall.Stat_t)
150
event := &processcollectortypes.Event{
151
Event: eventtypes.Event{
152
Type: eventtypes.NORMAL,
159
WithMountNsID: eventtypes.WithMountNsID{MountNsID: mntnsid},
163
enricher.EnrichByMntNs(&event.CommonData, event.WithMountNsID.MountNsID)
169
func getPidEvents(config *Config, enricher gadgets.DataEnricherByMntNs, pid int) ([]*processcollectortypes.Event, error) {
170
var events []*processcollectortypes.Event
172
taskPath := filepath.Join(host.HostProcFs, fmt.Sprint(pid), "task")
173
items, err := os.ReadDir(taskPath)
178
for _, item := range items {
183
tid, err := strconv.ParseInt(item.Name(), 10, strconv.IntSize)
188
event, err := getTidEvent(config, enricher, pid, int(tid))
193
events = append(events, event)
199
func runProcfsCollector(config *Config, enricher gadgets.DataEnricherByMntNs) ([]*processcollectortypes.Event, error) {
200
items, err := os.ReadDir(host.HostProcFs)
205
events := []*processcollectortypes.Event{}
207
for _, item := range items {
212
pid, err := strconv.ParseInt(item.Name(), 10, strconv.IntSize)
217
if config.ShowThreads {
218
pidEvents, err := getPidEvents(config, enricher, int(pid))
222
events = append(events, pidEvents...)
224
event, err := getTidEvent(config, enricher, int(pid), int(pid))
228
events = append(events, event)
239
eventHandler func(ev []*processcollectortypes.Event)
242
func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) {
249
func (t *Tracer) SetEventHandlerArray(handler any) {
250
nh, ok := handler.(func(ev []*processcollectortypes.Event))
252
panic("event handler invalid")
257
func (t *Tracer) SetMountNsMap(mntnsMap *ebpf.Map) {
258
t.config.MountnsMap = mntnsMap
261
func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error {
262
t.config.ShowThreads = gadgetCtx.GadgetParams().Get(ParamThreads).AsBool()
264
processes, err := RunCollector(t.config, nil)
266
return fmt.Errorf("running snapshotter: %w", err)
268
t.eventHandler(processes)