diff --git a/pkg/sensors/program/loader.go b/pkg/sensors/program/loader.go index b709f5c711f..4a2112c8392 100644 --- a/pkg/sensors/program/loader.go +++ b/pkg/sensors/program/loader.go @@ -13,6 +13,7 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/btf" "github.com/cilium/ebpf/link" + "github.com/cilium/tetragon/pkg/bpf" cachedbtf "github.com/cilium/tetragon/pkg/btf" "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/option" @@ -75,7 +76,31 @@ func RawAttachWithFlags(targetFD int, flags uint32) AttachFunc { } } -func TracepointAttach(load *Program) AttachFunc { +func linkPin(lnk link.Link, bpfDir string, load *Program, extra ...string) error { + if !bpf.HasLinkPin() { + return nil + } + + pinPath := filepath.Join(bpfDir, load.PinPath) + if load.Override { + pinPath = pinPath + "_override" + } + if load.RetProbe { + pinPath = pinPath + "_return" + } + if len(extra) != 0 { + pinPath = pinPath + "_" + strings.Join(extra, "_") + } + pinPath = pinPath + "_link" + + err := lnk.Pin(pinPath) + if err != nil { + return fmt.Errorf("pinning link '%s' failed: %w", pinPath, err) + } + return nil +} + +func TracepointAttach(load *Program, bpfDir string) AttachFunc { return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { @@ -87,6 +112,11 @@ func TracepointAttach(load *Program) AttachFunc { if err != nil { return nil, fmt.Errorf("attaching '%s' failed: %w", spec.Name, err) } + err = linkPin(tpLink, bpfDir, load) + if err != nil { + tpLink.Close() + return nil, err + } return &unloader.RelinkUnloader{ UnloadProg: unloader.PinUnloader{Prog: prog}.Unload, IsLinked: true, @@ -157,7 +187,7 @@ func KprobeOpen(load *Program) OpenFunc { } } -func kprobeAttach(load *Program, prog *ebpf.Program, spec *ebpf.ProgramSpec, symbol string) (unloader.Unloader, error) { +func kprobeAttach(load *Program, prog *ebpf.Program, spec *ebpf.ProgramSpec, symbol, bpfDir string, extra ...string) (unloader.Unloader, error) { var linkFn func() (link.Link, error) if load.RetProbe { @@ -170,6 +200,13 @@ func kprobeAttach(load *Program, prog *ebpf.Program, spec *ebpf.ProgramSpec, sym if err != nil { return nil, fmt.Errorf("attaching '%s' failed: %w", spec.Name, err) } + + err = linkPin(lnk, bpfDir, load, extra...) + if err != nil { + lnk.Close() + return nil, err + } + return &unloader.RelinkUnloader{ UnloadProg: unloader.PinUnloader{Prog: prog}.Unload, IsLinked: true, @@ -202,7 +239,7 @@ func kprobeAttachOverride(load *Program, bpfDir string, return fmt.Errorf("pinning '%s' to '%s' failed: %w", load.Label, pinPath, err) } - load.unloaderOverride, err = kprobeAttach(load, prog, spec, load.Attach) + load.unloaderOverride, err = kprobeAttach(load, prog, spec, load.Attach, bpfDir) if err != nil { logger.GetLogger().Warnf("Failed to attach override program: %w", err) } @@ -271,7 +308,7 @@ func KprobeAttach(load *Program, bpfDir string) AttachFunc { } } - return kprobeAttach(load, prog, spec, load.Attach) + return kprobeAttach(load, prog, spec, load.Attach, bpfDir) } } @@ -404,7 +441,7 @@ func LSMAttach() AttachFunc { } func multiKprobeAttach(load *Program, prog *ebpf.Program, - spec *ebpf.ProgramSpec, opts link.KprobeMultiOptions) (unloader.Unloader, error) { + spec *ebpf.ProgramSpec, bpfDir string, opts link.KprobeMultiOptions) (unloader.Unloader, error) { var lnk link.Link var err error @@ -417,6 +454,13 @@ func multiKprobeAttach(load *Program, prog *ebpf.Program, if err != nil { return nil, fmt.Errorf("attaching '%s' failed: %w", spec.Name, err) } + + err = linkPin(lnk, bpfDir, load) + if err != nil { + lnk.Close() + return nil, err + } + return unloader.ChainUnloader{ unloader.PinUnloader{ Prog: prog, @@ -462,7 +506,7 @@ func MultiKprobeAttach(load *Program, bpfDir string) AttachFunc { Symbols: data.Overrides, } - load.unloaderOverride, err = multiKprobeAttach(load, progOverride, progOverrideSpec, opts) + load.unloaderOverride, err = multiKprobeAttach(load, progOverride, progOverrideSpec, bpfDir, opts) if err != nil { logger.GetLogger().Warnf("Failed to attach override program: %w", err) } @@ -473,7 +517,7 @@ func MultiKprobeAttach(load *Program, bpfDir string) AttachFunc { Cookies: data.Cookies, } - return multiKprobeAttach(load, prog, spec, opts) + return multiKprobeAttach(load, prog, spec, bpfDir, opts) } } @@ -486,7 +530,7 @@ func LoadTracepointProgram(bpfDir string, load *Program, verbose int) error { } } opts := &LoadOpts{ - Attach: TracepointAttach(load), + Attach: TracepointAttach(load, bpfDir), TcMap: tc.name, TcPrefix: tc.prefix, } @@ -517,7 +561,7 @@ func LoadKprobeProgram(bpfDir string, load *Program, verbose int) error { return loadProgram(bpfDir, load, opts, verbose) } -func KprobeAttachMany(load *Program, syms []string) AttachFunc { +func KprobeAttachMany(load *Program, syms []string, bpfDir string) AttachFunc { return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { @@ -528,7 +572,7 @@ func KprobeAttachMany(load *Program, syms []string) AttachFunc { } for idx := range syms { - un, err := kprobeAttach(load, prog, spec, syms[idx]) + un, err := kprobeAttach(load, prog, spec, syms[idx], bpfDir, fmt.Sprintf("%d_%s", idx, syms[idx])) if err != nil { return nil, err } @@ -541,7 +585,7 @@ func KprobeAttachMany(load *Program, syms []string) AttachFunc { func LoadKprobeProgramAttachMany(bpfDir string, load *Program, syms []string, verbose int) error { opts := &LoadOpts{ - Attach: KprobeAttachMany(load, syms), + Attach: KprobeAttachMany(load, syms, bpfDir), } return loadProgram(bpfDir, load, opts, verbose) } diff --git a/pkg/sensors/unloader/unloader.go b/pkg/sensors/unloader/unloader.go index 6a31eb7e7d0..0eee616c626 100644 --- a/pkg/sensors/unloader/unloader.go +++ b/pkg/sensors/unloader/unloader.go @@ -10,6 +10,7 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/link" + "github.com/cilium/tetragon/pkg/bpf" "github.com/vishvananda/netlink" "go.uber.org/multierr" "golang.org/x/sys/unix" @@ -55,6 +56,13 @@ type PinUnloader struct { Prog *ebpf.Program } +func linkUnpin(lnk link.Link) error { + if bpf.HasLinkPin() { + return lnk.Unpin() + } + return nil +} + func (pu PinUnloader) Unload() error { defer pu.Prog.Close() return pu.Prog.Unpin() @@ -66,7 +74,8 @@ type LinkUnloader struct { } func (lu LinkUnloader) Unload() error { - return lu.Link.Close() + defer lu.Link.Close() + return linkUnpin(lu.Link) } // rawDetachUnloader can be used to unload cgroup and sockmap programs. @@ -163,6 +172,9 @@ type RelinkUnloader struct { func (u *RelinkUnloader) Unload() error { var ret error if u.IsLinked { + if err := linkUnpin(u.Link); err != nil { + ret = multierr.Append(ret, err) + } if err := u.Link.Close(); err != nil { ret = multierr.Append(ret, err) } else { @@ -178,6 +190,10 @@ func (u *RelinkUnloader) Unlink() error { return errors.New("Unlink failed: program not linked") } + if err := linkUnpin(u.Link); err != nil { + return fmt.Errorf("Unlink failed: %w", err) + } + if err := u.Link.Close(); err != nil { return fmt.Errorf("Unlink failed: %w", err) }