From a250225c19b353d6928cee24a5d2fab56c42bec3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Dec 2023 23:24:20 +0000 Subject: [PATCH] tetragon: Add support to detect available exit probes Adding support to use disassociate_ctty exit probe in case acct_process is missing in kernel. Detecting both probes during base sensor setup and picking up available function and adding new log line: time="2023-12-11T14:44:28Z" level=info msg="Exit probe on acct_process" failed=false The failed value will be true when the kallsyms detection fails. Signed-off-by: Jiri Olsa --- bpf/process/bpf_exit.c | 20 +++++++++++++++++++- pkg/ksyms/ksyms.go | 9 +++++++++ pkg/sensors/base/base.go | 26 ++++++++++++++++++++++++++ pkg/testutils/sensors/load.go | 2 +- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/bpf/process/bpf_exit.c b/bpf/process/bpf_exit.c index f5cf2dd88e9..baadae713f5 100644 --- a/bpf/process/bpf_exit.c +++ b/bpf/process/bpf_exit.c @@ -43,10 +43,28 @@ char _license[] __attribute__((section("license"), used)) = "Dual BSD/GPL"; * we are the last one of the thread group. */ __attribute__((section("kprobe/acct_process"), used)) int -event_exit(struct pt_regs *ctx) +event_exit_acct_process(struct pt_regs *ctx) { __u64 pid_tgid = get_current_pid_tgid(); event_exit_send(ctx, pid_tgid >> 32); return 0; } + +/* + * Hooking on acct_process kernel function, which is called on the task's + * exit path once the task is the last one in the group. It's stable since + * v4.19, so it's safe to hook for us. + * + * It's called with on_exit argument != 0 when called from do_exit + * function with same conditions like for acct_process described above. + */ +__attribute__((section("kprobe/disassociate_ctty"), used)) int +event_exit_disassociate_ctty(struct pt_regs *ctx) +{ + int on_exit = (int)PT_REGS_PARM1_CORE(ctx); + + if (on_exit) + event_exit_send(ctx, get_current_pid_tgid() >> 32); + return 0; +} diff --git a/pkg/ksyms/ksyms.go b/pkg/ksyms/ksyms.go index 461a36e2dee..9f7587f07ed 100644 --- a/pkg/ksyms/ksyms.go +++ b/pkg/ksyms/ksyms.go @@ -193,3 +193,12 @@ func (k *Ksyms) getFnOffset(addr uint64) (*FnOffset, error) { Offset: addr - sym.addr, }, nil } + +func (k *Ksyms) IsAvailable(name string) bool { + for _, sym := range k.table { + if sym.name == name { + return true + } + } + return false +} diff --git a/pkg/sensors/base/base.go b/pkg/sensors/base/base.go index a5ed3b26021..441e5ac9121 100644 --- a/pkg/sensors/base/base.go +++ b/pkg/sensors/base/base.go @@ -4,7 +4,12 @@ package base import ( + "log" + "sync" + "github.com/cilium/tetragon/pkg/kernels" + "github.com/cilium/tetragon/pkg/ksyms" + "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/sensors" "github.com/cilium/tetragon/pkg/sensors/program" ) @@ -64,6 +69,26 @@ var ( sensorInit sync.Once ) +func setupExitProgram() { + ks, err := ksyms.KernelSymbols() + if err == nil { + has_acct_process := ks.IsAvailable("acct_process") + has_disassociate_ctty := ks.IsAvailable("disassociate_ctty") + + /* Preffer acct_process over disassociate_ctty */ + if has_acct_process { + Exit.Attach = "acct_process" + Exit.Label = "kprobe/acct_process" + } else if has_disassociate_ctty { + Exit.Attach = "disassociate_ctty" + Exit.Label = "kprobe/disassociate_ctty" + } else { + log.Fatal("Failed to detect exit probe symbol.") + } + } + logger.GetLogger().Infof("Exit probe on %s", Exit.Attach) +} + func GetExecveMap() *program.Map { return ExecveMap } @@ -104,6 +129,7 @@ func GetDefaultMaps() []*program.Map { // GetInitialSensor returns the base sensor func GetInitialSensor() *sensors.Sensor { sensorInit.Do(func() { + setupExitProgram() sensor.Progs = GetDefaultPrograms() sensor.Maps = GetDefaultMaps() }) diff --git a/pkg/testutils/sensors/load.go b/pkg/testutils/sensors/load.go index 39c2e226d6e..2d34ef05adb 100644 --- a/pkg/testutils/sensors/load.go +++ b/pkg/testutils/sensors/load.go @@ -131,7 +131,7 @@ func mergeSensorMaps(t *testing.T, maps1, maps2 []SensorMap, progs1, progs2 []Se func mergeInBaseSensorMaps(t *testing.T, sensorMaps []SensorMap, sensorProgs []SensorProg) ([]SensorMap, []SensorProg) { var baseProgs = []SensorProg{ 0: SensorProg{Name: "event_execve", Type: ebpf.TracePoint}, - 1: SensorProg{Name: "event_exit", Type: ebpf.Kprobe}, + 1: SensorProg{Name: "event_exit", Type: ebpf.Kprobe, Match: ProgMatchPartial}, 2: SensorProg{Name: "event_wake_up_new_task", Type: ebpf.Kprobe}, 3: SensorProg{Name: "execve_send", Type: ebpf.TracePoint}, 4: SensorProg{Name: "tg_kp_bprm_committing_creds", Type: ebpf.Kprobe},