diff --git a/pkg/sensors/base/base.go b/pkg/sensors/base/base.go index 80ce370f8e6..33deb375708 100644 --- a/pkg/sensors/base/base.go +++ b/pkg/sensors/base/base.go @@ -155,33 +155,6 @@ func GetTetragonConfMap() *program.Map { return TetragonConfMap } -func GetDefaultPrograms() []*program.Program { - progs := []*program.Program{ - Exit, - Fork, - Execve, - ExecveBprmCommit, - } - return progs -} - -func GetDefaultMaps() []*program.Map { - maps := []*program.Map{ - ExecveMap, - ExecveJoinMap, - ExecveStats, - ExecveJoinMapStats, - ExecveTailCallsMap, - TCPMonMap, - TetragonConfMap, - StatsMap, - MatchBinariesSetMap, - ErrMetricsMap, - } - return maps - -} - func initBaseSensor() *sensors.Sensor { sensor := sensors.Sensor{ Name: basePolicy, diff --git a/pkg/sensors/base/base_linux.go b/pkg/sensors/base/base_linux.go new file mode 100644 index 00000000000..acffa9127fe --- /dev/null +++ b/pkg/sensors/base/base_linux.go @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Tetragon + +package base + +import ( + "github.com/cilium/tetragon/pkg/sensors/program" +) + +func GetDefaultPrograms() []*program.Program { + progs := []*program.Program{ + Exit, + Fork, + Execve, + ExecveBprmCommit, + } + return progs +} + +func GetDefaultMaps() []*program.Map { + maps := []*program.Map{ + ExecveMap, + ExecveJoinMap, + ExecveStats, + ExecveJoinMapStats, + ExecveTailCallsMap, + TCPMonMap, + TetragonConfMap, + StatsMap, + MatchBinariesSetMap, + ErrMetricsMap, + } + return maps + +} diff --git a/pkg/sensors/base/base_windows.go b/pkg/sensors/base/base_windows.go new file mode 100644 index 00000000000..02762902393 --- /dev/null +++ b/pkg/sensors/base/base_windows.go @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Tetragon + +package base + +import ( + "github.com/cilium/tetragon/pkg/sensors/program" +) + +var ( + CreateProcess = program.Builder( + "process_monitor.sys", + "process", + "ProcessMonitor", + "process::program", + "windows", + ).SetPolicy(basePolicy) + + ProcessRingBufMap = program.MapBuilder("process_ringbuf", CreateProcess) + ProcessPidMap = program.MapBuilder("process_map", CreateProcess) + ProcessCmdMap = program.MapBuilder("command_map", CreateProcess) +) + +func GetDefaultPrograms() []*program.Program { + progs := []*program.Program{ + CreateProcess, + } + return progs +} + +func GetDefaultMaps() []*program.Map { + maps := []*program.Map{ + ProcessRingBufMap, + ProcessCmdMap, + ProcessPidMap, + } + return maps + +} diff --git a/pkg/sensors/config/confmap/confmap.go b/pkg/sensors/config/confmap/confmap.go index 67fa9e0f3dc..455927084bf 100644 --- a/pkg/sensors/config/confmap/confmap.go +++ b/pkg/sensors/config/confmap/confmap.go @@ -11,12 +11,12 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/tetragon/pkg/cgroups" "github.com/cilium/tetragon/pkg/config" + "github.com/cilium/tetragon/pkg/constants" "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/option" "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) const ( @@ -122,7 +122,7 @@ func UpdateTgRuntimeConf(mapDir string, nspid int) error { return err } - if v.CgrpFsMagic == unix.CGROUP2_SUPER_MAGIC { + if v.CgrpFsMagic == constants.CGROUP2_SUPER_MAGIC { log.WithFields(logrus.Fields{ "confmap-update": configMapName, "deployment.mode": deployMode.String(), diff --git a/pkg/sensors/load.go b/pkg/sensors/load.go index 2eafb6c6869..1b5b884dd76 100644 --- a/pkg/sensors/load.go +++ b/pkg/sensors/load.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strings" + "github.com/cilium/tetragon/pkg/kernels" "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/option" "github.com/cilium/tetragon/pkg/sensors/program" @@ -102,6 +103,92 @@ func (s *Sensor) removeDirs() { os.Remove(filepath.Join(s.BpfDir, s.policyDir())) } +// Load loads the sensor, by loading all the BPF programs and maps. +func (s *Sensor) Load(bpfDir string) (err error) { + if s == nil { + return nil + } + + if s.Destroyed { + return fmt.Errorf("sensor %s has been previously destroyed, please recreate it before loading", s.Name) + } + + logger.GetLogger().WithField("metadata", getCachedBTFFile()).Info("BTF file: using metadata file") + if _, err = observerMinReqs(); err != nil { + return fmt.Errorf("tetragon, aborting minimum requirements not met: %w", err) + } + + var ( + loadedMaps []*program.Map + loadedProgs []*program.Program + ) + + s.createDirs(bpfDir) + defer func() { + if err != nil { + for _, m := range loadedMaps { + m.Unload(true) + } + for _, p := range loadedProgs { + unloadProgram(p, true) + } + s.removeDirs() + } + }() + + l := logger.GetLogger() + + l.WithField("name", s.Name).Info("Loading sensor") + if s.Loaded { + return fmt.Errorf("loading sensor %s failed: sensor already loaded", s.Name) + } + + _, verStr, _ := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS) + l.Infof("Loading kernel version %s", verStr) + + if err = s.FindPrograms(); err != nil { + return fmt.Errorf("tetragon, aborting could not find BPF programs: %w", err) + } + if loadedMaps, err = s.preLoadMaps(bpfDir, loadedMaps); err != nil { + return err + } + for _, p := range s.Progs { + if p.LoadState.IsLoaded() { + l.WithField("prog", p.Name).Info("BPF prog is already loaded, incrementing reference count") + p.LoadState.RefInc() + continue + } + + if err = observerLoadInstance(bpfDir, p, s.Maps); err != nil { + return err + } + p.LoadState.RefInc() + loadedProgs = append(loadedProgs, p) + l.WithField("prog", p.Name).WithField("label", p.Label).Debugf("BPF prog was loaded") + } + + // Add the *loaded* programs and maps, so they can be unloaded later + progsAdd(s.Progs) + AllMaps = append(AllMaps, s.Maps...) + + if s.PostLoadHook != nil { + if err := s.PostLoadHook(); err != nil { + logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Post load hook failed") + } + } + + // cleanup the BTF once we have loaded all sensor's program + flushKernelSpec() + + l.WithFields(logrus.Fields{ + "sensor": s.Name, + "maps": loadedMaps, + "progs": loadedProgs, + }).Infof("Loaded BPF maps and events for sensor successfully") + s.Loaded = true + return nil +} + func (s *Sensor) Unload(unpin bool) error { logger.GetLogger().Infof("Unloading sensor %s", s.Name) if !s.Loaded { diff --git a/pkg/sensors/load_linux.go b/pkg/sensors/load_linux.go index 59a00f46c5a..7dc4ceec6e4 100644 --- a/pkg/sensors/load_linux.go +++ b/pkg/sensors/load_linux.go @@ -17,97 +17,6 @@ import ( "github.com/sirupsen/logrus" ) -// Load loads the sensor, by loading all the BPF programs and maps. -func (s *Sensor) Load(bpfDir string) (err error) { - if s == nil { - return nil - } - - if s.Destroyed { - return fmt.Errorf("sensor %s has been previously destroyed, please recreate it before loading", s.Name) - } - - logger.GetLogger().WithField("metadata", cachedbtf.GetCachedBTFFile()).Info("BTF file: using metadata file") - if _, err = observerMinReqs(); err != nil { - return fmt.Errorf("tetragon, aborting minimum requirements not met: %w", err) - } - - var ( - loadedMaps []*program.Map - loadedProgs []*program.Program - ) - - s.createDirs(bpfDir) - defer func() { - if err != nil { - for _, m := range loadedMaps { - m.Unload(true) - } - for _, p := range loadedProgs { - unloadProgram(p, true) - } - s.removeDirs() - } - }() - - l := logger.GetLogger() - - l.WithField("name", s.Name).Info("Loading sensor") - if s.Loaded { - return fmt.Errorf("loading sensor %s failed: sensor already loaded", s.Name) - } - - _, verStr, _ := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS) - l.Infof("Loading kernel version %s", verStr) - - if err = s.FindPrograms(); err != nil { - return fmt.Errorf("tetragon, aborting could not find BPF programs: %w", err) - } - - for _, m := range s.Maps { - if err = s.loadMap(bpfDir, m); err != nil { - return fmt.Errorf("tetragon, aborting could not load sensor BPF maps: %w", err) - } - loadedMaps = append(loadedMaps, m) - } - - for _, p := range s.Progs { - if p.LoadState.IsLoaded() { - l.WithField("prog", p.Name).Info("BPF prog is already loaded, incrementing reference count") - p.LoadState.RefInc() - continue - } - - if err = observerLoadInstance(bpfDir, p, s.Maps); err != nil { - return err - } - p.LoadState.RefInc() - loadedProgs = append(loadedProgs, p) - l.WithField("prog", p.Name).WithField("label", p.Label).Debugf("BPF prog was loaded") - } - - // Add the *loaded* programs and maps, so they can be unloaded later - progsAdd(s.Progs) - AllMaps = append(AllMaps, s.Maps...) - - if s.PostLoadHook != nil { - if err := s.PostLoadHook(); err != nil { - logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Post load hook failed") - } - } - - // cleanup the BTF once we have loaded all sensor's program - btf.FlushKernelSpec() - - l.WithFields(logrus.Fields{ - "sensor": s.Name, - "maps": loadedMaps, - "progs": loadedProgs, - }).Infof("Loaded BPF maps and events for sensor successfully") - s.Loaded = true - return nil -} - func (s *Sensor) setMapPinPath(m *program.Map) { policy := s.policyDir() switch m.Type { @@ -122,6 +31,16 @@ func (s *Sensor) setMapPinPath(m *program.Map) { } } +func (s *Sensor) preLoadMaps(bpfDir string, loadedMaps []*program.Map) ([]*program.Map, error) { + for _, m := range s.Maps { + if err := s.loadMap(bpfDir, m); err != nil { + return loadedMaps, fmt.Errorf("tetragon, aborting could not load sensor BPF maps: %w", err) + } + loadedMaps = append(loadedMaps, m) + } + return loadedMaps, nil +} + // loadMap loads BPF map in the sensor. func (s *Sensor) loadMap(bpfDir string, m *program.Map) error { l := logger.GetLogger() @@ -282,3 +201,11 @@ func observerMinReqs() (bool, error) { } return true, nil } + +func flushKernelSpec() { + btf.FlushKernelSpec() +} + +func getCachedBTFFile() string { + return cachedbtf.GetCachedBTFFile() +} diff --git a/pkg/sensors/load_windows.go b/pkg/sensors/load_windows.go index 863827a28ee..b3e016a623e 100644 --- a/pkg/sensors/load_windows.go +++ b/pkg/sensors/load_windows.go @@ -14,84 +14,6 @@ import ( "github.com/sirupsen/logrus" ) -// Load loads the sensor, by loading all the BPF programs and maps. -func (s *Sensor) Load(bpfDir string) (err error) { - if s == nil { - return nil - } - - if s.Destroyed { - return fmt.Errorf("sensor %s has been previously destroyed, please recreate it before loading", s.Name) - } - if _, err = observerMinReqs(); err != nil { - return fmt.Errorf("tetragon, aborting minimum requirements not met: %w", err) - } - - var ( - loadedMaps []*program.Map - loadedProgs []*program.Program - ) - - s.createDirs(bpfDir) - defer func() { - if err != nil { - for _, m := range loadedMaps { - m.Unload(true) - } - for _, p := range loadedProgs { - unloadProgram(p, true) - } - s.removeDirs() - } - }() - - l := logger.GetLogger() - - l.WithField("name", s.Name).Info("Loading sensor") - if s.Loaded { - return fmt.Errorf("loading sensor %s failed: sensor already loaded", s.Name) - } - - if err = s.FindPrograms(); err != nil { - return fmt.Errorf("tetragon, aborting could not find BPF programs: %w", err) - } - // Comparing with Linux, why are maps not loaded here ? - // In windows, we load collection directly and do not load specs. - // The collection loads maps for us. - for _, p := range s.Progs { - if p.LoadState.IsLoaded() { - l.WithField("prog", p.Name).Info("BPF prog is already loaded, incrementing reference count") - p.LoadState.RefInc() - continue - } - - if err = observerLoadInstance(bpfDir, p, s.Maps); err != nil { - return err - } - p.LoadState.RefInc() - loadedProgs = append(loadedProgs, p) - l.WithField("prog", p.Name).WithField("label", p.Label).Debugf("BPF prog was loaded") - } - - // Add the *loaded* programs and maps, so they can be unloaded later - progsAdd(s.Progs) - AllMaps = append(AllMaps, s.Maps...) - - if s.PostLoadHook != nil { - if err := s.PostLoadHook(); err != nil { - logger.GetLogger().WithError(err).WithField("sensor", s.Name).Warn("Post load hook failed") - } - } - - l.WithFields(logrus.Fields{ - "sensor": s.Name, - "maps": loadedMaps, - "progs": loadedProgs, - }).Infof("Loaded BPF maps and events for sensor successfully") - s.Loaded = true - return nil -} - func observerLoadInstance(bpfDir string, load *program.Program, maps []*program.Map) error { version, _, err := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS) if err != nil { @@ -129,3 +51,15 @@ func loadInstance(bpfDir string, load *program.Program, maps []*program.Map, ver func observerMinReqs() (bool, error) { return true, nil } + +func flushKernelSpec() { + return +} + +func (s *Sensor) preLoadMaps(bpfDir string, loadedMaps []*program.Map) ([]*program.Map, error) { + return nil, nil +} + +func getCachedBTFFile() string { + return "" +} diff --git a/pkg/sensors/program/loader.go b/pkg/sensors/program/loader.go new file mode 100644 index 00000000000..131b0dab6f4 --- /dev/null +++ b/pkg/sensors/program/loader.go @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Tetragon +package program + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/cilium/ebpf" + "github.com/cilium/tetragon/pkg/sensors/unloader" +) + +// AttachFunc is the type for the various attachment functions. The function is +// given the program and it's up to it to close it. +type AttachFunc func(*ebpf.Collection, *ebpf.CollectionSpec, *ebpf.Program, *ebpf.ProgramSpec) (unloader.Unloader, error) + +type OpenFunc func(*ebpf.CollectionSpec) error + +type LoadOpts struct { + Attach AttachFunc + Open OpenFunc + Maps []*Map +} + +func linkPinPath(bpfDir string, load *Program, extra ...string) string { + pinPath := filepath.Join(bpfDir, load.PinPath, "link") + if len(extra) != 0 { + pinPath = pinPath + "_" + strings.Join(extra, "_") + } + return pinPath +} + +func RawAttach(targetFD int) AttachFunc { + return RawAttachWithFlags(targetFD, 0) +} + +func NoAttach() AttachFunc { + return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, + prog *ebpf.Program, _ *ebpf.ProgramSpec) (unloader.Unloader, error) { + return unloader.ChainUnloader{ + unloader.ProgUnloader{ + Prog: prog, + }, + }, nil + } +} + +// MissingConstantsError is returned by [rewriteConstants]. +type MissingConstantsError struct { + // The constants missing from .rodata. + Constants []string +} + +func (m *MissingConstantsError) Error() string { + return fmt.Sprintf("some constants are missing from .rodata: %s", strings.Join(m.Constants, ", ")) +} + +// The loadProgram loads and attach bpf object @load. It is expected that user +// provides @loadOpts with mandatory attach function and optional open function. +// +// The load process is roughly as follows: +// +// - load object | ebpf.LoadCollectionSpec +// - open callback | loadOpts.open(spec) +// - open refferenced maps | +// - creates collection | ebpf.NewCollectionWithOptions(spec, opts) +// - install tail calls | loadOpts.ci +// - load maps with values | +// - pin main program | +// - attach callback | loadOpts.attach(coll, spec, prog, progSpec) +// - print loaded progs/maps | if KeepCollection == true +// +// The @loadOpts.open callback can be used to customize ebpf.CollectionSpec +// before it's loaded into kernel (like disable/enable programs). +// +// The @loadOpts.attach callback is used to actually attach main object program +// to desired function/symbol/whatever.. +// +// The @loadOpts.ci defines specific installation of tailcalls in object. + +func loadProgram( + bpfDir string, + load *Program, + opts *LoadOpts, + verbose int, +) error { + + // Attach function is mandatory + if opts.Attach == nil { + return fmt.Errorf("attach function is not provided") + } + + lc, err := doLoadProgram(bpfDir, load, opts, verbose) + if err != nil { + return err + } + if KeepCollection { + load.LC = filterLoadedCollection(lc) + printLoadedCollection(load.Name, load.LC) + } + return nil +} + +func LoadProgram( + bpfDir string, + load *Program, + maps []*Map, + attach AttachFunc, + verbose int, +) error { + return loadProgram(bpfDir, load, &LoadOpts{Attach: attach, Maps: maps}, verbose) +} + +func LoadProgramOpts( + bpfDir string, + load *Program, + opts *LoadOpts, + verbose int, +) error { + return loadProgram(bpfDir, load, opts, verbose) +} diff --git a/pkg/sensors/program/loader_linux.go b/pkg/sensors/program/loader_linux.go index 4ce70f782a6..71382578f1f 100644 --- a/pkg/sensors/program/loader_linux.go +++ b/pkg/sensors/program/loader_linux.go @@ -19,26 +19,6 @@ import ( "github.com/cilium/tetragon/pkg/sensors/unloader" ) -// AttachFunc is the type for the various attachment functions. The function is -// given the program and it's up to it to close it. -type AttachFunc func(*ebpf.Collection, *ebpf.CollectionSpec, *ebpf.Program, *ebpf.ProgramSpec) (unloader.Unloader, error) - -type OpenFunc func(*ebpf.CollectionSpec) error - -type LoadOpts struct { - Attach AttachFunc - Open OpenFunc - Maps []*Map -} - -func linkPinPath(bpfDir string, load *Program, extra ...string) string { - pinPath := filepath.Join(bpfDir, load.PinPath, "link") - if len(extra) != 0 { - pinPath = pinPath + "_" + strings.Join(extra, "_") - } - return pinPath -} - func linkPin(lnk link.Link, bpfDir string, load *Program, extra ...string) error { // pinned link is not supported if !bpf.HasLinkPin() { @@ -54,10 +34,6 @@ func linkPin(lnk link.Link, bpfDir string, load *Program, extra ...string) error return nil } -func RawAttach(targetFD int) AttachFunc { - return RawAttachWithFlags(targetFD, 0) -} - func RawAttachWithFlags(targetFD int, flags uint32) AttachFunc { return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { @@ -379,17 +355,6 @@ func MultiUprobeAttach(load *Program) AttachFunc { } } -func NoAttach() AttachFunc { - return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, - prog *ebpf.Program, _ *ebpf.ProgramSpec) (unloader.Unloader, error) { - return unloader.ChainUnloader{ - unloader.ProgUnloader{ - Prog: prog, - }, - }, nil - } -} - func TracingAttach(load *Program, bpfDir string) AttachFunc { return func(_ *ebpf.Collection, _ *ebpf.CollectionSpec, prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { @@ -747,16 +712,6 @@ func installTailCalls(bpfDir string, spec *ebpf.CollectionSpec, coll *ebpf.Colle return nil } -// MissingConstantsError is returned by [rewriteConstants]. -type MissingConstantsError struct { - // The constants missing from .rodata. - Constants []string -} - -func (m *MissingConstantsError) Error() string { - return fmt.Sprintf("some constants are missing from .rodata: %s", strings.Join(m.Constants, ", ")) -} - func rewriteConstants(spec *ebpf.CollectionSpec, consts map[string]interface{}) error { var missing []string @@ -1061,68 +1016,3 @@ func doLoadProgram( } return nil, nil } - -// The loadProgram loads and attach bpf object @load. It is expected that user -// provides @loadOpts with mandatory attach function and optional open function. -// -// The load process is roughly as follows: -// -// - load object | ebpf.LoadCollectionSpec -// - open callback | loadOpts.open(spec) -// - open refferenced maps | -// - creates collection | ebpf.NewCollectionWithOptions(spec, opts) -// - install tail calls | loadOpts.ci -// - load maps with values | -// - pin main program | -// - attach callback | loadOpts.attach(coll, spec, prog, progSpec) -// - print loaded progs/maps | if KeepCollection == true -// -// The @loadOpts.open callback can be used to customize ebpf.CollectionSpec -// before it's loaded into kernel (like disable/enable programs). -// -// The @loadOpts.attach callback is used to actually attach main object program -// to desired function/symbol/whatever.. -// -// The @loadOpts.ci defines specific installation of tailcalls in object. - -func loadProgram( - bpfDir string, - load *Program, - opts *LoadOpts, - verbose int, -) error { - - // Attach function is mandatory - if opts.Attach == nil { - return fmt.Errorf("attach function is not provided") - } - - lc, err := doLoadProgram(bpfDir, load, opts, verbose) - if err != nil { - return err - } - if KeepCollection { - load.LC = filterLoadedCollection(lc) - printLoadedCollection(load.Name, load.LC) - } - return nil -} - -func LoadProgram( - bpfDir string, - load *Program, - maps []*Map, - attach AttachFunc, - verbose int, -) error { - return loadProgram(bpfDir, load, &LoadOpts{Attach: attach, Maps: maps}, verbose) -} - -func LoadProgramOpts( - bpfDir string, - load *Program, - opts *LoadOpts, - verbose int, -) error { - return loadProgram(bpfDir, load, opts, verbose) -} diff --git a/pkg/sensors/program/loader_windows.go b/pkg/sensors/program/loader_windows.go new file mode 100644 index 00000000000..612ec144b80 --- /dev/null +++ b/pkg/sensors/program/loader_windows.go @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of Tetragon + +package program + +import ( + "errors" + "fmt" + "os" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/link" + "github.com/cilium/tetragon/pkg/bpf" + "github.com/cilium/tetragon/pkg/constants" + "github.com/cilium/tetragon/pkg/logger" + "github.com/cilium/tetragon/pkg/sensors/unloader" + "golang.org/x/sys/windows" +) + +var ( + notSupportedWinErr = errors.New("not supported on windows") + programTypeProcessGUID = makeGUID(0x22ea7b37, 0x1043, 0x4d0d, [8]byte{0xb6, 0x0d, 0xca, 0xfa, 0x1c, 0x7b, 0x63, 0x8e}) + attachTypeProcessGUID = makeGUID(0x66e20687, 0x9805, 0x4458, [8]byte{0xa0, 0xdb, 0x38, 0xe2, 0x20, 0xd3, 0x16, 0x85}) +) + +func makeGUID(data1 uint32, data2 uint16, data3 uint16, data4 [8]byte) windows.GUID { + return windows.GUID{Data1: data1, Data2: data2, Data3: data3, Data4: data4} +} + +func winAttachStub(_ *ebpf.Collection, _ *ebpf.CollectionSpec, + prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { + + return nil, notSupportedWinErr +} + +func RawAttachWithFlags(targetFD int, flags uint32) AttachFunc { + return winAttachStub +} + +func windowsAttach(load *Program, prog *ebpf.Program, spec *ebpf.ProgramSpec, + symbol string, bpfDir string, extra ...string) (unloader.Unloader, error) { + + attachType, err := ebpf.WindowsAttachTypeForGUID(attachTypeProcessGUID.String()) + if err != nil { + return nil, err + } + + link, err := link.AttachRawLink(link.RawLinkOptions{ + Program: prog, + Attach: attachType, + }) + if err != nil { + return nil, err + } + return unloader.ChainUnloader{ + unloader.ProgUnloader{ + Prog: prog, + }, + unloader.LinkUnloader{ + Link: link, + }, + }, nil + +} + +func WindowsAttach(load *Program, bpfDir string) AttachFunc { + return func(coll *ebpf.Collection, collSpec *ebpf.CollectionSpec, + prog *ebpf.Program, spec *ebpf.ProgramSpec) (unloader.Unloader, error) { + + return windowsAttach(load, prog, spec, load.Attach, bpfDir) + } +} + +func LoadWindowsProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { + opts := &LoadOpts{ + Attach: WindowsAttach(load, bpfDir), + } + return loadProgram(bpfDir, load, opts, verbose) +} + +func LoadTracepointProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { + return constants.ErrWindowsNotSupported +} + +func LoadKprobeProgramAttachMany(bpfDir string, load *Program, syms []string, maps []*Map, verbose int) error { + return constants.ErrWindowsNotSupported +} + +func LoadMultiKprobeProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { + return constants.ErrWindowsNotSupported +} + +func LoadFmodRetProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int) error { + return constants.ErrWindowsNotSupported +} + +func doLoadProgram( + bpfDir string, + load *Program, + loadOpts *LoadOpts, + verbose int, +) (*LoadedCollection, error) { + + coll, err := ebpf.LoadCollection(load.Name) + if err != nil { + logger.GetLogger().WithError(err).WithField("Error ", err.Error()).Warn(" Failed to load Native Windows Collection ") + return nil, err + } + bpf.SetExecCollection(coll) + + collMaps := map[ebpf.MapID]*ebpf.Map{} + // we need a mapping by ID + for _, m := range coll.Maps { + + info, err := m.Info() + if err != nil { + logger.GetLogger().WithError(err).WithField("map", m.String()).Warn("failed to retrieve BPF map info") + continue + } + id, available := info.ID() + if !available { + logger.GetLogger().WithField("map", m.String()).Warn("failed to retrieve BPF map ID, you might be running <4.13") + continue + } + collMaps[id] = m + + // In Windows, this is where we pin maps. + // ToDo: Pinned maps do not get unpinned when tetragon stops, + // This is to be uncommented once that issue is fixed. + // We do not need pinned maps for events + // if _, exist := load.PinMap[info.Name]; exist { + // pinPath := load.Attach + "::" + info.Name + // err = m.Pin(pinPath) + // if err != nil { + // logger.GetLogger().WithField("map", m.String()).Warn("failed to pin map") + // } else { + // logger.GetLogger().WithField("map tp path ", pinPath).Info("Successfully pinned") + // } + // } + } + + load.LoadedMapsInfo = map[int]bpf.ExtendedMapInfo{} + + var prog *ebpf.Program + for _, p := range coll.Programs { + + i, err := p.Info() + if i.Name == load.Label { + prog = p + } + if err != nil { + logger.GetLogger().WithError(err).WithField("program", p.String()).Warn("failed to retrieve BPF program info, you might be running <4.10") + break + } + ids, available := i.MapIDs() + if !available { + logger.GetLogger().WithField("program", p.String()).Warn("failed to retrieve BPF program map IDs, you might be running <4.15") + break + } + for _, id := range ids { + if _, exist := load.LoadedMapsInfo[int(id)]; exist { + continue + } + xInfo, err := bpf.ExtendedInfoFromMap(collMaps[id]) + if err != nil { + logger.GetLogger().WithError(err).WithField("mapID", id).Warn("failed to retrieve extended map info") + break + } + load.LoadedMapsInfo[int(id)] = xInfo + } + } + + for _, mapLoad := range load.MapLoad { + pinPath := "" + if pm, ok := load.PinMap[mapLoad.Name]; ok { + pinPath = pm.PinPath + } + if m, ok := coll.Maps[mapLoad.Name]; ok { + if err := mapLoad.Load(m, pinPath, mapLoad.Index); err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("populating map failed as map '%s' was not found from collection", mapLoad.Name) + } + } + if prog == nil { + return nil, fmt.Errorf("program for section '%s' not found", load.Label) + } + + pinPath := load.PinPath + if _, err := os.Stat(pinPath); err == nil { + logger.GetLogger().Debugf("Pin file '%s' already exists, repinning", load.PinPath) + if err := os.Remove(pinPath); err != nil { + logger.GetLogger().Warnf("Unpinning '%s' failed: %s", pinPath, err) + } + } + + // Clone the program so it can be passed on to attach function and unloader after + // we close the collection. + prog, err = prog.Clone() + if err != nil { + return nil, fmt.Errorf("failed to clone program '%s': %w", load.Label, err) + } + + if err := prog.Pin(pinPath); err != nil { + return nil, fmt.Errorf("pinning '%s' to '%s' failed: %w", load.Label, pinPath, err) + } + + load.unloader, err = loadOpts.Attach(coll, nil, prog, nil) + if err != nil { + if err := prog.Unpin(); err != nil { + logger.GetLogger().Warnf("Unpinning '%s' failed: %w", pinPath, err) + } + return nil, err + } + + load.Prog = prog + + // in KernelTypes, we use a non-standard BTF which is possibly annotated with symbols + // from kernel modules. At this point we don't need that anymore, so we can release + // the memory from it. + load.KernelTypes = nil + + // Copy the loaded collection before it's destroyed + if KeepCollection { + return copyLoadedCollection(coll) + } + return nil, nil +}