From 23d15ac7ff597d73318a1fa55873a22e2f78a57d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 22 Apr 2024 15:58:39 +0000 Subject: [PATCH] tetragon: Add HasMissedStatsKprobe/Multi functions Signed-off-by: Jiri Olsa --- cmd/tetragon/main.go | 5 +- pkg/bpf/detect.go | 126 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 9 deletions(-) diff --git a/cmd/tetragon/main.go b/cmd/tetragon/main.go index 2e673be21a4..b6a8e52c87b 100644 --- a/cmd/tetragon/main.go +++ b/cmd/tetragon/main.go @@ -209,8 +209,6 @@ func tetragonExecute() error { } defer pidfile.Delete() - log.Info("BPF detected features: ", bpf.LogFeatures()) - if option.Config.ForceLargeProgs && option.Config.ForceSmallProgs { log.Fatalf("Can't specify --force-small-progs and --force-large-progs together") } @@ -352,6 +350,9 @@ func tetragonExecute() error { return err } + // needs BTF, so caling it after InitCachedBTF + log.Info("BPF detected features: ", bpf.LogFeatures()) + if err := observer.InitDataCache(option.Config.DataCacheSize); err != nil { return err } diff --git a/pkg/bpf/detect.go b/pkg/bpf/detect.go index bbed59a3074..dd18b993fab 100644 --- a/pkg/bpf/detect.go +++ b/pkg/bpf/detect.go @@ -14,9 +14,11 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/asm" + ebtf "github.com/cilium/ebpf/btf" "github.com/cilium/ebpf/features" "github.com/cilium/ebpf/link" "github.com/cilium/tetragon/pkg/arch" + "github.com/cilium/tetragon/pkg/btf" "github.com/cilium/tetragon/pkg/logger" "golang.org/x/sys/unix" ) @@ -27,11 +29,13 @@ type Feature struct { } var ( - kprobeMulti Feature - uprobeMulti Feature - buildid Feature - modifyReturn Feature - modifyReturnSyscall Feature + kprobeMulti Feature + uprobeMulti Feature + buildid Feature + modifyReturn Feature + modifyReturnSyscall Feature + missedStatsKprobe Feature + missedStatsKprobeMulti Feature ) func HasOverrideHelper() bool { @@ -218,8 +222,116 @@ func HasProgramLargeSize() bool { return features.HaveLargeInstructions() == nil } +func detectMissedStats() (bool, bool) { + spec, err := btf.NewBTF() + if err != nil { + return false, false + } + + // bpf_link_info + var linkInfo *ebtf.Struct + if err := spec.TypeByName("bpf_link_info", &linkInfo); err != nil { + return false, false + } + + if len(linkInfo.Members) < 4 { + return false, false + } + + // bpf_link_info::union + m := linkInfo.Members[3] + union, ok := m.Type.(*ebtf.Union) + if !ok { + return false, false + } + + kprobe := false + kprobeMulti := false + + hasField := func(st *ebtf.Struct, name string) bool { + for _, m := range st.Members { + if m.Name == name { + return true + } + } + return false + } + + detectKprobeMulti := func(m ebtf.Member) bool { + // bpf_link_info::kprobe_multi + st, ok := m.Type.(*ebtf.Struct) + if !ok { + return false + } + // bpf_link_info::kprobe_multi::missed + return hasField(st, "missed") + } + + detectKprobe := func(m ebtf.Member) bool { + // bpf_link_info::perf_event + st, ok := m.Type.(*ebtf.Struct) + if !ok { + return false + } + + if len(st.Members) < 2 { + return false + } + + // bpf_link_info::perf_event::union + tm := st.Members[1] + un, ok := tm.Type.(*ebtf.Union) + if !ok { + return false + } + + for _, mu := range un.Members { + // bpf_link_info::perf_event::kprobe + if mu.Name == "kprobe" { + st2, ok := mu.Type.(*ebtf.Struct) + if !ok { + return false + } + // bpf_link_info::perf_event::kprobe::missed + return hasField(st2, "missed") + } + } + return false + } + + for _, m := range union.Members { + if m.Name == "kprobe_multi" { + kprobeMulti = detectKprobeMulti(m) + } else if m.Name == "perf_event" { + kprobe = detectKprobe(m) + } + } + + return kprobe, kprobeMulti +} + +func detectMissedStatsOnce() { + missedStatsKprobe.init.Do(func() { + kprobe, kprobeMulti := detectMissedStats() + missedStatsKprobe.detected = kprobe + missedStatsKprobeMulti.detected = kprobeMulti + }) +} + +func HasMissedStatsPerfEvent() bool { + detectMissedStatsOnce() + return missedStatsKprobe.detected +} + +func HasMissedStatsKprobeMulti() bool { + detectMissedStatsOnce() + return missedStatsKprobeMulti.detected +} + func LogFeatures() string { - return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, uprobe_multi %t, fmodret: %t, fmodret_syscall: %t, signal: %t, large: %t", + HasMissedStatsPerfEvent() + return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, uprobe_multi %t, fmodret: %t, fmodret_syscall: %t, signal: %t, large: %t, missed_stats_kprobe_multi: %t, missed_stats_kprobe: %t", HasOverrideHelper(), HasBuildId(), HasKprobeMulti(), HasUprobeMulti(), - HasModifyReturn(), HasModifyReturnSyscall(), HasSignalHelper(), HasProgramLargeSize()) + HasModifyReturn(), HasModifyReturnSyscall(), HasSignalHelper(), HasProgramLargeSize(), + HasMissedStatsKprobeMulti(), HasMissedStatsPerfEvent()) }