diff --git a/go.mod b/go.mod index 75d148e4ab1..a5c87ddcf00 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ go 1.22.0 require ( github.com/bombsimon/logrusr/v4 v4.1.0 github.com/cilium/cilium v1.15.0 - github.com/cilium/ebpf v0.12.4-0.20231215112452-00c0cb05d35c + github.com/cilium/ebpf v0.12.4-0.20240214170503-b0728bcadcd9 github.com/cilium/little-vm-helper v0.0.16 github.com/cilium/lumberjack/v2 v2.3.0 github.com/cilium/tetragon/api v0.0.0-00010101000000-000000000000 diff --git a/go.sum b/go.sum index 410475d8934..9d2bb83b3d7 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/cilium/controller-tools v0.8.0-1 h1:D5xhwSUZZceaKAacHOyfcpUMgLbs2TGeJ github.com/cilium/controller-tools v0.8.0-1/go.mod h1:qE2DXhVOiEq5ijmINcFbqi9GZrrUjzB1TuJU0xa6eoY= github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3 h1:3PErIjIq4DlOwNsQNPcILFzbGnxPuKuqJsHEFpiwstM= github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3/go.mod h1:/7LC2GOgyXJ7maupZlaVIumYQiGPIgllSf6mA9sg6RU= -github.com/cilium/ebpf v0.12.4-0.20231215112452-00c0cb05d35c h1:A4GKNW2FJKFAwvkJvFVnxyVn+9LGaUPz5LY6r8wZAh0= -github.com/cilium/ebpf v0.12.4-0.20231215112452-00c0cb05d35c/go.mod h1:9BszLnmZR7oucpa/kBbVVf1ts3BoUSpltcnNp1hQkVw= +github.com/cilium/ebpf v0.12.4-0.20240214170503-b0728bcadcd9 h1:3nfQDPNKGu4bHpyMGE4v0+ZJu8ZuBKJpWxJdkgdaxpQ= +github.com/cilium/ebpf v0.12.4-0.20240214170503-b0728bcadcd9/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= github.com/cilium/little-vm-helper v0.0.16 h1:ebw5hT4RVz1oqYWNJgQbK3TskyPQ0DgsAmWLBjSghLg= github.com/cilium/little-vm-helper v0.0.16/go.mod h1:BBnQ5i6fWBpO9L9BbZwMzVqPGRC8X2CN0BIH5gYav8A= github.com/cilium/lumberjack/v2 v2.3.0 h1:IhVJMvPpqDYmQzC0KDhAoy7KlaRsyOsZnT97Nsa3u0o= diff --git a/vendor/github.com/cilium/ebpf/Makefile b/vendor/github.com/cilium/ebpf/Makefile index 0a1201076d7..eb532b2fd14 100644 --- a/vendor/github.com/cilium/ebpf/Makefile +++ b/vendor/github.com/cilium/ebpf/Makefile @@ -84,7 +84,8 @@ all: format $(addsuffix -el.elf,$(TARGETS)) $(addsuffix -eb.elf,$(TARGETS)) gene ln -srf testdata/loader-$(CLANG)-eb.elf testdata/loader-eb.elf generate: - go generate ./... + go generate -run "internal/cmd/gentypes" ./... + go generate -skip "internal/cmd/gentypes" ./... testdata/loader-%-el.elf: testdata/loader.c $* $(CFLAGS) -target bpfel -c $< -o $@ @@ -103,14 +104,7 @@ testdata/loader-%-eb.elf: testdata/loader.c $(STRIP) -g $@ .PHONY: update-kernel-deps -update-kernel-deps: KERNEL_VERSION?=6.6 +update-kernel-deps: export KERNEL_VERSION?=6.7 update-kernel-deps: - $(eval TMP := $(shell mktemp -d)) - curl -fL https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/tools/lib/bpf/libbpf.c?h=v$(KERNEL_VERSION) -o "$(TMP)/libbpf.c" - "$(CURDIR)/internal/cmd/gensections.awk" "$(TMP)/libbpf.c" | gofmt > "$(CURDIR)/elf_sections.go" - curl -fL "$(CI_KERNEL_URL)/linux-$(KERNEL_VERSION)-amd64.tgz" -o "$(TMP)/linux.tgz" - tar xvf "$(TMP)/linux.tgz" -C "$(TMP)" --strip-components=2 ./boot/vmlinuz ./lib/modules - /lib/modules/$(shell uname -r)/build/scripts/extract-vmlinux "$(TMP)/vmlinuz" > "$(TMP)/vmlinux" - $(OBJCOPY) --dump-section .BTF=/dev/stdout "$(TMP)/vmlinux" /dev/null | gzip > "btf/testdata/vmlinux.btf.gz" - find "$(TMP)/modules" -type f -name bpf_testmod.ko -exec $(OBJCOPY) --dump-section .BTF="btf/testdata/btf_testmod.btf" {} /dev/null \; - $(RM) -r "$(TMP)" + ./testdata/sh/update-kernel-deps.sh + $(MAKE) container-all diff --git a/vendor/github.com/cilium/ebpf/btf/btf.go b/vendor/github.com/cilium/ebpf/btf/btf.go index 80f64d78aee..6a3e53d678d 100644 --- a/vendor/github.com/cilium/ebpf/btf/btf.go +++ b/vendor/github.com/cilium/ebpf/btf/btf.go @@ -29,9 +29,8 @@ var ( // ID represents the unique ID of a BTF object. type ID = sys.BTFID -// Spec allows querying a set of Types and loading the set into the -// kernel. -type Spec struct { +// immutableTypes is a set of types which musn't be changed. +type immutableTypes struct { // All types contained by the spec, not including types from the base in // case the spec was parsed from split BTF. types []Type @@ -44,13 +43,132 @@ type Spec struct { // Types indexed by essential name. // Includes all struct flavors and types with the same name. - namedTypes map[essentialName][]Type + namedTypes map[essentialName][]TypeID + + // Byte order of the types. This affects things like struct member order + // when using bitfields. + byteOrder binary.ByteOrder +} + +func (s *immutableTypes) typeByID(id TypeID) (Type, bool) { + if id < s.firstTypeID { + return nil, false + } + + index := int(id - s.firstTypeID) + if index >= len(s.types) { + return nil, false + } + + return s.types[index], true +} + +// mutableTypes is a set of types which may be changed. +type mutableTypes struct { + imm immutableTypes + copies map[Type]Type // map[orig]copy + copiedTypeIDs map[Type]TypeID //map[copy]origID +} + +// add a type to the set of mutable types. +// +// Copies type and all of its children once. Repeated calls with the same type +// do not copy again. +func (mt *mutableTypes) add(typ Type, typeIDs map[Type]TypeID) Type { + return modifyGraphPreorder(typ, func(t Type) (Type, bool) { + cpy, ok := mt.copies[t] + if ok { + // This has been copied previously, no need to continue. + return cpy, false + } + + cpy = t.copy() + mt.copies[t] = cpy + + if id, ok := typeIDs[t]; ok { + mt.copiedTypeIDs[cpy] = id + } + + // This is a new copy, keep copying children. + return cpy, true + }) +} + +// copy a set of mutable types. +func (mt *mutableTypes) copy() mutableTypes { + mtCopy := mutableTypes{ + mt.imm, + make(map[Type]Type, len(mt.copies)), + make(map[Type]TypeID, len(mt.copiedTypeIDs)), + } + + copies := make(map[Type]Type, len(mt.copies)) + for orig, copy := range mt.copies { + // NB: We make a copy of copy, not orig, so that changes to mutable types + // are preserved. + copyOfCopy := mtCopy.add(copy, mt.copiedTypeIDs) + copies[orig] = copyOfCopy + } + + // mtCopy.copies is currently map[copy]copyOfCopy, replace it with + // map[orig]copyOfCopy. + mtCopy.copies = copies + return mtCopy +} + +func (mt *mutableTypes) typeID(typ Type) (TypeID, error) { + if _, ok := typ.(*Void); ok { + // Equality is weird for void, since it is a zero sized type. + return 0, nil + } + + id, ok := mt.copiedTypeIDs[typ] + if !ok { + return 0, fmt.Errorf("no ID for type %s: %w", typ, ErrNotFound) + } + + return id, nil +} + +func (mt *mutableTypes) typeByID(id TypeID) (Type, bool) { + immT, ok := mt.imm.typeByID(id) + if !ok { + return nil, false + } + + return mt.add(immT, mt.imm.typeIDs), true +} + +func (mt *mutableTypes) anyTypesByName(name string) ([]Type, error) { + immTypes := mt.imm.namedTypes[newEssentialName(name)] + if len(immTypes) == 0 { + return nil, fmt.Errorf("type name %s: %w", name, ErrNotFound) + } + + // Return a copy to prevent changes to namedTypes. + result := make([]Type, 0, len(immTypes)) + for _, id := range immTypes { + immT, ok := mt.imm.typeByID(id) + if !ok { + return nil, fmt.Errorf("no type with ID %d", id) + } + + // Match against the full name, not just the essential one + // in case the type being looked up is a struct flavor. + if immT.TypeName() == name { + result = append(result, mt.add(immT, mt.imm.typeIDs)) + } + } + return result, nil +} + +// Spec allows querying a set of Types and loading the set into the +// kernel. +type Spec struct { + mutableTypes // String table from ELF. strings *stringTable - - // Byte order of the ELF we decoded the spec from, may be nil. - byteOrder binary.ByteOrder } // LoadSpec opens file and calls LoadSpecFromReader on it. @@ -181,7 +299,7 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) { return nil, err } - err = fixupDatasec(spec.types, sectionSizes, offsets) + err = fixupDatasec(spec.imm.types, sectionSizes, offsets) if err != nil { return nil, err } @@ -197,7 +315,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error ) if base != nil { - if base.firstTypeID != 0 { + if base.imm.firstTypeID != 0 { return nil, fmt.Errorf("can't use split BTF as base") } @@ -217,16 +335,22 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error typeIDs, typesByName := indexTypes(types, firstTypeID) return &Spec{ - namedTypes: typesByName, - typeIDs: typeIDs, - types: types, - firstTypeID: firstTypeID, - strings: rawStrings, - byteOrder: bo, + mutableTypes{ + immutableTypes{ + types, + typeIDs, + firstTypeID, + typesByName, + bo, + }, + make(map[Type]Type), + make(map[Type]TypeID), + }, + rawStrings, }, nil } -func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentialName][]Type) { +func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentialName][]TypeID) { namedTypes := 0 for _, typ := range types { if typ.TypeName() != "" { @@ -238,13 +362,15 @@ func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentia } typeIDs := make(map[Type]TypeID, len(types)) - typesByName := make(map[essentialName][]Type, namedTypes) + typesByName := make(map[essentialName][]TypeID, namedTypes) for i, typ := range types { + id := firstTypeID + TypeID(i) + typeIDs[typ] = id + if name := newEssentialName(typ.TypeName()); name != "" { - typesByName[name] = append(typesByName[name], typ) + typesByName[name] = append(typesByName[name], id) } - typeIDs[typ] = firstTypeID + TypeID(i) } return typeIDs, typesByName @@ -492,17 +618,9 @@ func fixupDatasecLayout(ds *Datasec) error { // Copy creates a copy of Spec. func (s *Spec) Copy() *Spec { - types := copyTypes(s.types, nil) - typeIDs, typesByName := indexTypes(types, s.firstTypeID) - - // NB: Other parts of spec are not copied since they are immutable. return &Spec{ - types, - typeIDs, - s.firstTypeID, - typesByName, + s.mutableTypes.copy(), s.strings, - s.byteOrder, } } @@ -519,8 +637,8 @@ func (sw sliceWriter) Write(p []byte) (int, error) { // nextTypeID returns the next unallocated type ID or an error if there are no // more type IDs. func (s *Spec) nextTypeID() (TypeID, error) { - id := s.firstTypeID + TypeID(len(s.types)) - if id < s.firstTypeID { + id := s.imm.firstTypeID + TypeID(len(s.imm.types)) + if id < s.imm.firstTypeID { return 0, fmt.Errorf("no more type IDs") } return id, nil @@ -531,33 +649,19 @@ func (s *Spec) nextTypeID() (TypeID, error) { // Returns an error wrapping ErrNotFound if a Type with the given ID // does not exist in the Spec. func (s *Spec) TypeByID(id TypeID) (Type, error) { - if id < s.firstTypeID { - return nil, fmt.Errorf("look up type with ID %d (first ID is %d): %w", id, s.firstTypeID, ErrNotFound) - } - - index := int(id - s.firstTypeID) - if index >= len(s.types) { - return nil, fmt.Errorf("look up type with ID %d: %w", id, ErrNotFound) + typ, ok := s.typeByID(id) + if !ok { + return nil, fmt.Errorf("look up type with ID %d (first ID is %d): %w", id, s.imm.firstTypeID, ErrNotFound) } - return s.types[index], nil + return typ, nil } // TypeID returns the ID for a given Type. // // Returns an error wrapping ErrNoFound if the type isn't part of the Spec. func (s *Spec) TypeID(typ Type) (TypeID, error) { - if _, ok := typ.(*Void); ok { - // Equality is weird for void, since it is a zero sized type. - return 0, nil - } - - id, ok := s.typeIDs[typ] - if !ok { - return 0, fmt.Errorf("no ID for type %s: %w", typ, ErrNotFound) - } - - return id, nil + return s.mutableTypes.typeID(typ) } // AnyTypesByName returns a list of BTF Types with the given name. @@ -568,21 +672,7 @@ func (s *Spec) TypeID(typ Type) (TypeID, error) { // // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec. func (s *Spec) AnyTypesByName(name string) ([]Type, error) { - types := s.namedTypes[newEssentialName(name)] - if len(types) == 0 { - return nil, fmt.Errorf("type name %s: %w", name, ErrNotFound) - } - - // Return a copy to prevent changes to namedTypes. - result := make([]Type, 0, len(types)) - for _, t := range types { - // Match against the full name, not just the essential one - // in case the type being looked up is a struct flavor. - if t.TypeName() == name { - result = append(result, t) - } - } - return result, nil + return s.mutableTypes.anyTypesByName(name) } // AnyTypeByName returns a Type with the given name. @@ -671,26 +761,27 @@ func LoadSplitSpecFromReader(r io.ReaderAt, base *Spec) (*Spec, error) { // TypesIterator iterates over types of a given spec. type TypesIterator struct { - types []Type - index int + spec *Spec + id TypeID + done bool // The last visited type in the spec. Type Type } // Iterate returns the types iterator. func (s *Spec) Iterate() *TypesIterator { - // We share the backing array of types with the Spec. This is safe since - // we don't allow deletion or shuffling of types. - return &TypesIterator{types: s.types, index: 0} + return &TypesIterator{spec: s, id: s.imm.firstTypeID} } // Next returns true as long as there are any remaining types. func (iter *TypesIterator) Next() bool { - if len(iter.types) <= iter.index { + if iter.done { return false } - iter.Type = iter.types[iter.index] - iter.index++ - return true + var ok bool + iter.Type, ok = iter.spec.typeByID(iter.id) + iter.id++ + iter.done = !ok + return !iter.done } diff --git a/vendor/github.com/cilium/ebpf/btf/core.go b/vendor/github.com/cilium/ebpf/btf/core.go index 720309a1bb6..724fae4b8c2 100644 --- a/vendor/github.com/cilium/ebpf/btf/core.go +++ b/vendor/github.com/cilium/ebpf/btf/core.go @@ -178,8 +178,8 @@ func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder, re } } - if bo != target.byteOrder { - return nil, fmt.Errorf("can't relocate %s against %s", bo, target.byteOrder) + if bo != target.imm.byteOrder { + return nil, fmt.Errorf("can't relocate %s against %s", bo, target.imm.byteOrder) } type reloGroup struct { @@ -227,7 +227,7 @@ func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder, re return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported) } - targets := target.namedTypes[newEssentialName(localTypeName)] + targets := target.imm.namedTypes[newEssentialName(localTypeName)] fixups, err := coreCalculateFixups(group.relos, target, targets, bo) if err != nil { return nil, fmt.Errorf("relocate %s: %w", localType, err) @@ -251,13 +251,13 @@ var errIncompatibleTypes = errors.New("incompatible types") // // The best target is determined by scoring: the less poisoning we have to do // the better the target is. -func coreCalculateFixups(relos []*CORERelocation, targetSpec *Spec, targets []Type, bo binary.ByteOrder) ([]COREFixup, error) { +func coreCalculateFixups(relos []*CORERelocation, targetSpec *Spec, targets []TypeID, bo binary.ByteOrder) ([]COREFixup, error) { bestScore := len(relos) var bestFixups []COREFixup - for _, target := range targets { - targetID, err := targetSpec.TypeID(target) + for _, targetID := range targets { + target, err := targetSpec.TypeByID(targetID) if err != nil { - return nil, fmt.Errorf("target type ID: %w", err) + return nil, fmt.Errorf("look up target: %w", err) } score := 0 // lower is better diff --git a/vendor/github.com/cilium/ebpf/btf/marshal.go b/vendor/github.com/cilium/ebpf/btf/marshal.go index cdaf08a6c03..744c84c4c0d 100644 --- a/vendor/github.com/cilium/ebpf/btf/marshal.go +++ b/vendor/github.com/cilium/ebpf/btf/marshal.go @@ -6,11 +6,10 @@ import ( "errors" "fmt" "math" + "slices" "sync" "github.com/cilium/ebpf/internal" - - "golang.org/x/exp/slices" ) type MarshalOptions struct { diff --git a/vendor/github.com/cilium/ebpf/btf/strings.go b/vendor/github.com/cilium/ebpf/btf/strings.go index 114d250018b..7c31461c306 100644 --- a/vendor/github.com/cilium/ebpf/btf/strings.go +++ b/vendor/github.com/cilium/ebpf/btf/strings.go @@ -6,10 +6,9 @@ import ( "errors" "fmt" "io" + "maps" + "slices" "strings" - - "golang.org/x/exp/maps" - "golang.org/x/exp/slices" ) type stringTable struct { diff --git a/vendor/github.com/cilium/ebpf/btf/traversal.go b/vendor/github.com/cilium/ebpf/btf/traversal.go index a3a9dec940a..5a7387b0638 100644 --- a/vendor/github.com/cilium/ebpf/btf/traversal.go +++ b/vendor/github.com/cilium/ebpf/btf/traversal.go @@ -87,6 +87,43 @@ func (po *postorderIterator) Next() bool { return po.Type != nil } +// modifyGraphPreorder allows modifying every Type in a graph. +// +// fn is invoked in preorder for every unique Type in a graph. See [Type] for the definition +// of equality. Every occurrence of node is substituted with its replacement. +// +// If cont is true, fn is invoked for every child of replacement. Otherwise +// traversal stops. +// +// Returns the substitution of the root node. +func modifyGraphPreorder(root Type, fn func(node Type) (replacement Type, cont bool)) Type { + sub, cont := fn(root) + replacements := map[Type]Type{root: sub} + + // This is a preorder traversal. + var walk func(*Type) + walk = func(node *Type) { + sub, visited := replacements[*node] + if visited { + *node = sub + return + } + + sub, cont := fn(*node) + replacements[*node] = sub + *node = sub + + if cont { + walkType(*node, walk) + } + } + + if cont { + walkType(sub, walk) + } + return sub +} + // walkType calls fn on each child of typ. func walkType(typ Type, fn func(*Type)) { // Explicitly type switch on the most common types to allow the inliner to diff --git a/vendor/github.com/cilium/ebpf/btf/types.go b/vendor/github.com/cilium/ebpf/btf/types.go index 8bd7fc77fc6..1e57a9791fe 100644 --- a/vendor/github.com/cilium/ebpf/btf/types.go +++ b/vendor/github.com/cilium/ebpf/btf/types.go @@ -6,12 +6,12 @@ import ( "fmt" "io" "math" + "slices" "strings" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/sys" - "golang.org/x/exp/slices" ) // Mirrors MAX_RESOLVE_DEPTH in libbpf. @@ -678,52 +678,31 @@ type Transformer func(Type) Type // typ may form a cycle. If transform is not nil, it is called with the // to be copied type, and the returned value is copied instead. func Copy(typ Type, transform Transformer) Type { - copies := copier{copies: make(map[Type]Type)} - copies.copy(&typ, transform) - return typ + copies := make(copier) + return copies.copy(typ, transform) } -// copy a slice of Types recursively. -// -// See Copy for the semantics. -func copyTypes(types []Type, transform Transformer) []Type { - result := make([]Type, len(types)) - copy(result, types) - - copies := copier{copies: make(map[Type]Type, len(types))} - for i := range result { - copies.copy(&result[i], transform) - } - - return result -} - -type copier struct { - copies map[Type]Type - work typeDeque -} +// A map of a type to its copy. +type copier map[Type]Type -func (c *copier) copy(typ *Type, transform Transformer) { - for t := typ; t != nil; t = c.work.Pop() { - // *t is the identity of the type. - if cpy := c.copies[*t]; cpy != nil { - *t = cpy - continue +func (c copier) copy(typ Type, transform Transformer) Type { + return modifyGraphPreorder(typ, func(t Type) (Type, bool) { + cpy, ok := c[t] + if ok { + // This has been copied previously, no need to continue. + return cpy, false } - var cpy Type if transform != nil { - cpy = transform(*t).copy() + cpy = transform(t).copy() } else { - cpy = (*t).copy() + cpy = t.copy() } + c[t] = cpy - c.copies[*t] = cpy - *t = cpy - - // Mark any nested types for copying. - walkType(cpy, c.work.Push) - } + // This is a new copy, keep copying children. + return cpy, true + }) } type typeDeque = internal.Deque[*Type] diff --git a/vendor/github.com/cilium/ebpf/cpu.go b/vendor/github.com/cilium/ebpf/cpu.go index 1397d6de985..07e959efdcb 100644 --- a/vendor/github.com/cilium/ebpf/cpu.go +++ b/vendor/github.com/cilium/ebpf/cpu.go @@ -4,11 +4,10 @@ import ( "fmt" "os" "strings" - - "github.com/cilium/ebpf/internal" + "sync" ) -var possibleCPU = internal.Memoize(func() (int, error) { +var possibleCPU = sync.OnceValues(func() (int, error) { return parseCPUsFromFile("/sys/devices/system/cpu/possible") }) diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go index 1eab8d69bc6..e409e97f9fc 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader.go +++ b/vendor/github.com/cilium/ebpf/elf_reader.go @@ -457,6 +457,8 @@ func jumpTarget(offset uint64, ins asm.Instruction) uint64 { return uint64(dest) } +var errUnsupportedBinding = errors.New("unsupported binding") + func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) error { var ( typ = elf.ST_TYPE(rel.Info) @@ -473,7 +475,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err } if bind != elf.STB_GLOBAL { - return fmt.Errorf("map %q: unsupported relocation %s", name, bind) + return fmt.Errorf("map %q: %w: %s", name, errUnsupportedBinding, bind) } if typ != elf.STT_OBJECT && typ != elf.STT_NOTYPE { @@ -489,7 +491,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err switch typ { case elf.STT_SECTION: if bind != elf.STB_LOCAL { - return fmt.Errorf("direct load: %s: unsupported section relocation %s", name, bind) + return fmt.Errorf("direct load: %s: %w: %s", name, errUnsupportedBinding, bind) } // This is really a reference to a static symbol, which clang doesn't @@ -500,7 +502,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err case elf.STT_OBJECT: // LLVM 9 emits OBJECT-LOCAL symbols for anonymous constants. if bind != elf.STB_GLOBAL && bind != elf.STB_LOCAL { - return fmt.Errorf("direct load: %s: unsupported object relocation %s", name, bind) + return fmt.Errorf("direct load: %s: %w: %s", name, errUnsupportedBinding, bind) } offset = uint32(rel.Value) @@ -508,7 +510,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err case elf.STT_NOTYPE: // LLVM 7 emits NOTYPE-LOCAL symbols for anonymous constants. if bind != elf.STB_LOCAL { - return fmt.Errorf("direct load: %s: unsupported untyped relocation %s", name, bind) + return fmt.Errorf("direct load: %s: %w: %s", name, errUnsupportedBinding, bind) } offset = uint32(rel.Value) @@ -536,12 +538,12 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err switch typ { case elf.STT_NOTYPE, elf.STT_FUNC: if bind != elf.STB_GLOBAL { - return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + return fmt.Errorf("call: %s: %w: %s", name, errUnsupportedBinding, bind) } case elf.STT_SECTION: if bind != elf.STB_LOCAL { - return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + return fmt.Errorf("call: %s: %w: %s", name, errUnsupportedBinding, bind) } // The function we want to call is in the indicated section, @@ -564,12 +566,12 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err switch typ { case elf.STT_FUNC: if bind != elf.STB_GLOBAL { - return fmt.Errorf("load: %s: unsupported binding: %s", name, bind) + return fmt.Errorf("load: %s: %w: %s", name, errUnsupportedBinding, bind) } case elf.STT_SECTION: if bind != elf.STB_LOCAL { - return fmt.Errorf("load: %s: unsupported binding: %s", name, bind) + return fmt.Errorf("load: %s: %w: %s", name, errUnsupportedBinding, bind) } // ins.Constant already contains the offset in bytes from the @@ -599,7 +601,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err // and extern kconfig variables declared using __kconfig. case undefSection: if bind != elf.STB_GLOBAL { - return fmt.Errorf("asm relocation: %s: unsupported binding: %s", name, bind) + return fmt.Errorf("asm relocation: %s: %w: %s", name, errUnsupportedBinding, bind) } if typ != elf.STT_NOTYPE { diff --git a/vendor/github.com/cilium/ebpf/elf_sections.go b/vendor/github.com/cilium/ebpf/elf_sections.go index 1cfbd6bbaeb..4b58251d9ab 100644 --- a/vendor/github.com/cilium/ebpf/elf_sections.go +++ b/vendor/github.com/cilium/ebpf/elf_sections.go @@ -33,6 +33,8 @@ var elfSectionDefs = []libbpfElfSectionDef{ {"tc", sys.BPF_PROG_TYPE_SCHED_CLS, 0, _SEC_NONE}, {"classifier", sys.BPF_PROG_TYPE_SCHED_CLS, 0, _SEC_NONE}, {"action", sys.BPF_PROG_TYPE_SCHED_ACT, 0, _SEC_NONE}, + {"netkit/primary", sys.BPF_PROG_TYPE_SCHED_CLS, sys.BPF_NETKIT_PRIMARY, _SEC_NONE}, + {"netkit/peer", sys.BPF_PROG_TYPE_SCHED_CLS, sys.BPF_NETKIT_PEER, _SEC_NONE}, {"tracepoint+", sys.BPF_PROG_TYPE_TRACEPOINT, 0, _SEC_NONE}, {"tp+", sys.BPF_PROG_TYPE_TRACEPOINT, 0, _SEC_NONE}, {"raw_tracepoint+", sys.BPF_PROG_TYPE_RAW_TRACEPOINT, 0, _SEC_NONE}, @@ -83,14 +85,19 @@ var elfSectionDefs = []libbpfElfSectionDef{ {"cgroup/bind6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET6_BIND, _SEC_ATTACHABLE}, {"cgroup/connect4", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET4_CONNECT, _SEC_ATTACHABLE}, {"cgroup/connect6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET6_CONNECT, _SEC_ATTACHABLE}, + {"cgroup/connect_unix", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UNIX_CONNECT, _SEC_ATTACHABLE}, {"cgroup/sendmsg4", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UDP4_SENDMSG, _SEC_ATTACHABLE}, {"cgroup/sendmsg6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UDP6_SENDMSG, _SEC_ATTACHABLE}, + {"cgroup/sendmsg_unix", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UNIX_SENDMSG, _SEC_ATTACHABLE}, {"cgroup/recvmsg4", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UDP4_RECVMSG, _SEC_ATTACHABLE}, {"cgroup/recvmsg6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UDP6_RECVMSG, _SEC_ATTACHABLE}, + {"cgroup/recvmsg_unix", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UNIX_RECVMSG, _SEC_ATTACHABLE}, {"cgroup/getpeername4", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET4_GETPEERNAME, _SEC_ATTACHABLE}, {"cgroup/getpeername6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET6_GETPEERNAME, _SEC_ATTACHABLE}, + {"cgroup/getpeername_unix", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UNIX_GETPEERNAME, _SEC_ATTACHABLE}, {"cgroup/getsockname4", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET4_GETSOCKNAME, _SEC_ATTACHABLE}, {"cgroup/getsockname6", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_INET6_GETSOCKNAME, _SEC_ATTACHABLE}, + {"cgroup/getsockname_unix", sys.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, sys.BPF_CGROUP_UNIX_GETSOCKNAME, _SEC_ATTACHABLE}, {"cgroup/sysctl", sys.BPF_PROG_TYPE_CGROUP_SYSCTL, sys.BPF_CGROUP_SYSCTL, _SEC_ATTACHABLE}, {"cgroup/getsockopt", sys.BPF_PROG_TYPE_CGROUP_SOCKOPT, sys.BPF_CGROUP_GETSOCKOPT, _SEC_ATTACHABLE}, {"cgroup/setsockopt", sys.BPF_PROG_TYPE_CGROUP_SOCKOPT, sys.BPF_CGROUP_SETSOCKOPT, _SEC_ATTACHABLE}, diff --git a/vendor/github.com/cilium/ebpf/features/misc.go b/vendor/github.com/cilium/ebpf/features/misc.go index de07d3801b7..6bd8df9332d 100644 --- a/vendor/github.com/cilium/ebpf/features/misc.go +++ b/vendor/github.com/cilium/ebpf/features/misc.go @@ -12,7 +12,11 @@ import ( // Upstream commit c04c0d2b968a ("bpf: increase complexity limit and maximum program size"). // // See the package documentation for the meaning of the error return value. -var HaveLargeInstructions = internal.NewFeatureTest(">4096 instructions", "5.2", func() error { +func HaveLargeInstructions() error { + return haveLargeInstructions() +} + +var haveLargeInstructions = internal.NewFeatureTest(">4096 instructions", "5.2", func() error { const maxInsns = 4096 insns := make(asm.Instructions, maxInsns, maxInsns+1) @@ -32,7 +36,11 @@ var HaveLargeInstructions = internal.NewFeatureTest(">4096 instructions", "5.2", // Upstream commit 2589726d12a1 ("bpf: introduce bounded loops"). // // See the package documentation for the meaning of the error return value. -var HaveBoundedLoops = internal.NewFeatureTest("bounded loops", "5.3", func() error { +func HaveBoundedLoops() error { + return haveBoundedLoops() +} + +var haveBoundedLoops = internal.NewFeatureTest("bounded loops", "5.3", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ @@ -49,7 +57,11 @@ var HaveBoundedLoops = internal.NewFeatureTest("bounded loops", "5.3", func() er // Upstream commit 92b31a9af73b ("bpf: add BPF_J{LT,LE,SLT,SLE} instructions"). // // See the package documentation for the meaning of the error return value. -var HaveV2ISA = internal.NewFeatureTest("v2 ISA", "4.14", func() error { +func HaveV2ISA() error { + return haveV2ISA() +} + +var haveV2ISA = internal.NewFeatureTest("v2 ISA", "4.14", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ @@ -66,7 +78,11 @@ var HaveV2ISA = internal.NewFeatureTest("v2 ISA", "4.14", func() error { // Upstream commit 092ed0968bb6 ("bpf: verifier support JMP32"). // // See the package documentation for the meaning of the error return value. -var HaveV3ISA = internal.NewFeatureTest("v3 ISA", "5.1", func() error { +func HaveV3ISA() error { + return haveV3ISA() +} + +var haveV3ISA = internal.NewFeatureTest("v3 ISA", "5.1", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ diff --git a/vendor/github.com/cilium/ebpf/internal/auxv.go b/vendor/github.com/cilium/ebpf/internal/auxv.go new file mode 100644 index 00000000000..45fd0d37f13 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/auxv.go @@ -0,0 +1,60 @@ +package internal + +import ( + "errors" + "io" + _ "unsafe" +) + +type auxvPairReader interface { + Close() error + ReadAuxvPair() (uint64, uint64, error) +} + +// See https://elixir.bootlin.com/linux/v6.5.5/source/include/uapi/linux/auxvec.h +const ( + _AT_NULL = 0 // End of vector + _AT_SYSINFO_EHDR = 33 // Offset to vDSO blob in process image +) + +//go:linkname runtime_getAuxv runtime.getAuxv +func runtime_getAuxv() []uintptr + +type auxvRuntimeReader struct { + data []uintptr + index int +} + +func (r *auxvRuntimeReader) Close() error { + return nil +} + +func (r *auxvRuntimeReader) ReadAuxvPair() (uint64, uint64, error) { + if r.index >= len(r.data)+2 { + return 0, 0, io.EOF + } + + // we manually add the (_AT_NULL, _AT_NULL) pair at the end + // that is not provided by the go runtime + var tag, value uintptr + if r.index+1 < len(r.data) { + tag, value = r.data[r.index], r.data[r.index+1] + } else { + tag, value = _AT_NULL, _AT_NULL + } + r.index += 2 + return uint64(tag), uint64(value), nil +} + +func newAuxvRuntimeReader() (auxvPairReader, error) { + data := runtime_getAuxv() + + if len(data)%2 != 0 { + return nil, errors.New("malformed auxv passed from runtime") + } + + return &auxvRuntimeReader{ + data: data, + index: 0, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/internal/memoize.go b/vendor/github.com/cilium/ebpf/internal/memoize.go deleted file mode 100644 index 3de0a3fb95a..00000000000 --- a/vendor/github.com/cilium/ebpf/internal/memoize.go +++ /dev/null @@ -1,26 +0,0 @@ -package internal - -import ( - "sync" -) - -type memoizedFunc[T any] struct { - once sync.Once - fn func() (T, error) - result T - err error -} - -func (mf *memoizedFunc[T]) do() (T, error) { - mf.once.Do(func() { - mf.result, mf.err = mf.fn() - }) - return mf.result, mf.err -} - -// Memoize the result of a function call. -// -// fn is only ever called once, even if it returns an error. -func Memoize[T any](fn func() (T, error)) func() (T, error) { - return (&memoizedFunc[T]{fn: fn}).do -} diff --git a/vendor/github.com/cilium/ebpf/internal/sys/types.go b/vendor/github.com/cilium/ebpf/internal/sys/types.go index 0feffaee9f4..db7baa0224b 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/types.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/types.go @@ -65,7 +65,14 @@ const ( BPF_TCX_INGRESS AttachType = 46 BPF_TCX_EGRESS AttachType = 47 BPF_TRACE_UPROBE_MULTI AttachType = 48 - __MAX_BPF_ATTACH_TYPE AttachType = 49 + BPF_CGROUP_UNIX_CONNECT AttachType = 49 + BPF_CGROUP_UNIX_SENDMSG AttachType = 50 + BPF_CGROUP_UNIX_RECVMSG AttachType = 51 + BPF_CGROUP_UNIX_GETPEERNAME AttachType = 52 + BPF_CGROUP_UNIX_GETSOCKNAME AttachType = 53 + BPF_NETKIT_PRIMARY AttachType = 54 + BPF_NETKIT_PEER AttachType = 55 + __MAX_BPF_ATTACH_TYPE AttachType = 56 ) type Cmd uint32 @@ -351,46 +358,48 @@ const ( BPF_LINK_TYPE_NETFILTER LinkType = 10 BPF_LINK_TYPE_TCX LinkType = 11 BPF_LINK_TYPE_UPROBE_MULTI LinkType = 12 - MAX_BPF_LINK_TYPE LinkType = 13 + BPF_LINK_TYPE_NETKIT LinkType = 13 + MAX_BPF_LINK_TYPE LinkType = 14 ) type MapType uint32 const ( - BPF_MAP_TYPE_UNSPEC MapType = 0 - BPF_MAP_TYPE_HASH MapType = 1 - BPF_MAP_TYPE_ARRAY MapType = 2 - BPF_MAP_TYPE_PROG_ARRAY MapType = 3 - BPF_MAP_TYPE_PERF_EVENT_ARRAY MapType = 4 - BPF_MAP_TYPE_PERCPU_HASH MapType = 5 - BPF_MAP_TYPE_PERCPU_ARRAY MapType = 6 - BPF_MAP_TYPE_STACK_TRACE MapType = 7 - BPF_MAP_TYPE_CGROUP_ARRAY MapType = 8 - BPF_MAP_TYPE_LRU_HASH MapType = 9 - BPF_MAP_TYPE_LRU_PERCPU_HASH MapType = 10 - BPF_MAP_TYPE_LPM_TRIE MapType = 11 - BPF_MAP_TYPE_ARRAY_OF_MAPS MapType = 12 - BPF_MAP_TYPE_HASH_OF_MAPS MapType = 13 - BPF_MAP_TYPE_DEVMAP MapType = 14 - BPF_MAP_TYPE_SOCKMAP MapType = 15 - BPF_MAP_TYPE_CPUMAP MapType = 16 - BPF_MAP_TYPE_XSKMAP MapType = 17 - BPF_MAP_TYPE_SOCKHASH MapType = 18 - BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED MapType = 19 - BPF_MAP_TYPE_CGROUP_STORAGE MapType = 19 - BPF_MAP_TYPE_REUSEPORT_SOCKARRAY MapType = 20 - BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE MapType = 21 - BPF_MAP_TYPE_QUEUE MapType = 22 - BPF_MAP_TYPE_STACK MapType = 23 - BPF_MAP_TYPE_SK_STORAGE MapType = 24 - BPF_MAP_TYPE_DEVMAP_HASH MapType = 25 - BPF_MAP_TYPE_STRUCT_OPS MapType = 26 - BPF_MAP_TYPE_RINGBUF MapType = 27 - BPF_MAP_TYPE_INODE_STORAGE MapType = 28 - BPF_MAP_TYPE_TASK_STORAGE MapType = 29 - BPF_MAP_TYPE_BLOOM_FILTER MapType = 30 - BPF_MAP_TYPE_USER_RINGBUF MapType = 31 - BPF_MAP_TYPE_CGRP_STORAGE MapType = 32 + BPF_MAP_TYPE_UNSPEC MapType = 0 + BPF_MAP_TYPE_HASH MapType = 1 + BPF_MAP_TYPE_ARRAY MapType = 2 + BPF_MAP_TYPE_PROG_ARRAY MapType = 3 + BPF_MAP_TYPE_PERF_EVENT_ARRAY MapType = 4 + BPF_MAP_TYPE_PERCPU_HASH MapType = 5 + BPF_MAP_TYPE_PERCPU_ARRAY MapType = 6 + BPF_MAP_TYPE_STACK_TRACE MapType = 7 + BPF_MAP_TYPE_CGROUP_ARRAY MapType = 8 + BPF_MAP_TYPE_LRU_HASH MapType = 9 + BPF_MAP_TYPE_LRU_PERCPU_HASH MapType = 10 + BPF_MAP_TYPE_LPM_TRIE MapType = 11 + BPF_MAP_TYPE_ARRAY_OF_MAPS MapType = 12 + BPF_MAP_TYPE_HASH_OF_MAPS MapType = 13 + BPF_MAP_TYPE_DEVMAP MapType = 14 + BPF_MAP_TYPE_SOCKMAP MapType = 15 + BPF_MAP_TYPE_CPUMAP MapType = 16 + BPF_MAP_TYPE_XSKMAP MapType = 17 + BPF_MAP_TYPE_SOCKHASH MapType = 18 + BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED MapType = 19 + BPF_MAP_TYPE_CGROUP_STORAGE MapType = 19 + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY MapType = 20 + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED MapType = 21 + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE MapType = 21 + BPF_MAP_TYPE_QUEUE MapType = 22 + BPF_MAP_TYPE_STACK MapType = 23 + BPF_MAP_TYPE_SK_STORAGE MapType = 24 + BPF_MAP_TYPE_DEVMAP_HASH MapType = 25 + BPF_MAP_TYPE_STRUCT_OPS MapType = 26 + BPF_MAP_TYPE_RINGBUF MapType = 27 + BPF_MAP_TYPE_INODE_STORAGE MapType = 28 + BPF_MAP_TYPE_TASK_STORAGE MapType = 29 + BPF_MAP_TYPE_BLOOM_FILTER MapType = 30 + BPF_MAP_TYPE_USER_RINGBUF MapType = 31 + BPF_MAP_TYPE_CGRP_STORAGE MapType = 32 ) type ProgType uint32 @@ -507,7 +516,7 @@ type LinkInfo struct { Id LinkID ProgId uint32 _ [4]byte - Extra [32]uint8 + Extra [40]uint8 } type MapInfo struct { @@ -711,6 +720,26 @@ func LinkCreateKprobeMulti(attr *LinkCreateKprobeMultiAttr) (*FD, error) { return NewFD(int(fd)) } +type LinkCreateNetfilterAttr struct { + ProgFd uint32 + TargetFd uint32 + AttachType AttachType + Flags uint32 + Pf uint32 + Hooknum uint32 + Priority int32 + NetfilterFlags uint32 + _ [32]byte +} + +func LinkCreateNetfilter(attr *LinkCreateNetfilterAttr) (*FD, error) { + fd, err := BPF(BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + return NewFD(int(fd)) +} + type LinkCreatePerfEventAttr struct { ProgFd uint32 TargetFd uint32 @@ -766,6 +795,29 @@ func LinkCreateTracing(attr *LinkCreateTracingAttr) (*FD, error) { return NewFD(int(fd)) } +type LinkCreateUprobeMultiAttr struct { + ProgFd uint32 + TargetFd uint32 + AttachType AttachType + Flags uint32 + Path Pointer + Offsets Pointer + RefCtrOffsets Pointer + Cookies Pointer + Count uint32 + UprobeMultiFlags uint32 + Pid uint32 + _ [4]byte +} + +func LinkCreateUprobeMulti(attr *LinkCreateUprobeMultiAttr) (*FD, error) { + fd, err := BPF(BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + return NewFD(int(fd)) +} + type LinkUpdateAttr struct { LinkFd uint32 NewProgFd uint32 @@ -1169,6 +1221,13 @@ type NetNsLinkInfo struct { AttachType AttachType } +type NetfilterLinkInfo struct { + Pf uint32 + Hooknum uint32 + Priority int32 + Flags uint32 +} + type RawTracepointLinkInfo struct { TpName Pointer TpNameLen uint32 diff --git a/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go b/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go index 97ac473c889..d184ea196ae 100644 --- a/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go +++ b/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go @@ -54,6 +54,11 @@ func (b Buffer) CopyTo(dst []byte) int { return copy(dst, b.unsafeBytes()) } +// AppendTo appends the buffer onto dst. +func (b Buffer) AppendTo(dst []byte) []byte { + return append(dst, b.unsafeBytes()...) +} + // Pointer returns the location where a syscall should write. func (b Buffer) Pointer() sys.Pointer { // NB: This deliberately ignores b.length to support zero-copy diff --git a/vendor/github.com/cilium/ebpf/internal/sysenc/marshal.go b/vendor/github.com/cilium/ebpf/internal/sysenc/marshal.go index 52339456aaf..0026af8f24f 100644 --- a/vendor/github.com/cilium/ebpf/internal/sysenc/marshal.go +++ b/vendor/github.com/cilium/ebpf/internal/sysenc/marshal.go @@ -7,12 +7,11 @@ import ( "errors" "fmt" "reflect" + "slices" "sync" "unsafe" "github.com/cilium/ebpf/internal" - - "golang.org/x/exp/slices" ) // Marshal turns data into a byte slice using the system's native endianness. diff --git a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go index 1b45a9a7427..897740fec0c 100644 --- a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go +++ b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go @@ -8,6 +8,7 @@ import ( "path/filepath" "runtime" "strings" + "sync" "syscall" "github.com/cilium/ebpf/internal" @@ -110,7 +111,7 @@ func sanitizeTracefsPath(path ...string) (string, error) { // Since kernel 4.1 tracefs should be mounted by default at /sys/kernel/tracing, // but may be also be available at /sys/kernel/debug/tracing if debugfs is mounted. // The available tracefs paths will depends on distribution choices. -var getTracefsPath = internal.Memoize(func() (string, error) { +var getTracefsPath = sync.OnceValues(func() (string, error) { for _, p := range []struct { path string fsType int64 diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go index bc63724018b..2f22b1278ed 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go @@ -40,6 +40,7 @@ const ( BPF_F_MMAPABLE = linux.BPF_F_MMAPABLE BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP BPF_F_KPROBE_MULTI_RETURN = linux.BPF_F_KPROBE_MULTI_RETURN + BPF_F_UPROBE_MULTI_RETURN = linux.BPF_F_UPROBE_MULTI_RETURN BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN BPF_TAG_SIZE = linux.BPF_TAG_SIZE BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go index 3a0f79cd3c5..e5bad046986 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go @@ -42,6 +42,7 @@ const ( BPF_F_MMAPABLE BPF_F_INNER_MAP BPF_F_KPROBE_MULTI_RETURN + BPF_F_UPROBE_MULTI_RETURN BPF_F_XDP_HAS_FRAGS BPF_OBJ_NAME_LEN BPF_TAG_SIZE diff --git a/vendor/github.com/cilium/ebpf/internal/vdso.go b/vendor/github.com/cilium/ebpf/internal/vdso.go index c444a41c4b1..1049278554e 100644 --- a/vendor/github.com/cilium/ebpf/internal/vdso.go +++ b/vendor/github.com/cilium/ebpf/internal/vdso.go @@ -8,7 +8,6 @@ import ( "io" "math" "os" - "unsafe" "github.com/cilium/ebpf/internal/unix" ) @@ -20,21 +19,14 @@ var ( // vdsoVersion returns the LINUX_VERSION_CODE embedded in the vDSO library // linked into the current process image. func vdsoVersion() (uint32, error) { - const uintptrIs32bits = unsafe.Sizeof((uintptr)(0)) == 4 - - // Read data from the auxiliary vector, which is normally passed directly - // to the process. Go does not expose that data, so we must read it from procfs. - // https://man7.org/linux/man-pages/man3/getauxval.3.html - av, err := os.Open("/proc/self/auxv") - if errors.Is(err, unix.EACCES) { - return 0, fmt.Errorf("opening auxv: %w (process may not be dumpable due to file capabilities)", err) - } + av, err := newAuxvRuntimeReader() if err != nil { - return 0, fmt.Errorf("opening auxv: %w", err) + return 0, err } + defer av.Close() - vdsoAddr, err := vdsoMemoryAddress(av, NativeEndian, uintptrIs32bits) + vdsoAddr, err := vdsoMemoryAddress(av) if err != nil { return 0, fmt.Errorf("finding vDSO memory address: %w", err) } @@ -55,43 +47,13 @@ func vdsoVersion() (uint32, error) { return c, nil } -type auxvPair32 struct { - Tag, Value uint32 -} - -type auxvPair64 struct { - Tag, Value uint64 -} - -func readAuxvPair(r io.Reader, order binary.ByteOrder, uintptrIs32bits bool) (tag, value uint64, _ error) { - if uintptrIs32bits { - var aux auxvPair32 - if err := binary.Read(r, order, &aux); err != nil { - return 0, 0, fmt.Errorf("reading auxv entry: %w", err) - } - return uint64(aux.Tag), uint64(aux.Value), nil - } - - var aux auxvPair64 - if err := binary.Read(r, order, &aux); err != nil { - return 0, 0, fmt.Errorf("reading auxv entry: %w", err) - } - return aux.Tag, aux.Value, nil -} - // vdsoMemoryAddress returns the memory address of the vDSO library // linked into the current process image. r is an io.Reader into an auxv blob. -func vdsoMemoryAddress(r io.Reader, order binary.ByteOrder, uintptrIs32bits bool) (uintptr, error) { - // See https://elixir.bootlin.com/linux/v6.5.5/source/include/uapi/linux/auxvec.h - const ( - _AT_NULL = 0 // End of vector - _AT_SYSINFO_EHDR = 33 // Offset to vDSO blob in process image - ) - +func vdsoMemoryAddress(r auxvPairReader) (uintptr, error) { // Loop through all tag/value pairs in auxv until we find `AT_SYSINFO_EHDR`, // the address of a page containing the virtual Dynamic Shared Object (vDSO). for { - tag, value, err := readAuxvPair(r, order, uintptrIs32bits) + tag, value, err := r.ReadAuxvPair() if err != nil { return 0, err } diff --git a/vendor/github.com/cilium/ebpf/internal/version.go b/vendor/github.com/cilium/ebpf/internal/version.go index 9b17ffb44de..acd4650af73 100644 --- a/vendor/github.com/cilium/ebpf/internal/version.go +++ b/vendor/github.com/cilium/ebpf/internal/version.go @@ -2,6 +2,7 @@ package internal import ( "fmt" + "sync" "github.com/cilium/ebpf/internal/unix" ) @@ -79,7 +80,7 @@ func (v Version) Kernel() uint32 { } // KernelVersion returns the version of the currently running kernel. -var KernelVersion = Memoize(func() (Version, error) { +var KernelVersion = sync.OnceValues(func() (Version, error) { return detectKernelVersion() }) diff --git a/vendor/github.com/cilium/ebpf/link/link.go b/vendor/github.com/cilium/ebpf/link/link.go index 590ea3aec3d..03368a2019c 100644 --- a/vendor/github.com/cilium/ebpf/link/link.go +++ b/vendor/github.com/cilium/ebpf/link/link.go @@ -96,10 +96,14 @@ func wrapRawLink(raw *RawLink) (_ Link, err error) { return &NetNsLink{*raw}, nil case KprobeMultiType: return &kprobeMultiLink{*raw}, nil + case UprobeMultiType: + return &uprobeMultiLink{*raw}, nil case PerfEventType: return nil, fmt.Errorf("recovering perf event fd: %w", ErrNotSupported) case TCXType: return &tcxLink{*raw}, nil + case NetfilterType: + return &netfilterLink{*raw}, nil default: return raw, nil } @@ -135,6 +139,7 @@ type CgroupInfo sys.CgroupLinkInfo type NetNsInfo sys.NetNsLinkInfo type XDPInfo sys.XDPLinkInfo type TCXInfo sys.TcxLinkInfo +type NetfilterInfo sys.NetfilterLinkInfo // Tracing returns tracing type-specific link info. // @@ -160,7 +165,7 @@ func (r Info) NetNs() *NetNsInfo { return e } -// ExtraNetNs returns XDP type-specific link info. +// XDP returns XDP type-specific link info. // // Returns nil if the type-specific link info isn't available. func (r Info) XDP() *XDPInfo { @@ -168,6 +173,22 @@ func (r Info) XDP() *XDPInfo { return e } +// TCX returns TCX type-specific link info. +// +// Returns nil if the type-specific link info isn't available. +func (r Info) TCX() *TCXInfo { + e, _ := r.extra.(*TCXInfo) + return e +} + +// Netfilter returns netfilter type-specific link info. +// +// Returns nil if the type-specific link info isn't available. +func (r Info) Netfilter() *NetfilterInfo { + e, _ := r.extra.(*NetfilterInfo) + return e +} + // RawLink is the low-level API to bpf_link. // // You should consider using the higher level interfaces in this @@ -316,10 +337,12 @@ func (l *RawLink) Info() (*Info, error) { case XDPType: extra = &XDPInfo{} case RawTracepointType, IterType, - PerfEventType, KprobeMultiType: + PerfEventType, KprobeMultiType, UprobeMultiType: // Extra metadata not supported. case TCXType: extra = &TCXInfo{} + case NetfilterType: + extra = &NetfilterInfo{} default: return nil, fmt.Errorf("unknown link info type: %d", info.Type) } diff --git a/vendor/github.com/cilium/ebpf/link/netfilter.go b/vendor/github.com/cilium/ebpf/link/netfilter.go new file mode 100644 index 00000000000..250c87677b0 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/link/netfilter.go @@ -0,0 +1,70 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" +) + +const NetfilterIPDefrag NetfilterAttachFlags = 0 // Enable IP packet defragmentation + +type NetfilterAttachFlags uint32 + +type NetfilterOptions struct { + // Program must be a netfilter BPF program. + Program *ebpf.Program + // The protocol family. + ProtocolFamily uint32 + // The number of the hook you are interested in. + HookNumber uint32 + // Priority within hook + Priority int32 + // Extra link flags + Flags uint32 + // Netfilter flags + NetfilterFlags NetfilterAttachFlags +} + +type netfilterLink struct { + RawLink +} + +// AttachNetfilter links a netfilter BPF program to a netfilter hook. +func AttachNetfilter(opts NetfilterOptions) (Link, error) { + if opts.Program == nil { + return nil, fmt.Errorf("netfilter program is nil") + } + + if t := opts.Program.Type(); t != ebpf.Netfilter { + return nil, fmt.Errorf("invalid program type %s, expected netfilter", t) + } + + progFd := opts.Program.FD() + if progFd < 0 { + return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd) + } + + attr := sys.LinkCreateNetfilterAttr{ + ProgFd: uint32(opts.Program.FD()), + AttachType: sys.BPF_NETFILTER, + Flags: opts.Flags, + Pf: uint32(opts.ProtocolFamily), + Hooknum: uint32(opts.HookNumber), + Priority: opts.Priority, + NetfilterFlags: uint32(opts.NetfilterFlags), + } + + fd, err := sys.LinkCreateNetfilter(&attr) + if err != nil { + return nil, fmt.Errorf("attach netfilter link: %w", err) + } + + return &netfilterLink{RawLink{fd, ""}}, nil +} + +func (*netfilterLink) Update(new *ebpf.Program) error { + return fmt.Errorf("netfilter update: %w", ErrNotSupported) +} + +var _ Link = (*netfilterLink)(nil) diff --git a/vendor/github.com/cilium/ebpf/link/syscalls.go b/vendor/github.com/cilium/ebpf/link/syscalls.go index 96d6c7b1a03..53476c925b0 100644 --- a/vendor/github.com/cilium/ebpf/link/syscalls.go +++ b/vendor/github.com/cilium/ebpf/link/syscalls.go @@ -25,6 +25,8 @@ const ( PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT KprobeMultiType = sys.BPF_LINK_TYPE_KPROBE_MULTI TCXType = sys.BPF_LINK_TYPE_TCX + UprobeMultiType = sys.BPF_LINK_TYPE_UPROBE_MULTI + NetfilterType = sys.BPF_LINK_TYPE_NETFILTER ) var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error { @@ -125,3 +127,38 @@ var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() err } return errors.New("syscall succeeded unexpectedly") }) + +var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error { + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Type: ebpf.SchedCLS, + License: "MIT", + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + }) + + if err != nil { + return internal.ErrNotSupported + } + + defer prog.Close() + attr := sys.LinkCreateTcxAttr{ + // We rely on this being checked during the syscall. + // With an otherwise correct payload we expect ENODEV here + // as an indication that the feature is present. + TargetIfindex: ^uint32(0), + ProgFd: uint32(prog.FD()), + AttachType: sys.AttachType(ebpf.AttachTCXIngress), + } + + _, err = sys.LinkCreateTcx(&attr) + + if errors.Is(err, unix.ENODEV) { + return nil + } + if err != nil { + return ErrNotSupported + } + return errors.New("syscall succeeded unexpectedly") +}) diff --git a/vendor/github.com/cilium/ebpf/link/tcx.go b/vendor/github.com/cilium/ebpf/link/tcx.go index 6989af8c9e7..88f2237d290 100644 --- a/vendor/github.com/cilium/ebpf/link/tcx.go +++ b/vendor/github.com/cilium/ebpf/link/tcx.go @@ -55,6 +55,9 @@ func AttachTCX(opts TCXOptions) (Link, error) { runtime.KeepAlive(opts.Program) runtime.KeepAlive(opts.Anchor) if err != nil { + if haveFeatErr := haveTCX(); haveFeatErr != nil { + return nil, haveFeatErr + } return nil, fmt.Errorf("attach tcx link: %w", err) } diff --git a/vendor/github.com/cilium/ebpf/link/uprobe.go b/vendor/github.com/cilium/ebpf/link/uprobe.go index 83977e0e54d..ad85024e38e 100644 --- a/vendor/github.com/cilium/ebpf/link/uprobe.go +++ b/vendor/github.com/cilium/ebpf/link/uprobe.go @@ -36,10 +36,10 @@ var ( type Executable struct { // Path of the executable on the filesystem. path string - // Parsed ELF and dynamic symbols' addresses. - addresses map[string]uint64 + // Parsed ELF and dynamic symbols' cachedAddresses. + cachedAddresses map[string]uint64 // Keep track of symbol table lazy load. - addressesOnce sync.Once + cacheAddressesOnce sync.Once } // UprobeOptions defines additional parameters that will be used @@ -108,8 +108,8 @@ func OpenExecutable(path string) (*Executable, error) { } return &Executable{ - path: path, - addresses: make(map[string]uint64), + path: path, + cachedAddresses: make(map[string]uint64), }, nil } @@ -153,7 +153,7 @@ func (ex *Executable) load(f *internal.SafeELFFile) error { } } - ex.addresses[s.Name] = address + ex.cachedAddresses[s.Name] = address } return nil @@ -162,13 +162,13 @@ func (ex *Executable) load(f *internal.SafeELFFile) error { // address calculates the address of a symbol in the executable. // // opts must not be nil. -func (ex *Executable) address(symbol string, opts *UprobeOptions) (uint64, error) { - if opts.Address > 0 { - return opts.Address + opts.Offset, nil +func (ex *Executable) address(symbol string, address, offset uint64) (uint64, error) { + if address > 0 { + return address + offset, nil } var err error - ex.addressesOnce.Do(func() { + ex.cacheAddressesOnce.Do(func() { var f *internal.SafeELFFile f, err = internal.OpenSafeELFFile(ex.path) if err != nil { @@ -183,7 +183,7 @@ func (ex *Executable) address(symbol string, opts *UprobeOptions) (uint64, error return 0, fmt.Errorf("lazy load symbols: %w", err) } - address, ok := ex.addresses[symbol] + address, ok := ex.cachedAddresses[symbol] if !ok { return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol) } @@ -199,7 +199,7 @@ func (ex *Executable) address(symbol string, opts *UprobeOptions) (uint64, error "(consider providing UprobeOptions.Address)", ex.path, symbol, ErrNotSupported) } - return address + opts.Offset, nil + return address + offset, nil } // Uprobe attaches the given eBPF program to a perf event that fires when the @@ -284,7 +284,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti opts = &UprobeOptions{} } - offset, err := ex.address(symbol, opts) + offset, err := ex.address(symbol, opts.Address, opts.Offset) if err != nil { return nil, err } diff --git a/vendor/github.com/cilium/ebpf/link/uprobe_multi.go b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go new file mode 100644 index 00000000000..9a8d329c8f9 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go @@ -0,0 +1,224 @@ +package link + +import ( + "errors" + "fmt" + "os" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/sys" + "github.com/cilium/ebpf/internal/unix" +) + +// UprobeMultiOptions defines additional parameters that will be used +// when opening a UprobeMulti Link. +type UprobeMultiOptions struct { + // Symbol addresses. If set, overrides the addresses eventually parsed from + // the executable. Mutually exclusive with UprobeMulti's symbols argument. + Addresses []uint64 + + // Offsets into functions provided by UprobeMulti's symbols argument. + // For example: to set uprobes to main+5 and _start+10, call UprobeMulti + // with: + // symbols: "main", "_start" + // opt.Offsets: 5, 10 + Offsets []uint64 + + // Optional list of associated ref counter offsets. + RefCtrOffsets []uint64 + + // Optional list of associated BPF cookies. + Cookies []uint64 + + // Only set the uprobe_multi link on the given process ID, zero PID means + // system-wide. + PID uint32 +} + +func (ex *Executable) UprobeMulti(symbols []string, prog *ebpf.Program, opts *UprobeMultiOptions) (Link, error) { + return ex.uprobeMulti(symbols, prog, opts, 0) +} + +func (ex *Executable) UretprobeMulti(symbols []string, prog *ebpf.Program, opts *UprobeMultiOptions) (Link, error) { + + // The return probe is not limited for symbols entry, so there's no special + // setup for return uprobes (other than the extra flag). The symbols, opts.Offsets + // and opts.Addresses arrays follow the same logic as for entry uprobes. + return ex.uprobeMulti(symbols, prog, opts, unix.BPF_F_UPROBE_MULTI_RETURN) +} + +func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *UprobeMultiOptions, flags uint32) (Link, error) { + if prog == nil { + return nil, errors.New("cannot attach a nil program") + } + + if opts == nil { + opts = &UprobeMultiOptions{} + } + + addresses, err := ex.addresses(symbols, opts.Addresses, opts.Offsets) + if err != nil { + return nil, err + } + + addrs := len(addresses) + cookies := len(opts.Cookies) + refCtrOffsets := len(opts.RefCtrOffsets) + + if addrs == 0 { + return nil, fmt.Errorf("Addresses are required: %w", errInvalidInput) + } + if refCtrOffsets > 0 && refCtrOffsets != addrs { + return nil, fmt.Errorf("RefCtrOffsets must be exactly Addresses in length: %w", errInvalidInput) + } + if cookies > 0 && cookies != addrs { + return nil, fmt.Errorf("Cookies must be exactly Addresses in length: %w", errInvalidInput) + } + + attr := &sys.LinkCreateUprobeMultiAttr{ + Path: sys.NewStringPointer(ex.path), + ProgFd: uint32(prog.FD()), + AttachType: sys.BPF_TRACE_UPROBE_MULTI, + UprobeMultiFlags: flags, + Count: uint32(addrs), + Offsets: sys.NewPointer(unsafe.Pointer(&addresses[0])), + Pid: opts.PID, + } + + if refCtrOffsets != 0 { + attr.RefCtrOffsets = sys.NewPointer(unsafe.Pointer(&opts.RefCtrOffsets[0])) + } + if cookies != 0 { + attr.Cookies = sys.NewPointer(unsafe.Pointer(&opts.Cookies[0])) + } + + fd, err := sys.LinkCreateUprobeMulti(attr) + if errors.Is(err, unix.ESRCH) { + return nil, fmt.Errorf("%w (specified pid not found?)", os.ErrNotExist) + } + if errors.Is(err, unix.EINVAL) { + return nil, fmt.Errorf("%w (missing symbol or prog's AttachType not AttachTraceUprobeMulti?)", err) + } + + if err != nil { + if haveFeatErr := haveBPFLinkUprobeMulti(); haveFeatErr != nil { + return nil, haveFeatErr + } + return nil, err + } + + return &uprobeMultiLink{RawLink{fd, ""}}, nil +} + +func (ex *Executable) addresses(symbols []string, addresses, offsets []uint64) ([]uint64, error) { + n := len(symbols) + if n == 0 { + n = len(addresses) + } + + if n == 0 { + return nil, fmt.Errorf("%w: neither symbols nor addresses given", errInvalidInput) + } + + if symbols != nil && len(symbols) != n { + return nil, fmt.Errorf("%w: have %d symbols but want %d", errInvalidInput, len(symbols), n) + } + + if addresses != nil && len(addresses) != n { + return nil, fmt.Errorf("%w: have %d addresses but want %d", errInvalidInput, len(addresses), n) + } + + if offsets != nil && len(offsets) != n { + return nil, fmt.Errorf("%w: have %d offsets but want %d", errInvalidInput, len(offsets), n) + } + + results := make([]uint64, 0, n) + for i := 0; i < n; i++ { + var sym string + if symbols != nil { + sym = symbols[i] + } + + var addr, off uint64 + if addresses != nil { + addr = addresses[i] + } + + if offsets != nil { + off = offsets[i] + } + + result, err := ex.address(sym, addr, off) + if err != nil { + return nil, err + } + + results = append(results, result) + } + + return results, nil +} + +type uprobeMultiLink struct { + RawLink +} + +var _ Link = (*uprobeMultiLink)(nil) + +func (kml *uprobeMultiLink) Update(prog *ebpf.Program) error { + return fmt.Errorf("update uprobe_multi: %w", ErrNotSupported) +} + +func (kml *uprobeMultiLink) Pin(string) error { + return fmt.Errorf("pin uprobe_multi: %w", ErrNotSupported) +} + +func (kml *uprobeMultiLink) Unpin() error { + return fmt.Errorf("unpin uprobe_multi: %w", ErrNotSupported) +} + +var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6.6", func() error { + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Name: "probe_upm_link", + Type: ebpf.Kprobe, + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + AttachType: ebpf.AttachTraceUprobeMulti, + License: "MIT", + }) + if errors.Is(err, unix.E2BIG) { + // Kernel doesn't support AttachType field. + return internal.ErrNotSupported + } + if err != nil { + return err + } + defer prog.Close() + + // We try to create uprobe multi link on '/' path which results in + // error with -EBADF in case uprobe multi link is supported. + fd, err := sys.LinkCreateUprobeMulti(&sys.LinkCreateUprobeMultiAttr{ + ProgFd: uint32(prog.FD()), + AttachType: sys.BPF_TRACE_UPROBE_MULTI, + Path: sys.NewStringPointer("/"), + Offsets: sys.NewPointer(unsafe.Pointer(&[]uint64{0})), + Count: 1, + }) + switch { + case errors.Is(err, unix.EBADF): + return nil + case errors.Is(err, unix.EINVAL): + return internal.ErrNotSupported + case err != nil: + return err + } + + // should not happen + fd.Close() + return errors.New("successfully attached uprobe_multi to /, kernel bug?") +}) diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go index ab21bea87e7..b93ca913ec0 100644 --- a/vendor/github.com/cilium/ebpf/linker.go +++ b/vendor/github.com/cilium/ebpf/linker.go @@ -6,8 +6,7 @@ import ( "fmt" "io" "math" - - "golang.org/x/exp/slices" + "slices" "github.com/cilium/ebpf/asm" "github.com/cilium/ebpf/btf" diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go index 5e71ccfc2a1..2b1f1e7df0d 100644 --- a/vendor/github.com/cilium/ebpf/map.go +++ b/vendor/github.com/cilium/ebpf/map.go @@ -10,6 +10,7 @@ import ( "path/filepath" "reflect" "strings" + "sync" "time" "unsafe" @@ -907,7 +908,7 @@ func (m *Map) nextKey(key interface{}, nextKeyOut sys.Pointer) error { return nil } -var mmapProtectedPage = internal.Memoize(func() ([]byte, error) { +var mmapProtectedPage = sync.OnceValues(func() ([]byte, error) { return unix.Mmap(-1, 0, os.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED) }) @@ -1005,6 +1006,53 @@ type BatchCursor struct { } func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { + if m.typ.hasPerCPUValue() { + return m.batchLookupPerCPU(cmd, cursor, keysOut, valuesOut, opts) + } + + count, err := batchCount(keysOut, valuesOut) + if err != nil { + return 0, err + } + + valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize)) + + n, err := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts) + if err != nil { + return n, err + } + + err = valueBuf.Unmarshal(valuesOut) + if err != nil { + return 0, err + } + + return n, nil +} + +func (m *Map) batchLookupPerCPU(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { + count, err := sliceLen(keysOut) + if err != nil { + return 0, fmt.Errorf("keys: %w", err) + } + + valueBuf := make([]byte, count*int(m.fullValueSize)) + valuePtr := sys.NewSlicePointer(valueBuf) + + n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valuePtr, opts) + if sysErr != nil && !errors.Is(sysErr, unix.ENOENT) { + return 0, err + } + + err = unmarshalBatchPerCPUValue(valuesOut, count, int(m.valueSize), valueBuf) + if err != nil { + return 0, err + } + + return n, sysErr +} + +func (m *Map) batchLookupCmd(cmd sys.Cmd, cursor *BatchCursor, count int, keysOut any, valuePtr sys.Pointer, opts *BatchOptions) (int, error) { cursorLen := int(m.keySize) if cursorLen < 4 { // * generic_map_lookup_batch requires that batch_out is key_size bytes. @@ -1033,29 +1081,13 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i if err := haveBatchAPI(); err != nil { return 0, err } - if m.typ.hasPerCPUValue() { - return 0, ErrNotSupported - } - keysValue := reflect.ValueOf(keysOut) - if keysValue.Kind() != reflect.Slice { - return 0, fmt.Errorf("keys must be a slice") - } - valuesValue := reflect.ValueOf(valuesOut) - if valuesValue.Kind() != reflect.Slice { - return 0, fmt.Errorf("valuesOut must be a slice") - } - count := keysValue.Len() - if count != valuesValue.Len() { - return 0, fmt.Errorf("keysOut and valuesOut must be the same length") - } keyBuf := sysenc.SyscallOutput(keysOut, count*int(m.keySize)) - valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize)) attr := sys.MapLookupBatchAttr{ MapFd: m.fd.Uint(), Keys: keyBuf.Pointer(), - Values: valueBuf.Pointer(), + Values: valuePtr, Count: uint32(count), InBatch: sys.NewSlicePointer(inBatch), OutBatch: sys.NewSlicePointer(cursor.opaque), @@ -1075,9 +1107,6 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i if err := keyBuf.Unmarshal(keysOut); err != nil { return 0, err } - if err := valueBuf.Unmarshal(valuesOut); err != nil { - return 0, err - } return int(attr.Count), sysErr } @@ -1088,29 +1117,24 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i // to a slice or buffer will not work. func (m *Map) BatchUpdate(keys, values interface{}, opts *BatchOptions) (int, error) { if m.typ.hasPerCPUValue() { - return 0, ErrNotSupported + return m.batchUpdatePerCPU(keys, values, opts) } - keysValue := reflect.ValueOf(keys) - if keysValue.Kind() != reflect.Slice { - return 0, fmt.Errorf("keys must be a slice") - } - valuesValue := reflect.ValueOf(values) - if valuesValue.Kind() != reflect.Slice { - return 0, fmt.Errorf("values must be a slice") - } - var ( - count = keysValue.Len() - valuePtr sys.Pointer - err error - ) - if count != valuesValue.Len() { - return 0, fmt.Errorf("keys and values must be the same length") + + count, err := batchCount(keys, values) + if err != nil { + return 0, err } - keyPtr, err := marshalMapSyscallInput(keys, count*int(m.keySize)) + + valuePtr, err := marshalMapSyscallInput(values, count*int(m.valueSize)) if err != nil { return 0, err } - valuePtr, err = marshalMapSyscallInput(values, count*int(m.valueSize)) + + return m.batchUpdate(count, keys, valuePtr, opts) +} + +func (m *Map) batchUpdate(count int, keys any, valuePtr sys.Pointer, opts *BatchOptions) (int, error) { + keyPtr, err := marshalMapSyscallInput(keys, count*int(m.keySize)) if err != nil { return 0, err } @@ -1137,17 +1161,28 @@ func (m *Map) BatchUpdate(keys, values interface{}, opts *BatchOptions) (int, er return int(attr.Count), nil } +func (m *Map) batchUpdatePerCPU(keys, values any, opts *BatchOptions) (int, error) { + count, err := sliceLen(keys) + if err != nil { + return 0, fmt.Errorf("keys: %w", err) + } + + valueBuf, err := marshalBatchPerCPUValue(values, count, int(m.valueSize)) + if err != nil { + return 0, err + } + + return m.batchUpdate(count, keys, sys.NewSlicePointer(valueBuf), opts) +} + // BatchDelete batch deletes entries in the map by keys. // "keys" must be of type slice, a pointer to a slice or buffer will not work. func (m *Map) BatchDelete(keys interface{}, opts *BatchOptions) (int, error) { - if m.typ.hasPerCPUValue() { - return 0, ErrNotSupported - } - keysValue := reflect.ValueOf(keys) - if keysValue.Kind() != reflect.Slice { - return 0, fmt.Errorf("keys must be a slice") + count, err := sliceLen(keys) + if err != nil { + return 0, fmt.Errorf("keys: %w", err) } - count := keysValue.Len() + keyPtr, err := marshalMapSyscallInput(keys, count*int(m.keySize)) if err != nil { return 0, fmt.Errorf("cannot marshal keys: %v", err) @@ -1174,6 +1209,24 @@ func (m *Map) BatchDelete(keys interface{}, opts *BatchOptions) (int, error) { return int(attr.Count), nil } +func batchCount(keys, values any) (int, error) { + keysLen, err := sliceLen(keys) + if err != nil { + return 0, fmt.Errorf("keys: %w", err) + } + + valuesLen, err := sliceLen(values) + if err != nil { + return 0, fmt.Errorf("values: %w", err) + } + + if keysLen != valuesLen { + return 0, fmt.Errorf("keys and values must have the same length") + } + + return keysLen, nil +} + // Iterate traverses a map. // // It's safe to create multiple iterators at the same time. @@ -1552,3 +1605,12 @@ func NewMapFromID(id MapID) (*Map, error) { return newMapFromFD(fd) } + +// sliceLen returns the length if the value is a slice or an error otherwise. +func sliceLen(slice any) (int, error) { + sliceValue := reflect.ValueOf(slice) + if sliceValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("%T is not a slice", slice) + } + return sliceValue.Len(), nil +} diff --git a/vendor/github.com/cilium/ebpf/marshalers.go b/vendor/github.com/cilium/ebpf/marshalers.go index d77a5fb81f7..57a0a8e88af 100644 --- a/vendor/github.com/cilium/ebpf/marshalers.go +++ b/vendor/github.com/cilium/ebpf/marshalers.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "reflect" + "slices" "unsafe" "github.com/cilium/ebpf/internal" @@ -43,44 +44,90 @@ func makeMapSyscallOutput(dst any, length int) sysenc.Buffer { return sysenc.SyscallOutput(dst, length) } -// marshalPerCPUValue encodes a slice containing one value per +// appendPerCPUSlice encodes a slice containing one value per // possible CPU into a buffer of bytes. // // Values are initialized to zero if the slice has less elements than CPUs. -func marshalPerCPUValue(slice any, elemLength int) (sys.Pointer, error) { +func appendPerCPUSlice(buf []byte, slice any, possibleCPUs, elemLength, alignedElemLength int) ([]byte, error) { sliceType := reflect.TypeOf(slice) if sliceType.Kind() != reflect.Slice { - return sys.Pointer{}, errors.New("per-CPU value requires slice") - } - - possibleCPUs, err := PossibleCPU() - if err != nil { - return sys.Pointer{}, err + return nil, errors.New("per-CPU value requires slice") } sliceValue := reflect.ValueOf(slice) sliceLen := sliceValue.Len() if sliceLen > possibleCPUs { - return sys.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs") + return nil, fmt.Errorf("per-CPU value greater than number of CPUs") } - alignedElemLength := internal.Align(elemLength, 8) - buf := make([]byte, alignedElemLength*possibleCPUs) - + // Grow increases the slice's capacity, _if_necessary_ + buf = slices.Grow(buf, alignedElemLength*possibleCPUs) for i := 0; i < sliceLen; i++ { elem := sliceValue.Index(i).Interface() elemBytes, err := sysenc.Marshal(elem, elemLength) if err != nil { - return sys.Pointer{}, err + return nil, err } - offset := i * alignedElemLength - elemBytes.CopyTo(buf[offset : offset+elemLength]) + buf = elemBytes.AppendTo(buf) + buf = append(buf, make([]byte, alignedElemLength-elemLength)...) + } + + // Ensure buf is zero-padded full size. + buf = append(buf, make([]byte, (possibleCPUs-sliceLen)*alignedElemLength)...) + + return buf, nil +} + +// marshalPerCPUValue encodes a slice containing one value per +// possible CPU into a buffer of bytes. +// +// Values are initialized to zero if the slice has less elements than CPUs. +func marshalPerCPUValue(slice any, elemLength int) (sys.Pointer, error) { + possibleCPUs, err := PossibleCPU() + if err != nil { + return sys.Pointer{}, err + } + + alignedElemLength := internal.Align(elemLength, 8) + buf := make([]byte, 0, alignedElemLength*possibleCPUs) + buf, err = appendPerCPUSlice(buf, slice, possibleCPUs, elemLength, alignedElemLength) + if err != nil { + return sys.Pointer{}, err } return sys.NewSlicePointer(buf), nil } +// marshalBatchPerCPUValue encodes a batch-sized slice of slices containing +// one value per possible CPU into a buffer of bytes. +func marshalBatchPerCPUValue(slice any, batchLen, elemLength int) ([]byte, error) { + sliceType := reflect.TypeOf(slice) + if sliceType.Kind() != reflect.Slice { + return nil, fmt.Errorf("batch value requires a slice") + } + sliceValue := reflect.ValueOf(slice) + + possibleCPUs, err := PossibleCPU() + if err != nil { + return nil, err + } + if sliceValue.Len() != batchLen*possibleCPUs { + return nil, fmt.Errorf("per-CPU slice has incorrect length, expected %d, got %d", + batchLen*possibleCPUs, sliceValue.Len()) + } + alignedElemLength := internal.Align(elemLength, 8) + buf := make([]byte, 0, batchLen*alignedElemLength*possibleCPUs) + for i := 0; i < batchLen; i++ { + batch := sliceValue.Slice(i*possibleCPUs, (i+1)*possibleCPUs).Interface() + buf, err = appendPerCPUSlice(buf, batch, possibleCPUs, elemLength, alignedElemLength) + if err != nil { + return nil, fmt.Errorf("batch %d: %w", i, err) + } + } + return buf, nil +} + // unmarshalPerCPUValue decodes a buffer into a slice containing one value per // possible CPU. // @@ -123,6 +170,41 @@ func unmarshalPerCPUValue(slice any, elemLength int, buf []byte) error { buf = buf[stride:] } + return nil +} + +// unmarshalBatchPerCPUValue decodes a buffer into a batch-sized slice +// containing one value per possible CPU. +// +// slice must have length batchLen * PossibleCPUs(). +func unmarshalBatchPerCPUValue(slice any, batchLen, elemLength int, buf []byte) error { + sliceType := reflect.TypeOf(slice) + if sliceType.Kind() != reflect.Slice { + return fmt.Errorf("batch requires a slice") + } + sliceValue := reflect.ValueOf(slice) + possibleCPUs, err := PossibleCPU() + if err != nil { + return err + } + if sliceValue.Len() != batchLen*possibleCPUs { + return fmt.Errorf("per-CPU slice has incorrect length, expected %d, got %d", + sliceValue.Len(), batchLen*possibleCPUs) + } + + fullValueSize := possibleCPUs * internal.Align(elemLength, 8) + if len(buf) != batchLen*fullValueSize { + return fmt.Errorf("input buffer has incorrect length, expected %d, got %d", + len(buf), batchLen*fullValueSize) + } + + for i := 0; i < batchLen; i++ { + elem := sliceValue.Slice(i*possibleCPUs, (i+1)*possibleCPUs).Interface() + if err := unmarshalPerCPUValue(elem, elemLength, buf[:fullValueSize]); err != nil { + return fmt.Errorf("batch %d: %w", i, err) + } + buf = buf[fullValueSize:] + } return nil } diff --git a/vendor/github.com/cilium/ebpf/perf/reader.go b/vendor/github.com/cilium/ebpf/perf/reader.go index 1aec79d50b2..3c820708c72 100644 --- a/vendor/github.com/cilium/ebpf/perf/reader.go +++ b/vendor/github.com/cilium/ebpf/perf/reader.go @@ -231,11 +231,12 @@ func NewReaderWithOptions(array *ebpf.Map, perCPUBuffer int, opts ReaderOptions) pauseFds = append(pauseFds, -1) continue } - bufferSize = ring.size() if err != nil { return nil, fmt.Errorf("failed to create perf ring for CPU %d: %v", i, err) } + + bufferSize = ring.size() rings = append(rings, ring) pauseFds = append(pauseFds, ring.fd) diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go index e904abc54c4..611e087a9c5 100644 --- a/vendor/github.com/cilium/ebpf/prog.go +++ b/vendor/github.com/cilium/ebpf/prog.go @@ -53,7 +53,7 @@ type ProgramOptions struct { // verifier output enabled. Upon error, the program load will be repeated // with LogLevelBranch and the given (or default) LogSize value. // - // Setting this to a non-zero value will unconditionally enable the verifier + // Unless LogDisabled is set, setting this to a non-zero value will enable the verifier // log, populating the [ebpf.Program.VerifierLog] field on successful loads // and including detailed verifier errors if the program is rejected. This // will always allocate an output buffer, but will result in only a single diff --git a/vendor/github.com/cilium/ebpf/run-tests.sh b/vendor/github.com/cilium/ebpf/run-tests.sh index d48e97adc93..9f435613903 100644 --- a/vendor/github.com/cilium/ebpf/run-tests.sh +++ b/vendor/github.com/cilium/ebpf/run-tests.sh @@ -14,6 +14,8 @@ set -euo pipefail script="$(realpath "$0")" readonly script +source "$(dirname "$script")/testdata/sh/lib.sh" + quote_env() { for var in "$@"; do if [ -v "$var" ]; then @@ -120,26 +122,6 @@ fi input="$(mktemp -d)" readonly input -readonly docker="${CONTAINER_ENGINE:-docker}" - -extract_oci_image() { - local image_name=$1 - local target_directory=$2 - - echo -n "Fetching $image_name... " - - # We abuse the --output flag of docker buildx to obtain a copy of the image. - # This is simpler than creating a temporary container and using docker cp. - # It also automatically fetches the image for us if necessary. - if ! echo "FROM $image_name" | "$docker" buildx build --quiet --pull --output="$target_directory" - &> /dev/null; then - echo "failed" - return 1 - fi - - echo "ok" - return 0 -} - if [[ -f "${1}" ]]; then # First argument is a local file. readonly kernel="${1}" diff --git a/vendor/modules.txt b/vendor/modules.txt index 93c6c72ebdc..c5a8e3ea999 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -209,8 +209,8 @@ github.com/cilium/cilium/pkg/wireguard/types # github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3 ## explicit; go 1.18 github.com/cilium/dns -# github.com/cilium/ebpf v0.12.4-0.20231215112452-00c0cb05d35c -## explicit; go 1.20 +# github.com/cilium/ebpf v0.12.4-0.20240214170503-b0728bcadcd9 +## explicit; go 1.21.0 github.com/cilium/ebpf github.com/cilium/ebpf/asm github.com/cilium/ebpf/btf