1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright Authors of Tetragon
13
"github.com/cilium/ebpf"
14
cachedbtf "github.com/cilium/tetragon/pkg/btf"
15
"github.com/cilium/tetragon/pkg/kernels"
16
"github.com/cilium/tetragon/pkg/logger"
17
"github.com/cilium/tetragon/pkg/option"
18
"github.com/cilium/tetragon/pkg/sensors/program"
20
"github.com/sirupsen/logrus"
24
BPF_PROG_TYPE_UNSPEC = 0
25
BPF_PROG_TYPE_SOCKET_FILTER = 1
26
BPF_PROG_TYPE_KPROBE = 2
27
BPF_PROG_TYPE_SCHED_CLS = 3
28
BPF_PROG_TYPE_SCHED_ACT = 4
29
BPF_PROG_TYPE_TRACEPOINT = 5
31
BPF_PROG_TYPE_PERF_EVENT = 7
32
BPF_PROG_TYPE_CGROUP_SKB = 8
33
BPF_PROG_TYPE_CGROUP_SOCK = 9
34
BPF_PROG_TYPE_LWT_IN = 10
35
BPF_PROG_TYPE_LWT_OUT = 11
36
BPF_PROG_TYPE_LWT_XMIT = 12
37
BPF_PROG_TYPE_SOCK_OPS = 13
38
BPF_PROG_TYPE_SK_SKB = 14
39
BPF_PROG_TYPE_CGROUP_DEVICE = 15
40
BPF_PROG_TYPE_SK_MSG = 16
41
BPF_PROG_TYPE_RAW_TRACEPOINT = 17
42
BPF_PROG_TYPE_CGROUP_SOCK_ADDR = 18
43
BPF_PROG_TYPE_LWT_SEG6LOCAL = 19
44
BPF_PROG_TYPE_LIRC_MODE2 = 20
45
BPF_PROG_TYPE_SK_REUSEPORT = 21
46
BPF_PROG_TYPE_FLOW_DISSECTOR = 22
47
BPF_PROG_TYPE_CGROUP_SYSCTL = 23
48
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 24
49
BPF_PROG_TYPE_CGROUP_SOCKOPT = 25
50
BPF_PROG_TYPE_TRACING = 26
51
BPF_PROG_TYPE_STRUCT_OPS = 27
52
BPF_PROG_TYPE_EXT = 28
53
BPF_PROG_TYPE_LSM = 29
56
// LoadConfig loads the default sensor, including any from the configuration file.
57
func LoadConfig(bpfDir string, sens []*Sensor) error {
58
load := mergeSensors(sens)
59
if err := load.Load(bpfDir); err != nil {
60
return fmt.Errorf("tetragon, aborting could not load BPF programs: %w", err)
65
// Load loads the sensor, by loading all the BPF programs and maps.
66
func (s *Sensor) Load(bpfDir string) error {
72
return fmt.Errorf("sensor %s has been previously destroyed, please recreate it before loading", s.Name)
75
// Add the loaded programs and maps to All* so they can be unloaded on shutdown.
76
AllPrograms = append(AllPrograms, s.Progs...)
77
AllMaps = append(AllMaps, s.Maps...)
79
logger.GetLogger().WithField("metadata", cachedbtf.GetCachedBTFFile()).Info("BTF file: using metadata file")
80
if _, err := observerMinReqs(); err != nil {
81
return fmt.Errorf("tetragon, aborting minimum requirements not met: %w", err)
84
os.Mkdir(bpfDir, os.ModeDir)
86
l := logger.GetLogger()
88
l.WithField("name", s.Name).Info("Loading sensor")
90
return fmt.Errorf("loading sensor %s failed: sensor already loaded", s.Name)
93
_, verStr, _ := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS)
94
l.Infof("Loading kernel version %s", verStr)
96
if err := s.FindPrograms(); err != nil {
97
return fmt.Errorf("tetragon, aborting could not find BPF programs: %w", err)
100
if err := s.loadMaps(bpfDir); err != nil {
101
return fmt.Errorf("tetragon, aborting could not load sensor BPF maps: %w", err)
104
for _, p := range s.Progs {
105
if p.LoadState.IsLoaded() {
106
l.WithField("prog", p.Name).Info("BPF prog is already loaded, incrementing reference count")
111
if err := observerLoadInstance(bpfDir, p); err != nil {
115
l.WithField("prog", p.Name).WithField("label", p.Label).Debugf("BPF prog was loaded")
117
l.WithField("sensor", s.Name).Infof("Loaded BPF maps and events for sensor successfully")
122
func (s *Sensor) Unload() error {
123
logger.GetLogger().Infof("Unloading sensor %s", s.Name)
125
return fmt.Errorf("unload of sensor %s failed: sensor not loaded", s.Name)
128
if s.PreUnloadHook != nil {
129
if err := s.PreUnloadHook(); err != nil {
130
logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Pre unload hook failed")
134
for _, p := range s.Progs {
138
for _, m := range s.Maps {
139
if err := m.Unload(); err != nil {
140
logger.GetLogger().WithError(err).WithField("map", s.Name).Warn("Failed to unload map")
146
if s.PostUnloadHook != nil {
147
if err := s.PostUnloadHook(); err != nil {
148
logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Post unload hook failed")
155
// Destroy will unload the hook and call DestroyHook, this hook is usually used
156
// to clean up resources that were created during creation of the sensor.
157
func (s *Sensor) Destroy() {
160
// do not return on error but just log since Unload can only error on
161
// sensor being already not loaded
162
logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Unload failed during destroy")
165
if s.DestroyHook != nil {
166
err = s.DestroyHook()
168
logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Destroy hook failed")
174
func (s *Sensor) findProgram(p *program.Program) error {
175
logger.GetLogger().WithField("file", p.Name).Debug("Checking for bpf file")
176
if _, err := os.Stat(p.Name); err == nil {
177
logger.GetLogger().WithField("file", p.Name).Debug("Found bpf file")
180
logger.GetLogger().WithField("file", p.Name).Debug("Candidate bpf file does not exist")
181
last := strings.Split(p.Name, "/")
182
filename := last[len(last)-1]
184
path := path.Join(option.Config.HubbleLib, filename)
185
if _, err := os.Stat(path); err == nil {
187
logger.GetLogger().WithField("file", path).Debug("Found bpf file")
190
logger.GetLogger().WithField("file", path).Debug("Candidate bpf file does not exist")
192
return fmt.Errorf("sensor program %q can not be found", p.Name)
195
// FindPrograms finds all the BPF programs in the sensor on the filesytem.
196
func (s *Sensor) FindPrograms() error {
197
for _, p := range s.Progs {
198
if err := s.findProgram(p); err != nil {
202
for _, m := range s.Maps {
203
if err := s.findProgram(m.Prog); err != nil {
210
// loadMaps loads all the BPF maps in the sensor.
211
func (s *Sensor) loadMaps(bpfDir string) error {
212
l := logger.GetLogger()
213
for _, m := range s.Maps {
214
if m.PinState.IsLoaded() {
215
l.WithFields(logrus.Fields{
218
}).Info("map is already loaded, incrementing reference count")
223
pinPath := filepath.Join(bpfDir, m.PinName)
225
spec, err := ebpf.LoadCollectionSpec(m.Prog.Name)
227
return fmt.Errorf("failed to open collection '%s': %w", m.Prog.Name, err)
229
mapSpec, ok := spec.Maps[m.Name]
231
return fmt.Errorf("map '%s' not found from '%s'", m.Name, m.Prog.Name)
234
if max, ok := m.GetMaxEntries(); ok {
235
mapSpec.MaxEntries = max
238
if innerMax, ok := m.GetMaxInnerEntries(); ok {
239
if innerMs := mapSpec.InnerMap; innerMs != nil {
240
mapSpec.InnerMap.MaxEntries = innerMax
244
if err := m.LoadOrCreatePinnedMap(pinPath, mapSpec); err != nil {
245
return fmt.Errorf("failed to load map '%s' for sensor '%s': %w", m.Name, s.Name, err)
248
l.WithFields(logrus.Fields{
252
}).Info("tetragon, map loaded.")
258
func mergeSensors(sensors []*Sensor) *Sensor {
259
var progs []*program.Program
260
var maps []*program.Map
262
for _, s := range sensors {
263
progs = append(progs, s.Progs...)
264
maps = append(maps, s.Maps...)
273
func observerLoadInstance(bpfDir string, load *program.Program) error {
274
version, _, err := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS)
279
l := logger.GetLogger()
280
l.WithFields(logrus.Fields{
282
"kern_version": version,
283
}).Debug("observerLoadInstance", load.Name, version)
284
if load.Type == "tracepoint" {
285
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
288
"tracepoint", load.Name,
289
).Info("Failed to load, trying to remove and retrying")
291
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
294
return fmt.Errorf("failed prog %s kern_version %d LoadTracingProgram: %w",
295
load.Name, version, err)
297
} else if load.Type == "raw_tracepoint" || load.Type == "raw_tp" {
298
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
301
"raw_tracepoint", load.Name,
302
).Info("Failed to load, trying to remove and retrying")
304
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
307
return fmt.Errorf("failed prog %s kern_version %d LoadRawTracepointProgram: %w",
308
load.Name, version, err)
311
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
312
if err != nil && load.ErrorFatal {
313
return fmt.Errorf("failed prog %s kern_version %d loadInstance: %w",
314
load.Name, version, err)
320
func loadInstance(bpfDir string, load *program.Program, version, verbose int) error {
321
// Check if the load.type is a standard program type. If so, use the standard loader.
322
loadFn, ok := standardTypes[load.Type]
324
logger.GetLogger().WithField("Program", load.Name).
325
WithField("Type", load.Type).
326
WithField("Attach", load.Attach).
327
Info("Loading BPF program")
328
return loadFn(bpfDir, load, verbose)
330
// Otherwise, check for a registered probe type. If one exists, use that.
331
probe, ok := registeredProbeLoad[load.Type]
333
logger.GetLogger().WithField("Program", load.Name).
334
WithField("Type", load.Type).
335
WithField("Attach", load.Attach).
336
Info("Loading registered BPF probe")
337
// Registered probes need extra setup
338
version = kernels.FixKernelVersion(version)
339
return probe.LoadProbe(LoadProbeArgs{
347
return fmt.Errorf("program %s has unregistered type '%s'", load.Label, load.Type)
350
func observerMinReqs() (bool, error) {
351
_, _, err := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS)
353
return false, fmt.Errorf("kernel version lookup failed, required for kprobe")
358
func unloadProgram(prog *program.Program) {
359
log := logger.GetLogger().WithField("label", prog.Label).WithField("pin", prog.PinPath)
361
if !prog.LoadState.IsLoaded() {
362
log.Debugf("Refusing to remove %s, program not loaded", prog.Label)
365
if count := prog.LoadState.RefDec(); count > 0 {
366
log.Debugf("Program reference count %d, not unloading yet", count)
370
if err := prog.Unload(); err != nil {
371
logger.GetLogger().WithField("name", prog.Name).WithError(err).Warn("Failed to unload program")
374
log.Info("BPF prog was unloaded")
377
func UnloadSensors(sens []SensorIface) {
378
for i := range sens {
379
if err := sens[i].Unload(); err != nil {
380
logger.GetLogger().Warnf("Failed to unload sensor: %s", err)