diff --git a/go.mod b/go.mod index f383213cf..0965eabed 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/netobserv/gopipes v0.3.0 github.com/netobserv/loki-client-go v0.0.0-20251014110557-40bc8d2e6cf3 - github.com/netobserv/netobserv-ebpf-agent v1.10.0-community + github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e github.com/netsampler/goflow2 v1.3.7 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.23.2 @@ -66,7 +66,7 @@ require ( github.com/cenkalti/hub v1.0.2 // indirect github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cilium/ebpf v0.19.0 // indirect + github.com/cilium/ebpf v0.20.0 // indirect github.com/containernetworking/cni v1.1.2 // indirect github.com/containernetworking/plugins v1.2.0 // indirect github.com/coreos/go-iptables v0.6.0 // indirect diff --git a/go.sum b/go.sum index 3f450e26c..8c0fb2cd5 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.19.0 h1:Ro/rE64RmFBeA9FGjcTc+KmCeY6jXmryu6FfnzPRIao= -github.com/cilium/ebpf v0.19.0/go.mod h1:fLCgMo3l8tZmAdM3B2XqdFzXBpwkcSTroaVqN08OWVY= +github.com/cilium/ebpf v0.20.0 h1:atwWj9d3NffHyPZzVlx3hmw1on5CLe9eljR8VuHTwhM= +github.com/cilium/ebpf v0.20.0/go.mod h1:pzLjFymM+uZPLk/IXZUL63xdx5VXEo+enTzxkZXdycw= github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/plugins v1.2.0 h1:SWgg3dQG1yzUo4d9iD8cwSVh1VqI+bP7mkPDoSfP9VU= @@ -257,8 +257,8 @@ github.com/netobserv/gopipes v0.3.0 h1:IYmPnnAVCdSK7VmHmpFhrVBOEm45qpgbZmJz1sSW+ github.com/netobserv/gopipes v0.3.0/go.mod h1:N7/Gz05EOF0CQQSKWsv3eof22Cj2PB08Pbttw98YFYU= github.com/netobserv/loki-client-go v0.0.0-20251014110557-40bc8d2e6cf3 h1:rxQipq0xpoiao7ifls/82JCcOVALC4n08ppTLCUFGL4= github.com/netobserv/loki-client-go v0.0.0-20251014110557-40bc8d2e6cf3/go.mod h1:Zb/jtD3Lnu88Poo+jnhTASzxYnvncmHOoZaT93xQjJ8= -github.com/netobserv/netobserv-ebpf-agent v1.10.0-community h1:XLauF3k+G2RV2EgHvYK+r3zq0FRm+k7P3hq0I0J6GzE= -github.com/netobserv/netobserv-ebpf-agent v1.10.0-community/go.mod h1:n75b6DyE/soLE794JlxILqt8rd/KoPfSoUs1WN4jzqg= +github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e h1:hGJIbcfTbzjpuZ9K7hVwD/6+KijR0TfqJjmXeigQELc= +github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e/go.mod h1:ZQf6WKnhdfdaR5PQ/Fc99l4/doL94OQeTkQknwFiQZo= github.com/netsampler/goflow2 v1.3.7 h1:XZaTy8kkMnGXpJ9hS3KbO1McyrFTpVNhVFEx9rNhMmc= github.com/netsampler/goflow2 v1.3.7/go.mod h1:4UZsVGVAs//iMCptUHn3WNScztJeUhZH7kDW2+/vDdQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/vendor/github.com/cilium/ebpf/Makefile b/vendor/github.com/cilium/ebpf/Makefile index 45462e8d5..4f53b37f3 100644 --- a/vendor/github.com/cilium/ebpf/Makefile +++ b/vendor/github.com/cilium/ebpf/Makefile @@ -49,6 +49,7 @@ TARGETS := \ testdata/constants \ testdata/errors \ testdata/variables \ + testdata/arena \ btf/testdata/relocs \ btf/testdata/relocs_read \ btf/testdata/relocs_read_tgt \ @@ -91,8 +92,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 -run "internal/cmd/gentypes" ./... - go generate -skip "internal/cmd/gentypes" ./... + go generate -run "gentypes" ./... + go generate -skip "gentypes" ./... testdata/loader-%-el.elf: testdata/loader.c $* $(CFLAGS) -target bpfel -c $< -o $@ diff --git a/vendor/github.com/cilium/ebpf/README.md b/vendor/github.com/cilium/ebpf/README.md index d471ae769..01a154c61 100644 --- a/vendor/github.com/cilium/ebpf/README.md +++ b/vendor/github.com/cilium/ebpf/README.md @@ -59,10 +59,11 @@ This library includes the following packages: * A version of Go that is [supported by upstream](https://golang.org/doc/devel/release.html#policy) -* Linux: CI is run against kernel.org LTS releases. >= 4.4 should work but EOL'ed +* Linux (amd64, arm64): CI is run against kernel.org LTS releases. >= 4.4 should work but EOL'ed versions are not supported. -* Windows: CI is run against Windows Server 2022. Only the latest eBPF for Windows +* Windows (amd64): CI is run against Windows Server 2022. Only the latest eBPF for Windows release is supported. +* Other architectures are best effort. 32bit arches are not supported. ## License diff --git a/vendor/github.com/cilium/ebpf/asm/alu.go b/vendor/github.com/cilium/ebpf/asm/alu.go index 282233d32..a4ae72212 100644 --- a/vendor/github.com/cilium/ebpf/asm/alu.go +++ b/vendor/github.com/cilium/ebpf/asm/alu.go @@ -1,6 +1,6 @@ package asm -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output alu_string.go -type=Source,Endianness,ALUOp +//go:generate go tool stringer -output alu_string.go -type=Source,Endianness,ALUOp // Source of ALU / ALU64 / Branch operations // diff --git a/vendor/github.com/cilium/ebpf/asm/func.go b/vendor/github.com/cilium/ebpf/asm/func.go index 5ee4e954f..fe75c7578 100644 --- a/vendor/github.com/cilium/ebpf/asm/func.go +++ b/vendor/github.com/cilium/ebpf/asm/func.go @@ -2,7 +2,7 @@ package asm import "github.com/cilium/ebpf/internal/platform" -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output func_string.go -type=BuiltinFunc +//go:generate go tool stringer -output func_string.go -type=BuiltinFunc // BuiltinFunc is a built-in eBPF function. type BuiltinFunc uint32 diff --git a/vendor/github.com/cilium/ebpf/asm/jump.go b/vendor/github.com/cilium/ebpf/asm/jump.go index 2738d736b..a14bc4c89 100644 --- a/vendor/github.com/cilium/ebpf/asm/jump.go +++ b/vendor/github.com/cilium/ebpf/asm/jump.go @@ -1,6 +1,6 @@ package asm -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output jump_string.go -type=JumpOp +//go:generate go tool stringer -output jump_string.go -type=JumpOp // JumpOp affect control flow. // diff --git a/vendor/github.com/cilium/ebpf/asm/load_store.go b/vendor/github.com/cilium/ebpf/asm/load_store.go index 29571a74e..a32a9b318 100644 --- a/vendor/github.com/cilium/ebpf/asm/load_store.go +++ b/vendor/github.com/cilium/ebpf/asm/load_store.go @@ -2,7 +2,7 @@ package asm import "fmt" -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output load_store_string.go -type=Mode,Size +//go:generate go tool stringer -output load_store_string.go -type=Mode,Size // Mode for load and store operations // diff --git a/vendor/github.com/cilium/ebpf/asm/opcode.go b/vendor/github.com/cilium/ebpf/asm/opcode.go index c82a1f8fb..9b2f80f0a 100644 --- a/vendor/github.com/cilium/ebpf/asm/opcode.go +++ b/vendor/github.com/cilium/ebpf/asm/opcode.go @@ -5,7 +5,7 @@ import ( "strings" ) -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output opcode_string.go -type=Class +//go:generate go tool stringer -output opcode_string.go -type=Class // Class of operations // diff --git a/vendor/github.com/cilium/ebpf/asm/opcode_string.go b/vendor/github.com/cilium/ebpf/asm/opcode_string.go index 58bc3e7e7..07825e0dd 100644 --- a/vendor/github.com/cilium/ebpf/asm/opcode_string.go +++ b/vendor/github.com/cilium/ebpf/asm/opcode_string.go @@ -23,8 +23,9 @@ const _Class_name = "LdClassLdXClassStClassStXClassALUClassJumpClassJump32ClassA var _Class_index = [...]uint8{0, 7, 15, 22, 30, 38, 47, 58, 68} func (i Class) String() string { - if i >= Class(len(_Class_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_Class_index)-1 { return "Class(" + strconv.FormatInt(int64(i), 10) + ")" } - return _Class_name[_Class_index[i]:_Class_index[i+1]] + return _Class_name[_Class_index[idx]:_Class_index[idx+1]] } diff --git a/vendor/github.com/cilium/ebpf/btf/btf.go b/vendor/github.com/cilium/ebpf/btf/btf.go index d26931a04..41e1f8a6f 100644 --- a/vendor/github.com/cilium/ebpf/btf/btf.go +++ b/vendor/github.com/cilium/ebpf/btf/btf.go @@ -1,9 +1,7 @@ package btf import ( - "bufio" "debug/elf" - "encoding/binary" "errors" "fmt" "io" @@ -69,11 +67,12 @@ func LoadSpec(file string) (*Spec, error) { func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { file, err := internal.NewSafeELFFile(rd) if err != nil { - if bo := guessRawBTFByteOrder(rd); bo != nil { - return loadRawSpec(io.NewSectionReader(rd, 0, math.MaxInt64), bo, nil) + raw, err := io.ReadAll(io.NewSectionReader(rd, 0, math.MaxInt64)) + if err != nil { + return nil, fmt.Errorf("read raw BTF: %w", err) } - return nil, err + return loadRawSpec(raw, nil) } return loadSpecFromELF(file) @@ -170,15 +169,20 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) { return nil, err } - if btfSection.ReaderAt == nil { - return nil, fmt.Errorf("compressed BTF is not supported") + rawBTF, err := btfSection.Data() + if err != nil { + return nil, fmt.Errorf("reading .BTF section: %w", err) } - spec, err := loadRawSpec(btfSection.ReaderAt, file.ByteOrder, nil) + spec, err := loadRawSpec(rawBTF, nil) if err != nil { return nil, err } + if spec.decoder.byteOrder != file.ByteOrder { + return nil, fmt.Errorf("BTF byte order %s does not match ELF byte order %s", spec.decoder.byteOrder, file.ByteOrder) + } + spec.elf = &elfData{ sectionSizes, offsets, @@ -188,7 +192,7 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) { return spec, nil } -func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error) { +func loadRawSpec(btf []byte, base *Spec) (*Spec, error) { var ( baseDecoder *decoder baseStrings *stringTable @@ -200,25 +204,32 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error baseStrings = base.strings } - buf := internal.NewBufferedSectionReader(btf, 0, math.MaxInt64) - header, err := parseBTFHeader(buf, bo) + header, bo, err := parseBTFHeader(btf) if err != nil { return nil, fmt.Errorf("parsing .BTF header: %v", err) } - stringsSection := io.NewSectionReader(btf, header.stringStart(), int64(header.StringLen)) - rawStrings, err := readStringTable(stringsSection, baseStrings) + if header.HdrLen > uint32(len(btf)) { + return nil, fmt.Errorf("BTF header length is out of bounds") + } + btf = btf[header.HdrLen:] + + if int(header.StringOff+header.StringLen) > len(btf) { + return nil, fmt.Errorf("string table is out of bounds") + } + stringsSection := btf[header.StringOff : header.StringOff+header.StringLen] + + rawStrings, err := newStringTable(stringsSection, baseStrings) if err != nil { return nil, fmt.Errorf("read string section: %w", err) } - typesSection := io.NewSectionReader(btf, header.typeStart(), int64(header.TypeLen)) - rawTypes := make([]byte, header.TypeLen) - if _, err := io.ReadFull(typesSection, rawTypes); err != nil { - return nil, fmt.Errorf("read type section: %w", err) + if int(header.TypeOff+header.TypeLen) > len(btf) { + return nil, fmt.Errorf("types section is out of bounds") } + typesSection := btf[header.TypeOff : header.TypeOff+header.TypeLen] - decoder, err := newDecoder(rawTypes, bo, rawStrings, baseDecoder) + decoder, err := newDecoder(typesSection, bo, rawStrings, baseDecoder) if err != nil { return nil, err } @@ -226,21 +237,6 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error return &Spec{decoder, nil}, nil } -func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder { - buf := new(bufio.Reader) - for _, bo := range []binary.ByteOrder{ - binary.LittleEndian, - binary.BigEndian, - } { - buf.Reset(io.NewSectionReader(r, 0, math.MaxInt64)) - if _, err := parseBTFHeader(buf, bo); err == nil { - return bo - } - } - - return nil -} - // fixupDatasec attempts to patch up missing info in Datasecs and its members by // supplementing them with information from the ELF headers and symbol table. func (elf *elfData) fixupDatasec(typ Type) error { @@ -500,12 +496,31 @@ func (s *Spec) TypeByName(name string, typ interface{}) error { return nil } +// LoadSplitSpec loads split BTF from the given file. +// +// Types from base are used to resolve references in the split BTF. +// The returned Spec only contains types from the split BTF, not from the base. +func LoadSplitSpec(file string, base *Spec) (*Spec, error) { + fh, err := os.Open(file) + if err != nil { + return nil, err + } + defer fh.Close() + + return LoadSplitSpecFromReader(fh, base) +} + // LoadSplitSpecFromReader loads split BTF from a reader. // // Types from base are used to resolve references in the split BTF. // The returned Spec only contains types from the split BTF, not from the base. func LoadSplitSpecFromReader(r io.ReaderAt, base *Spec) (*Spec, error) { - return loadRawSpec(r, internal.NativeEndian, base) + raw, err := io.ReadAll(io.NewSectionReader(r, 0, math.MaxInt64)) + if err != nil { + return nil, fmt.Errorf("read raw BTF: %w", err) + } + + return loadRawSpec(raw, base) } // All iterates over all types. diff --git a/vendor/github.com/cilium/ebpf/btf/btf_types.go b/vendor/github.com/cilium/ebpf/btf/btf_types.go index d20a31969..c957f5970 100644 --- a/vendor/github.com/cilium/ebpf/btf/btf_types.go +++ b/vendor/github.com/cilium/ebpf/btf/btf_types.go @@ -4,13 +4,10 @@ import ( "encoding/binary" "errors" "fmt" - "io" "unsafe" - - "github.com/cilium/ebpf/internal" ) -//go:generate go run golang.org/x/tools/cmd/stringer@latest -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage,btfKind +//go:generate go tool stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage,btfKind // btfKind describes a Type. type btfKind uint8 @@ -87,47 +84,49 @@ type btfHeader struct { StringLen uint32 } -// typeStart returns the offset from the beginning of the .BTF section -// to the start of its type entries. -func (h *btfHeader) typeStart() int64 { - return int64(h.HdrLen + h.TypeOff) -} - -// stringStart returns the offset from the beginning of the .BTF section -// to the start of its string table. -func (h *btfHeader) stringStart() int64 { - return int64(h.HdrLen + h.StringOff) -} - // parseBTFHeader parses the header of the .BTF section. -func parseBTFHeader(r io.Reader, bo binary.ByteOrder) (*btfHeader, error) { +func parseBTFHeader(buf []byte) (*btfHeader, binary.ByteOrder, error) { var header btfHeader - if err := binary.Read(r, bo, &header); err != nil { - return nil, fmt.Errorf("can't read header: %v", err) + var bo binary.ByteOrder + for _, order := range []binary.ByteOrder{binary.LittleEndian, binary.BigEndian} { + n, err := binary.Decode(buf, order, &header) + if err != nil { + return nil, nil, fmt.Errorf("read header: %v", err) + } + + if header.Magic != btfMagic { + continue + } + + buf = buf[n:] + bo = order + break } - if header.Magic != btfMagic { - return nil, fmt.Errorf("incorrect magic value %v", header.Magic) + if bo == nil { + return nil, nil, fmt.Errorf("no valid BTF header") } if header.Version != 1 { - return nil, fmt.Errorf("unexpected version %v", header.Version) + return nil, nil, fmt.Errorf("unexpected version %v", header.Version) } if header.Flags != 0 { - return nil, fmt.Errorf("unsupported flags %v", header.Flags) + return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags) } remainder := int64(header.HdrLen) - int64(binary.Size(&header)) if remainder < 0 { - return nil, errors.New("header length shorter than btfHeader size") + return nil, nil, errors.New("header length shorter than btfHeader size") } - if _, err := io.CopyN(internal.DiscardZeroes{}, r, remainder); err != nil { - return nil, fmt.Errorf("header padding: %v", err) + for _, b := range buf[:remainder] { + if b != 0 { + return nil, nil, errors.New("header contains non-zero trailer") + } } - return &header, nil + return &header, bo, nil } // btfType is equivalent to struct btf_type in Documentation/bpf/btf.rst. diff --git a/vendor/github.com/cilium/ebpf/btf/btf_types_string.go b/vendor/github.com/cilium/ebpf/btf/btf_types_string.go index b7a1b80d1..a9d2d82b6 100644 --- a/vendor/github.com/cilium/ebpf/btf/btf_types_string.go +++ b/vendor/github.com/cilium/ebpf/btf/btf_types_string.go @@ -18,10 +18,11 @@ const _FuncLinkage_name = "staticglobalextern" var _FuncLinkage_index = [...]uint8{0, 6, 12, 18} func (i FuncLinkage) String() string { - if i < 0 || i >= FuncLinkage(len(_FuncLinkage_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_FuncLinkage_index)-1 { return "FuncLinkage(" + strconv.FormatInt(int64(i), 10) + ")" } - return _FuncLinkage_name[_FuncLinkage_index[i]:_FuncLinkage_index[i+1]] + return _FuncLinkage_name[_FuncLinkage_index[idx]:_FuncLinkage_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -37,10 +38,11 @@ const _VarLinkage_name = "staticglobalextern" var _VarLinkage_index = [...]uint8{0, 6, 12, 18} func (i VarLinkage) String() string { - if i < 0 || i >= VarLinkage(len(_VarLinkage_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_VarLinkage_index)-1 { return "VarLinkage(" + strconv.FormatInt(int64(i), 10) + ")" } - return _VarLinkage_name[_VarLinkage_index[i]:_VarLinkage_index[i+1]] + return _VarLinkage_name[_VarLinkage_index[idx]:_VarLinkage_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -73,8 +75,9 @@ const _btfKind_name = "UnknownIntPointerArrayStructUnionEnumForwardTypedefVolati var _btfKind_index = [...]uint8{0, 7, 10, 17, 22, 28, 33, 37, 44, 51, 59, 64, 72, 76, 85, 88, 95, 100, 107, 114, 120} func (i btfKind) String() string { - if i >= btfKind(len(_btfKind_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_btfKind_index)-1 { return "btfKind(" + strconv.FormatInt(int64(i), 10) + ")" } - return _btfKind_name[_btfKind_index[i]:_btfKind_index[i+1]] + return _btfKind_name[_btfKind_index[idx]:_btfKind_index[idx+1]] } diff --git a/vendor/github.com/cilium/ebpf/btf/handle.go b/vendor/github.com/cilium/ebpf/btf/handle.go index 2e483e9d9..89e09a3b8 100644 --- a/vendor/github.com/cilium/ebpf/btf/handle.go +++ b/vendor/github.com/cilium/ebpf/btf/handle.go @@ -1,7 +1,6 @@ package btf import ( - "bytes" "errors" "fmt" "math" @@ -153,7 +152,7 @@ func (h *Handle) Spec(base *Spec) (*Spec, error) { return nil, fmt.Errorf("missing base types") } - return loadRawSpec(bytes.NewReader(btfBuffer), internal.NativeEndian, base) + return loadRawSpec(btfBuffer, base) } // Close destroys the handle. diff --git a/vendor/github.com/cilium/ebpf/btf/kernel.go b/vendor/github.com/cilium/ebpf/btf/kernel.go index fcbe650ce..bb7368bfc 100644 --- a/vendor/github.com/cilium/ebpf/btf/kernel.go +++ b/vendor/github.com/cilium/ebpf/btf/kernel.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "slices" "sort" "sync" @@ -12,6 +13,7 @@ import ( "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/linux" "github.com/cilium/ebpf/internal/platform" + "github.com/cilium/ebpf/internal/unix" ) // globalCache amortises decoding BTF across all users of the library. @@ -58,6 +60,11 @@ func loadCachedKernelSpec() (*Spec, error) { globalCache.Lock() defer globalCache.Unlock() + // check again, to prevent race between multiple callers + if globalCache.kernel != nil { + return globalCache.kernel, nil + } + spec, err := loadKernelSpec() if err != nil { return nil, err @@ -101,6 +108,11 @@ func loadCachedKernelModuleSpec(module string) (*Spec, error) { globalCache.Lock() defer globalCache.Unlock() + // check again, to prevent race between multiple callers + if spec := globalCache.modules[module]; spec != nil { + return spec, nil + } + spec, err = loadKernelModuleSpec(module, base) if err != nil { return nil, err @@ -110,7 +122,7 @@ func loadCachedKernelModuleSpec(module string) (*Spec, error) { return spec, nil } -func loadKernelSpec() (_ *Spec, _ error) { +func loadKernelSpec() (*Spec, error) { if platform.IsWindows { return nil, internal.ErrNotSupportedOnOS } @@ -119,8 +131,31 @@ func loadKernelSpec() (_ *Spec, _ error) { if err == nil { defer fh.Close() - spec, err := loadRawSpec(fh, internal.NativeEndian, nil) - return spec, err + info, err := fh.Stat() + if err != nil { + return nil, fmt.Errorf("stat vmlinux: %w", err) + } + + // NB: It's not safe to mmap arbitrary files because mmap(2) doesn't + // guarantee that changes made after mmap are not visible in the mapping. + // + // This is not a problem for vmlinux, since it is always a read-only file. + raw, err := unix.Mmap(int(fh.Fd()), 0, int(info.Size()), unix.PROT_READ, unix.MAP_PRIVATE) + if err != nil { + return LoadSplitSpecFromReader(fh, nil) + } + + spec, err := loadRawSpec(raw, nil) + if err != nil { + _ = unix.Munmap(raw) + return nil, fmt.Errorf("load vmlinux: %w", err) + } + + runtime.AddCleanup(spec.decoder.sharedBuf, func(b []byte) { + _ = unix.Munmap(b) + }, raw) + + return spec, nil } file, err := findVMLinux() @@ -149,7 +184,7 @@ func loadKernelModuleSpec(module string, base *Spec) (*Spec, error) { } defer fh.Close() - return loadRawSpec(fh, internal.NativeEndian, base) + return LoadSplitSpecFromReader(fh, base) } // findVMLinux scans multiple well-known paths for vmlinux kernel images. @@ -190,9 +225,9 @@ func findVMLinux() (*os.File, error) { // // It is not safe for concurrent use. type Cache struct { - KernelTypes *Spec - ModuleTypes map[string]*Spec - LoadedModules []string + kernelTypes *Spec + moduleTypes map[string]*Spec + loadedModules []string } // NewCache creates a new Cache. @@ -227,13 +262,13 @@ func NewCache() *Cache { // Kernel is equivalent to [LoadKernelSpec], except that repeated calls do // not copy the Spec. func (c *Cache) Kernel() (*Spec, error) { - if c.KernelTypes != nil { - return c.KernelTypes, nil + if c.kernelTypes != nil { + return c.kernelTypes, nil } var err error - c.KernelTypes, err = LoadKernelSpec() - return c.KernelTypes, err + c.kernelTypes, err = LoadKernelSpec() + return c.kernelTypes, err } // Module is equivalent to [LoadKernelModuleSpec], except that repeated calls do @@ -241,12 +276,12 @@ func (c *Cache) Kernel() (*Spec, error) { // // All modules also share the return value of [Kernel] as their base. func (c *Cache) Module(name string) (*Spec, error) { - if spec := c.ModuleTypes[name]; spec != nil { + if spec := c.moduleTypes[name]; spec != nil { return spec, nil } - if c.ModuleTypes == nil { - c.ModuleTypes = make(map[string]*Spec) + if c.moduleTypes == nil { + c.moduleTypes = make(map[string]*Spec) } base, err := c.Kernel() @@ -267,14 +302,14 @@ func (c *Cache) Module(name string) (*Spec, error) { } spec = &Spec{decoder: decoder} - c.ModuleTypes[name] = spec + c.moduleTypes[name] = spec return spec, err } // Modules returns a sorted list of all loaded modules. func (c *Cache) Modules() ([]string, error) { - if c.LoadedModules != nil { - return c.LoadedModules, nil + if c.loadedModules != nil { + return c.loadedModules, nil } btfDir, err := os.Open("/sys/kernel/btf") @@ -293,6 +328,6 @@ func (c *Cache) Modules() ([]string, error) { }) sort.Strings(entries) - c.LoadedModules = entries + c.loadedModules = entries return entries, nil } diff --git a/vendor/github.com/cilium/ebpf/btf/strings.go b/vendor/github.com/cilium/ebpf/btf/strings.go index d09151c0e..482f93bef 100644 --- a/vendor/github.com/cilium/ebpf/btf/strings.go +++ b/vendor/github.com/cilium/ebpf/btf/strings.go @@ -10,7 +10,7 @@ import ( "sync" ) -// stringTable is contains a sequence of null-terminated strings. +// stringTable contains a sequence of null-terminated strings. // // It is safe for concurrent use. type stringTable struct { @@ -28,28 +28,30 @@ type sizedReader interface { } func readStringTable(r sizedReader, base *stringTable) (*stringTable, error) { - // When parsing split BTF's string table, the first entry offset is derived - // from the last entry offset of the base BTF. - firstStringOffset := uint32(0) - if base != nil { - firstStringOffset = uint32(len(base.bytes)) - } - bytes := make([]byte, r.Size()) if _, err := io.ReadFull(r, bytes); err != nil { return nil, err } - if len(bytes) == 0 { - return nil, errors.New("string table is empty") - } + return newStringTable(bytes, base) +} - if bytes[len(bytes)-1] != 0 { - return nil, errors.New("string table isn't null terminated") +func newStringTable(bytes []byte, base *stringTable) (*stringTable, error) { + // When parsing split BTF's string table, the first entry offset is derived + // from the last entry offset of the base BTF. + firstStringOffset := uint32(0) + if base != nil { + firstStringOffset = uint32(len(base.bytes)) } - if firstStringOffset == 0 && bytes[0] != 0 { - return nil, errors.New("first item in string table is non-empty") + if len(bytes) > 0 { + if bytes[len(bytes)-1] != 0 { + return nil, errors.New("string table isn't null terminated") + } + + if firstStringOffset == 0 && bytes[0] != 0 { + return nil, errors.New("first item in string table is non-empty") + } } return &stringTable{base: base, bytes: bytes}, nil diff --git a/vendor/github.com/cilium/ebpf/btf/unmarshal.go b/vendor/github.com/cilium/ebpf/btf/unmarshal.go index fdcf583da..26ae320d2 100644 --- a/vendor/github.com/cilium/ebpf/btf/unmarshal.go +++ b/vendor/github.com/cilium/ebpf/btf/unmarshal.go @@ -13,13 +13,22 @@ import ( "sync" ) +// sharedBuf is a buffer which may be shared between multiple decoders. +// +// It must not be modified. Some sharedBuf may be backed by an mmap-ed file, in +// which case the sharedBuf has a finalizer. sharedBuf must therefore always be +// passed as a pointer. +type sharedBuf struct { + raw []byte +} + type decoder struct { // Immutable fields, may be shared. base *decoder byteOrder binary.ByteOrder - raw []byte - strings *stringTable + *sharedBuf + strings *stringTable // The ID for offsets[0]. firstTypeID TypeID // Map from TypeID to offset of the marshaled data in raw. Contains an entry @@ -121,7 +130,7 @@ func newDecoder(raw []byte, bo binary.ByteOrder, strings *stringTable, base *dec return &decoder{ base, bo, - raw, + &sharedBuf{raw}, strings, firstTypeID, offsets, @@ -177,7 +186,7 @@ func rebaseDecoder(d *decoder, base *decoder) (*decoder, error) { return &decoder{ base, d.byteOrder, - d.raw, + d.sharedBuf, d.strings, d.firstTypeID, d.offsets, @@ -220,7 +229,7 @@ func (d *decoder) copy(copiedTypes map[Type]Type) *decoder { return &decoder{ d.base.copy(copiedTypes), d.byteOrder, - d.raw, + d.sharedBuf, d.strings, d.firstTypeID, d.offsets, diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go index 77476bd67..f99f354d4 100644 --- a/vendor/github.com/cilium/ebpf/collection.go +++ b/vendor/github.com/cilium/ebpf/collection.go @@ -6,6 +6,8 @@ import ( "fmt" "path/filepath" "reflect" + "runtime" + "slices" "strings" "github.com/cilium/ebpf/asm" @@ -437,7 +439,7 @@ func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collec make(map[string]*Map), make(map[string]*Program), make(map[string]*Variable), - newBTFCache(&opts.Programs), + btf.NewCache(), }, nil } @@ -445,20 +447,6 @@ func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collec // during individual program loading. Since we have less context available // at those stages, we batch the lookups here instead to avoid redundant work. func populateKallsyms(progs map[string]*ProgramSpec) error { - // Look up associated kernel modules for all symbols referenced by - // ProgramSpec.AttachTo for program types that support attaching to kmods. - mods := make(map[string]string) - for _, p := range progs { - if p.AttachTo != "" && p.targetsKernelModule() { - mods[p.AttachTo] = "" - } - } - if len(mods) != 0 { - if err := kallsyms.AssignModules(mods); err != nil { - return fmt.Errorf("getting modules from kallsyms: %w", err) - } - } - // Look up addresses of all kernel symbols referenced by all programs. addrs := make(map[string]uint64) for _, p := range progs { @@ -526,7 +514,7 @@ func (cl *collectionLoader) loadMap(mapName string) (*Map, error) { return m, nil } - m, err := newMapWithOptions(mapSpec, cl.opts.Maps) + m, err := newMapWithOptions(mapSpec, cl.opts.Maps, cl.types) if err != nil { return nil, fmt.Errorf("map %s: %w", mapName, err) } @@ -595,6 +583,7 @@ func (cl *collectionLoader) loadProgram(progName string) (*Program, error) { } cl.programs[progName] = prog + return prog, nil } @@ -702,6 +691,13 @@ func (cl *collectionLoader) populateDeferredMaps() error { } } + if mapSpec.Type == StructOpsMap { + // populate StructOps data into `kernVData` + if err := cl.populateStructOps(m, mapSpec); err != nil { + return err + } + } + // Populate and freeze the map if specified. if err := m.finalize(mapSpec); err != nil { return fmt.Errorf("populating map %s: %w", mapName, err) @@ -711,6 +707,97 @@ func (cl *collectionLoader) populateDeferredMaps() error { return nil } +// populateStructOps translates the user struct bytes into the kernel value struct +// layout for a struct_ops map and writes the result back to mapSpec.Contents[0]. +func (cl *collectionLoader) populateStructOps(m *Map, mapSpec *MapSpec) error { + userType, ok := btf.As[*btf.Struct](mapSpec.Value) + if !ok { + return fmt.Errorf("value should be a *Struct") + } + + userData, ok := mapSpec.Contents[0].Value.([]byte) + if !ok { + return fmt.Errorf("value should be an array of byte") + } + if len(userData) < int(userType.Size) { + return fmt.Errorf("user data too short: have %d, need at least %d", len(userData), userType.Size) + } + + vType, _, module, err := structOpsFindTarget(userType, cl.types) + if err != nil { + return fmt.Errorf("struct_ops value type %q: %w", userType.Name, err) + } + defer module.Close() + + // Find the inner ops struct embedded in the value struct. + kType, kTypeOff, err := structOpsFindInnerType(vType) + if err != nil { + return err + } + + kernVData := make([]byte, int(vType.Size)) + for _, m := range userType.Members { + i := slices.IndexFunc(kType.Members, func(km btf.Member) bool { + return km.Name == m.Name + }) + + // Allow field to not exist in target as long as the source is zero. + if i == -1 { + mSize, err := btf.Sizeof(m.Type) + if err != nil { + return fmt.Errorf("sizeof(user.%s): %w", m.Name, err) + } + srcOff := int(m.Offset.Bytes()) + if srcOff < 0 || srcOff+mSize > len(userData) { + return fmt.Errorf("member %q: userdata is too small", m.Name) + } + + // let fail if the field in type user type is missing in type kern type + if !structOpsIsMemZeroed(userData[srcOff : srcOff+mSize]) { + return fmt.Errorf("%s doesn't exist in %s, but it has non-zero value", m.Name, kType.Name) + } + + continue + } + + km := kType.Members[i] + + switch btf.UnderlyingType(m.Type).(type) { + case *btf.Pointer: + // If this is a pointer → resolve struct_ops program. + psKey := kType.Name + ":" + m.Name + for k, ps := range cl.coll.Programs { + if ps.AttachTo == psKey { + p, ok := cl.programs[k] + if !ok || p == nil { + return nil + } + if err := structOpsPopulateValue(km, kernVData[kTypeOff:], p); err != nil { + return err + } + } + } + + default: + // Otherwise → memcpy the field contents. + if err := structOpsCopyMember(m, km, userData, kernVData[kTypeOff:]); err != nil { + return fmt.Errorf("field %s: %w", kType.Name, err) + } + } + } + + // Populate the map explicitly and keep a reference on cl.programs. + // This is necessary because we may inline fds into kernVData which + // may become invalid if the GC frees them. + if err := m.Put(uint32(0), kernVData); err != nil { + return err + } + mapSpec.Contents = nil + runtime.KeepAlive(cl.programs) + + return nil +} + // resolveKconfig resolves all variables declared in .kconfig and populates // m.Contents. Does nothing if the given m.Contents is non-empty. func resolveKconfig(m *MapSpec) error { diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go index e2b21fa57..f2c9196b7 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader.go +++ b/vendor/github.com/cilium/ebpf/elf_reader.go @@ -873,10 +873,11 @@ func (ec *elfCode) loadBTFMaps() error { func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) { var ( key, value btf.Type - keySize, valueSize uint32 + keySize, valueSize uint64 mapType MapType - flags, maxEntries uint32 + flags, maxEntries uint64 pinType PinType + mapExtra uint64 innerMapSpec *MapSpec contents []MapKV err error @@ -920,7 +921,7 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b return nil, fmt.Errorf("can't get size of BTF key: %w", err) } - keySize = uint32(size) + keySize = uint64(size) case "value": if valueSize != 0 { @@ -939,7 +940,7 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b return nil, fmt.Errorf("can't get size of BTF value: %w", err) } - valueSize = uint32(size) + valueSize = uint64(size) case "key_size": // Key needs to be nil and keySize needs to be 0 for key_size to be @@ -1035,7 +1036,10 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b } case "map_extra": - return nil, fmt.Errorf("BTF map definition: field %s: %w", member.Name, ErrNotSupported) + mapExtra, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("resolving map_extra: %w", err) + } default: return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name) @@ -1057,33 +1061,45 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b return &MapSpec{ Name: sanitizeName(name, -1), Type: MapType(mapType), - KeySize: keySize, - ValueSize: valueSize, - MaxEntries: maxEntries, - Flags: flags, + KeySize: uint32(keySize), + ValueSize: uint32(valueSize), + MaxEntries: uint32(maxEntries), + Flags: uint32(flags), Key: key, Value: value, Pinning: pinType, InnerMap: innerMapSpec, Contents: contents, Tags: slices.Clone(v.Tags), + MapExtra: mapExtra, }, nil } -// uintFromBTF resolves the __uint macro, which is a pointer to a sized -// array, e.g. for int (*foo)[10], this function will return 10. -func uintFromBTF(typ btf.Type) (uint32, error) { - ptr, ok := typ.(*btf.Pointer) - if !ok { - return 0, fmt.Errorf("not a pointer: %v", typ) - } +// uintFromBTF resolves the __uint and __ulong macros. +// +// __uint emits a pointer to a sized array. For int (*foo)[10], this function +// will return 10. +// +// __ulong emits an enum with a single value that can represent a 64-bit +// integer. The first (and only) enum value is returned. +func uintFromBTF(typ btf.Type) (uint64, error) { + switch t := typ.(type) { + case *btf.Pointer: + arr, ok := t.Target.(*btf.Array) + if !ok { + return 0, fmt.Errorf("not a pointer to array: %v", typ) + } + return uint64(arr.Nelems), nil - arr, ok := ptr.Target.(*btf.Array) - if !ok { - return 0, fmt.Errorf("not a pointer to array: %v", typ) - } + case *btf.Enum: + if len(t.Values) == 0 { + return 0, errors.New("enum has no values") + } + return t.Values[0].Value, nil - return arr.Nelems, nil + default: + return 0, fmt.Errorf("not a pointer or enum: %v", typ) + } } // resolveBTFArrayMacro resolves the __array macro, which declares an array diff --git a/vendor/github.com/cilium/ebpf/info.go b/vendor/github.com/cilium/ebpf/info.go index b15202a0f..23c819aaa 100644 --- a/vendor/github.com/cilium/ebpf/info.go +++ b/vendor/github.com/cilium/ebpf/info.go @@ -301,6 +301,8 @@ type ProgramInfo struct { btf btf.ID loadTime time.Duration + restricted bool + maps []MapID insns []byte jitedSize uint32 @@ -477,6 +479,14 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) { } } + if info.XlatedProgLen > 0 && info2.XlatedProgInsns.IsNil() { + pi.restricted = true + pi.insns = nil + pi.lineInfos = nil + pi.funcInfos = nil + pi.jitedInfo = programJitedInfo{} + } + return &pi, nil } @@ -556,14 +566,25 @@ func (pi *ProgramInfo) btfSpec() (*btf.Spec, error) { return spec, nil } +// ErrRestrictedKernel is returned when kernel address information is restricted +// by kernel.kptr_restrict and/or net.core.bpf_jit_harden sysctls. +var ErrRestrictedKernel = internal.ErrRestrictedKernel + // LineInfos returns the BTF line information of the program. // // Available from 5.0. // +// Returns an error wrapping [ErrRestrictedKernel] if line infos are restricted +// by sysctls. +// // Requires CAP_SYS_ADMIN or equivalent for reading BTF information. Returns // ErrNotSupported if the program was created without BTF or if the kernel // doesn't support the field. func (pi *ProgramInfo) LineInfos() (btf.LineOffsets, error) { + if pi.restricted { + return nil, fmt.Errorf("line infos: %w", ErrRestrictedKernel) + } + if len(pi.lineInfos) == 0 { return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported) } @@ -599,6 +620,9 @@ func (pi *ProgramInfo) LineInfos() (btf.LineOffsets, error) { // this metadata requires CAP_SYS_ADMIN or equivalent. If capability is // unavailable, the instructions will be returned without metadata. // +// Returns an error wrapping [ErrRestrictedKernel] if instructions are +// restricted by sysctls. +// // Available from 4.13. Requires CAP_BPF or equivalent for plain instructions. // Requires CAP_SYS_ADMIN for instructions with metadata. func (pi *ProgramInfo) Instructions() (asm.Instructions, error) { @@ -606,6 +630,10 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) { return nil, fmt.Errorf("read instructions: %w", internal.ErrNotSupportedOnOS) } + if pi.restricted { + return nil, fmt.Errorf("instructions: %w", ErrRestrictedKernel) + } + // If the calling process is not BPF-capable or if the kernel doesn't // support getting xlated instructions, the field will be zero. if len(pi.insns) == 0 { @@ -671,22 +699,37 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) { return insns, nil } -// JitedSize returns the size of the program's JIT-compiled machine code in bytes, which is the -// actual code executed on the host's CPU. This field requires the BPF JIT compiler to be enabled. +// JitedSize returns the size of the program's JIT-compiled machine code in +// bytes, which is the actual code executed on the host's CPU. This field +// requires the BPF JIT compiler to be enabled. +// +// Returns an error wrapping [ErrRestrictedKernel] if jited program size is +// restricted by sysctls. // // Available from 4.13. Reading this metadata requires CAP_BPF or equivalent. func (pi *ProgramInfo) JitedSize() (uint32, error) { + if pi.restricted { + return 0, fmt.Errorf("jited size: %w", ErrRestrictedKernel) + } + if pi.jitedSize == 0 { return 0, fmt.Errorf("insufficient permissions, unsupported kernel, or JIT compiler disabled: %w", ErrNotSupported) } return pi.jitedSize, nil } -// TranslatedSize returns the size of the program's translated instructions in bytes, after it has -// been verified and rewritten by the kernel. +// TranslatedSize returns the size of the program's translated instructions in +// bytes, after it has been verified and rewritten by the kernel. +// +// Returns an error wrapping [ErrRestrictedKernel] if translated instructions +// are restricted by sysctls. // // Available from 4.13. Reading this metadata requires CAP_BPF or equivalent. func (pi *ProgramInfo) TranslatedSize() (int, error) { + if pi.restricted { + return 0, fmt.Errorf("xlated size: %w", ErrRestrictedKernel) + } + insns := len(pi.insns) if insns == 0 { return 0, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported) @@ -782,10 +825,17 @@ func (pi *ProgramInfo) JitedFuncLens() ([]uint32, bool) { // // Available from 5.0. // +// Returns an error wrapping [ErrRestrictedKernel] if function information is +// restricted by sysctls. +// // Requires CAP_SYS_ADMIN or equivalent for reading BTF information. Returns // ErrNotSupported if the program was created without BTF or if the kernel // doesn't support the field. func (pi *ProgramInfo) FuncInfos() (btf.FuncOffsets, error) { + if pi.restricted { + return nil, fmt.Errorf("func infos: %w", ErrRestrictedKernel) + } + if len(pi.funcInfos) == 0 { return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported) } diff --git a/vendor/github.com/cilium/ebpf/internal/efw/map.go b/vendor/github.com/cilium/ebpf/internal/efw/map.go new file mode 100644 index 000000000..82f510fef --- /dev/null +++ b/vendor/github.com/cilium/ebpf/internal/efw/map.go @@ -0,0 +1,109 @@ +//go:build windows + +package efw + +import ( + "runtime" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +/* +ebpf_ring_buffer_map_map_buffer( + + fd_t map_fd, + _Outptr_result_maybenull_ void** consumer, + _Outptr_result_maybenull_ const void** producer, + _Outptr_result_buffer_maybenull_(*data_size) const uint8_t** data, + _Out_ size_t* data_size) EBPF_NO_EXCEPT; +*/ +var ebpfRingBufferMapMapBufferProc = newProc("ebpf_ring_buffer_map_map_buffer") + +func EbpfRingBufferMapMapBuffer(mapFd int) (consumer, producer, data *uint8, dataLen Size, _ error) { + addr, err := ebpfRingBufferMapMapBufferProc.Find() + if err != nil { + return nil, nil, nil, 0, err + } + + err = errorResult(syscall.SyscallN(addr, + uintptr(mapFd), + uintptr(unsafe.Pointer(&consumer)), + uintptr(unsafe.Pointer(&producer)), + uintptr(unsafe.Pointer(&data)), + uintptr(unsafe.Pointer(&dataLen)), + )) + if err != nil { + return nil, nil, nil, 0, err + } + + return consumer, producer, data, dataLen, nil +} + +/* +ebpf_ring_buffer_map_unmap_buffer( + + fd_t map_fd, _In_ void* consumer, _In_ const void* producer, _In_ const void* data) EBPF_NO_EXCEPT; +*/ +var ebpfRingBufferMapUnmapBufferProc = newProc("ebpf_ring_buffer_map_unmap_buffer") + +func EbpfRingBufferMapUnmapBuffer(mapFd int, consumer, producer, data *uint8) error { + addr, err := ebpfRingBufferMapUnmapBufferProc.Find() + if err != nil { + return err + } + + return errorResult(syscall.SyscallN(addr, + uintptr(mapFd), + uintptr(unsafe.Pointer(consumer)), + uintptr(unsafe.Pointer(producer)), + uintptr(unsafe.Pointer(data)), + )) +} + +/* +ebpf_result_t ebpf_map_set_wait_handle( + + fd_t map_fd, + uint64_t index, + ebpf_handle_t handle) +*/ +var ebpfMapSetWaitHandleProc = newProc("ebpf_map_set_wait_handle") + +func EbpfMapSetWaitHandle(mapFd int, index uint64, handle windows.Handle) error { + addr, err := ebpfMapSetWaitHandleProc.Find() + if err != nil { + return err + } + + return errorResult(syscall.SyscallN(addr, + uintptr(mapFd), + uintptr(index), + uintptr(handle), + )) +} + +/* +ebpf_result_t ebpf_ring_buffer_map_write( + + fd_t ring_buffer_map_fd, + const void* data, + size_t data_length) +*/ +var ebpfRingBufferMapWriteProc = newProc("ebpf_ring_buffer_map_write") + +func EbpfRingBufferMapWrite(ringBufferMapFd int, data []byte) error { + addr, err := ebpfRingBufferMapWriteProc.Find() + if err != nil { + return err + } + + err = errorResult(syscall.SyscallN(addr, + uintptr(ringBufferMapFd), + uintptr(unsafe.Pointer(&data[0])), + uintptr(len(data)), + )) + runtime.KeepAlive(data) + return err +} diff --git a/vendor/github.com/cilium/ebpf/internal/efw/result.go b/vendor/github.com/cilium/ebpf/internal/efw/result.go index 3275941d3..4c68da931 100644 --- a/vendor/github.com/cilium/ebpf/internal/efw/result.go +++ b/vendor/github.com/cilium/ebpf/internal/efw/result.go @@ -5,7 +5,7 @@ package efw // See https://github.com/microsoft/ebpf-for-windows/blob/main/include/ebpf_result.h type Result int32 -//go:generate go run golang.org/x/tools/cmd/stringer@latest -tags windows -output result_string_windows.go -type=Result +//go:generate go tool stringer -tags windows -output result_string_windows.go -type=Result const ( EBPF_SUCCESS Result = iota diff --git a/vendor/github.com/cilium/ebpf/internal/feature.go b/vendor/github.com/cilium/ebpf/internal/feature.go index 82b8d9395..e27064c23 100644 --- a/vendor/github.com/cilium/ebpf/internal/feature.go +++ b/vendor/github.com/cilium/ebpf/internal/feature.go @@ -16,6 +16,10 @@ var ErrNotSupported = errors.New("not supported") // operating system. var ErrNotSupportedOnOS = fmt.Errorf("%w on %s", ErrNotSupported, runtime.GOOS) +// ErrRestrictedKernel is returned when kernel address information is restricted +// by kernel.kptr_restrict and/or net.core.bpf_jit_harden sysctls. +var ErrRestrictedKernel = errors.New("restricted by kernel.kptr_restrict and/or net.core.bpf_jit_harden sysctls") + // UnsupportedFeatureError is returned by FeatureTest() functions. type UnsupportedFeatureError struct { // The minimum version required for this feature. diff --git a/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go b/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go index 9154a8a79..efc64a503 100644 --- a/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go +++ b/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go @@ -16,151 +16,6 @@ import ( var errAmbiguousKsym = errors.New("multiple kernel symbols with the same name") var symAddrs cache[string, uint64] -var symModules cache[string, string] - -// Module returns the kernel module providing the given symbol in the kernel, if -// any. Returns an empty string and no error if the symbol is not present in the -// kernel. Only function symbols are considered. Returns an error if multiple -// symbols with the same name were found. -// -// Consider [AssignModules] if you need to resolve multiple symbols, as it will -// only perform one iteration over /proc/kallsyms. -func Module(name string) (string, error) { - if name == "" { - return "", nil - } - - if mod, ok := symModules.Load(name); ok { - return mod, nil - } - - request := map[string]string{name: ""} - if err := AssignModules(request); err != nil { - return "", err - } - - return request[name], nil -} - -// AssignModules looks up the kernel module providing each given symbol, if any, -// and assigns them to their corresponding values in the symbols map. Only -// function symbols are considered. Results of all lookups are cached, -// successful or otherwise. -// -// Any symbols missing in the kernel are ignored. Returns an error if multiple -// symbols with a given name were found. -func AssignModules(symbols map[string]string) error { - if !platform.IsLinux { - return fmt.Errorf("read /proc/kallsyms: %w", internal.ErrNotSupportedOnOS) - } - - if len(symbols) == 0 { - return nil - } - - // Attempt to fetch symbols from cache. - request := make(map[string]string) - for name := range symbols { - if mod, ok := symModules.Load(name); ok { - symbols[name] = mod - continue - } - - // Mark the symbol to be read from /proc/kallsyms. - request[name] = "" - } - if len(request) == 0 { - // All symbols satisfied from cache. - return nil - } - - f, err := os.Open("/proc/kallsyms") - if err != nil { - return err - } - defer f.Close() - - if err := assignModules(f, request); err != nil { - return fmt.Errorf("assigning symbol modules: %w", err) - } - - // Update the cache with the new symbols. Cache all requested symbols, even if - // they're missing or don't belong to a module. - for name, mod := range request { - symModules.Store(name, mod) - symbols[name] = mod - } - - return nil -} - -// assignModules assigns kernel symbol modules read from f to values requested -// by symbols. Always scans the whole input to make sure the user didn't request -// an ambiguous symbol. -func assignModules(f io.Reader, symbols map[string]string) error { - if len(symbols) == 0 { - return nil - } - - found := make(map[string]struct{}) - r := newReader(f) - for r.Line() { - // Only look for function symbols in the kernel's text section (tT). - s, err, skip := parseSymbol(r, []rune{'t', 'T'}) - if err != nil { - return fmt.Errorf("parsing kallsyms line: %w", err) - } - if skip { - continue - } - - if _, requested := symbols[string(s.name)]; !requested { - continue - } - - if _, ok := found[string(s.name)]; ok { - // We've already seen this symbol. Return an error to avoid silently - // attaching to a symbol in the wrong module. libbpf also rejects - // referring to ambiguous symbols. - // - // We can't simply check if we already have a value for the given symbol, - // since many won't have an associated kernel module. - return fmt.Errorf("symbol %s: duplicate found at address 0x%x (module %q): %w", - s.name, s.addr, s.mod, errAmbiguousKsym) - } - - symbols[string(s.name)] = string(s.mod) - found[string(s.name)] = struct{}{} - } - if err := r.Err(); err != nil { - return fmt.Errorf("reading kallsyms: %w", err) - } - - return nil -} - -// Address returns the address of the given symbol in the kernel. Returns 0 and -// no error if the symbol is not present. Returns an error if multiple addresses -// were found for a symbol. -// -// Consider [AssignAddresses] if you need to resolve multiple symbols, as it -// will only perform one iteration over /proc/kallsyms. -func Address(symbol string) (uint64, error) { - if symbol == "" { - return 0, nil - } - - if addr, ok := symAddrs.Load(symbol); ok { - return addr, nil - } - - request := map[string]uint64{symbol: 0} - if err := AssignAddresses(request); err != nil { - return 0, err - } - - return request[symbol], nil -} // AssignAddresses looks up the addresses of the requested symbols in the kernel // and assigns them to their corresponding values in the symbols map. Results @@ -238,6 +93,19 @@ func assignAddresses(f io.Reader, symbols map[string]uint64) error { return fmt.Errorf("symbol %s(0x%x): duplicate found at address 0x%x: %w", s.name, existing, s.addr, errAmbiguousKsym) } if requested { + // Reading a symbol with a zero address is a strong indication that + // kptr_restrict is set and the process doesn't have CAP_SYSLOG, or + // kptr_restrict is set to 2 (never show addresses). + // + // When running the kernel with KASLR disabled (like CI kernels running in + // microVMs), kallsyms will display many absolute symbols at address 0. + // This memory is unlikely to contain anything useful, and production + // machines are unlikely to run without KASLR. + // + // Return a helpful error instead of silently returning zero addresses. + if s.addr == 0 { + return fmt.Errorf("symbol %s: %w", s.name, internal.ErrRestrictedKernel) + } symbols[string(s.name)] = s.addr } } diff --git a/vendor/github.com/cilium/ebpf/internal/sys/doc.go b/vendor/github.com/cilium/ebpf/internal/sys/doc.go index dfe174448..75d7e4013 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/doc.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/doc.go @@ -3,4 +3,4 @@ package sys // Regenerate types.go by invoking go generate in the current directory. -//go:generate go run github.com/cilium/ebpf/internal/cmd/gentypes ../../btf/testdata/vmlinux.btf.gz +//go:generate go tool gentypes ../../btf/testdata/vmlinux.btf.gz diff --git a/vendor/github.com/cilium/ebpf/internal/sys/fd.go b/vendor/github.com/cilium/ebpf/internal/sys/fd.go index 7e769fb54..f12d11c20 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/fd.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/fd.go @@ -21,23 +21,14 @@ const invalidFd = -1 func newFD(value int) *FD { testmain.TraceFD(value, 1) - fd := &FD{value} - runtime.SetFinalizer(fd, (*FD).finalize) + fd := &FD{raw: value} + fd.cleanup = runtime.AddCleanup(fd, func(raw int) { + testmain.LeakFD(raw) + _ = unix.Close(raw) + }, fd.raw) return fd } -// finalize is set as the FD's runtime finalizer and -// sends a leak trace before calling FD.Close(). -func (fd *FD) finalize() { - if fd.raw == invalidFd { - return - } - - testmain.LeakFD(fd.raw) - - _ = fd.Close() -} - func (fd *FD) String() string { return strconv.FormatInt(int64(fd.raw), 10) } @@ -63,6 +54,6 @@ func (fd *FD) Disown() int { testmain.ForgetFD(value) fd.raw = invalidFd - runtime.SetFinalizer(fd, nil) + fd.cleanup.Stop() return value } diff --git a/vendor/github.com/cilium/ebpf/internal/sys/fd_other.go b/vendor/github.com/cilium/ebpf/internal/sys/fd_other.go index 47057395e..2a6423a59 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/fd_other.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/fd_other.go @@ -5,12 +5,14 @@ package sys import ( "fmt" "os" + "runtime" "github.com/cilium/ebpf/internal/unix" ) type FD struct { - raw int + raw int + cleanup runtime.Cleanup } // NewFD wraps a raw fd with a finalizer. diff --git a/vendor/github.com/cilium/ebpf/internal/sys/fd_windows.go b/vendor/github.com/cilium/ebpf/internal/sys/fd_windows.go index f39276382..1291c763f 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/fd_windows.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/fd_windows.go @@ -3,6 +3,7 @@ package sys import ( "fmt" "os" + "runtime" "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/efw" @@ -12,7 +13,8 @@ import ( // // It is not equivalent to a real file descriptor or handle. type FD struct { - raw int + raw int + cleanup runtime.Cleanup } // NewFD wraps a raw fd with a finalizer. diff --git a/vendor/github.com/cilium/ebpf/internal/sys/ptr.go b/vendor/github.com/cilium/ebpf/internal/sys/ptr.go index 173665c2a..aa6c2e91a 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/ptr.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/ptr.go @@ -28,6 +28,10 @@ type TypedPointer[T any] struct { ptr Pointer } +func (p TypedPointer[T]) IsNil() bool { + return p.ptr.ptr == nil +} + // SlicePointer creates a [TypedPointer] from a slice. func SlicePointer[T comparable](s []T) TypedPointer[T] { return TypedPointer[T]{ptr: UnsafeSlicePointer(s)} diff --git a/vendor/github.com/cilium/ebpf/internal/sys/types.go b/vendor/github.com/cilium/ebpf/internal/sys/types.go index 2847f17ed..2e6674862 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/types.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/types.go @@ -1064,6 +1064,16 @@ func LinkCreateUprobeMulti(attr *LinkCreateUprobeMultiAttr) (*FD, error) { return NewFD(int(fd)) } +type LinkDetachAttr struct { + _ structs.HostLayout + LinkFd uint32 +} + +func LinkDetach(attr *LinkDetachAttr) error { + _, err := BPF(BPF_LINK_DETACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + type LinkGetFdByIdAttr struct { _ structs.HostLayout Id LinkID diff --git a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go index 7f7b3cba5..d0b5be66c 100644 --- a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go +++ b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go @@ -23,7 +23,7 @@ var ( ErrInvalidMaxActive = errors.New("can only set maxactive on kretprobes") ) -//go:generate go run golang.org/x/tools/cmd/stringer@latest -type=ProbeType -linecomment +//go:generate go tool stringer -type=ProbeType -linecomment type ProbeType uint8 @@ -72,11 +72,11 @@ func RandomGroup(prefix string) (string, error) { } // validIdentifier implements the equivalent of a regex match -// against "^[a-zA-Z_][0-9a-zA-Z_]*$". +// against "^[a-zA-Z_][0-9a-zA-Z_-]*$". // -// Trace event groups, names and kernel symbols must adhere to this set -// of characters. Non-empty, first character must not be a number, all -// characters must be alphanumeric or underscore. +// Trace event groups, names and kernel symbols must adhere to this set of +// characters. Non-empty, first character must not be a number or hyphen, all +// characters must be alphanumeric, underscore or hyphen. func validIdentifier(s string) bool { if len(s) < 1 { return false @@ -86,7 +86,7 @@ func validIdentifier(s string) bool { case c >= 'a' && c <= 'z': case c >= 'A' && c <= 'Z': case c == '_': - case i > 0 && c >= '0' && c <= '9': + case i > 0 && (c == '-' || c >= '0' && c <= '9'): default: return false @@ -200,6 +200,8 @@ type Event struct { group, name string // event id allocated by the kernel. 0 if the event has already been removed. id uint64 + + cleanup runtime.Cleanup } // NewEvent creates a new ephemeral trace event. @@ -316,8 +318,11 @@ func NewEvent(args ProbeArgs) (*Event, error) { return nil, fmt.Errorf("get trace event id: %w", err) } - evt := &Event{args.Type, args.Group, eventName, tid} - runtime.SetFinalizer(evt, (*Event).Close) + evt := &Event{typ: args.Type, group: args.Group, name: eventName, id: tid} + evt.cleanup = runtime.AddCleanup(evt, func(*byte) { + _ = removeEvent(args.Type, fmt.Sprintf("%s/%s", args.Group, eventName)) + }, nil) + return evt, nil } @@ -330,7 +335,7 @@ func (evt *Event) Close() error { } evt.id = 0 - runtime.SetFinalizer(evt, nil) + evt.cleanup.Stop() pe := fmt.Sprintf("%s/%s", evt.group, evt.name) return removeEvent(evt.typ, pe) } diff --git a/vendor/github.com/cilium/ebpf/internal/tracefs/probetype_string.go b/vendor/github.com/cilium/ebpf/internal/tracefs/probetype_string.go index 87cb0a059..ed8471a89 100644 --- a/vendor/github.com/cilium/ebpf/internal/tracefs/probetype_string.go +++ b/vendor/github.com/cilium/ebpf/internal/tracefs/probetype_string.go @@ -17,8 +17,9 @@ const _ProbeType_name = "kprobeuprobe" var _ProbeType_index = [...]uint8{0, 6, 12} func (i ProbeType) String() string { - if i >= ProbeType(len(_ProbeType_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_ProbeType_index)-1 { return "ProbeType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _ProbeType_name[_ProbeType_index[i]:_ProbeType_index[i+1]] + return _ProbeType_name[_ProbeType_index[idx]:_ProbeType_index[idx+1]] } diff --git a/vendor/github.com/cilium/ebpf/internal/unix/errno_windows.go b/vendor/github.com/cilium/ebpf/internal/unix/errno_windows.go index 7500cd6d4..266e43daa 100644 --- a/vendor/github.com/cilium/ebpf/internal/unix/errno_windows.go +++ b/vendor/github.com/cilium/ebpf/internal/unix/errno_windows.go @@ -9,7 +9,7 @@ import ( "syscall" ) -//go:generate go run golang.org/x/tools/cmd/stringer@latest -type=Errno -tags=windows -output=errno_string_windows.go +//go:generate go tool stringer -type=Errno -tags=windows -output=errno_string_windows.go // Windows specific constants for Unix errnos. // @@ -37,6 +37,7 @@ const ( EILSEQ Errno = 42 ENOTSUP Errno = 129 EOPNOTSUPP Errno = 130 + EOTHER Errno = 131 ETIMEDOUT Errno = 138 EWOULDBLOCK Errno = 140 ) diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go index 0b966477f..98c4a0d0b 100644 --- a/vendor/github.com/cilium/ebpf/linker.go +++ b/vendor/github.com/cilium/ebpf/linker.go @@ -122,9 +122,8 @@ func hasFunctionReferences(insns asm.Instructions) bool { // applyRelocations collects and applies any CO-RE relocations in insns. // -// Passing a nil target will relocate against the running kernel. insns are -// modified in place. -func applyRelocations(insns asm.Instructions, bo binary.ByteOrder, b *btf.Builder, c *btf.Cache) error { +// insns are modified in place. +func applyRelocations(insns asm.Instructions, bo binary.ByteOrder, b *btf.Builder, c *btf.Cache, kernelOverride *btf.Spec, extraTargets []*btf.Spec) error { var relos []*btf.CORERelocation var reloInsns []*asm.Instruction iter := insns.Iterate() @@ -143,30 +142,39 @@ func applyRelocations(insns asm.Instructions, bo binary.ByteOrder, b *btf.Builde bo = internal.NativeEndian } - kernelTarget, err := c.Kernel() - if err != nil { - return fmt.Errorf("load kernel spec: %w", err) - } + var targets []*btf.Spec + if kernelOverride == nil { + kernel, err := c.Kernel() + if err != nil { + return fmt.Errorf("load kernel spec: %w", err) + } - modules, err := c.Modules() - // Ignore ErrNotExists to cater to kernels which have CONFIG_DEBUG_INFO_BTF_MODULES - // or CONFIG_DEBUG_INFO_BTF disabled. - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return err - } + modules, err := c.Modules() + // Ignore ErrNotExists to cater to kernels which have CONFIG_DEBUG_INFO_BTF_MODULES + // or CONFIG_DEBUG_INFO_BTF disabled. + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return err + } - targets := make([]*btf.Spec, 0, 1+len(modules)) - targets = append(targets, kernelTarget) + targets = make([]*btf.Spec, 0, 1+len(modules)+len(extraTargets)) + targets = append(targets, kernel) - for _, kmod := range modules { - spec, err := c.Module(kmod) - if err != nil { - return fmt.Errorf("load BTF for kmod %s: %w", kmod, err) - } + for _, kmod := range modules { + spec, err := c.Module(kmod) + if err != nil { + return fmt.Errorf("load BTF for kmod %s: %w", kmod, err) + } - targets = append(targets, spec) + targets = append(targets, spec) + } + } else { + // We expect kernelOverride to contain the merged types + // of vmlinux and kernel modules, as distributed by btfhub. + targets = []*btf.Spec{kernelOverride} } + targets = append(targets, extraTargets...) + fixups, err := btf.CORERelocate(relos, targets, bo, b.Add) if err != nil { return err @@ -287,7 +295,7 @@ const kfuncCallPoisonBase = 0xdedc0de // fixupKfuncs loops over all instructions in search for kfunc calls. // If at least one is found, the current kernels BTF and module BTFis are searched to set Instruction.Constant // and Instruction.Offset to the correct values. -func fixupKfuncs(insns asm.Instructions) (_ handles, err error) { +func fixupKfuncs(insns asm.Instructions, cache *btf.Cache) (_ handles, err error) { closeOnError := func(c io.Closer) { if err != nil { c.Close() @@ -308,7 +316,7 @@ fixups: // Only load kernel BTF if we found at least one kfunc call. kernelSpec can be // nil if the kernel does not have BTF, in which case we poison all kfunc // calls. - kernelSpec, err := btf.LoadKernelSpec() + _, err = cache.Kernel() // ErrNotSupportedOnOS wraps ErrNotSupported, check for it first. if errors.Is(err, internal.ErrNotSupportedOnOS) { return nil, fmt.Errorf("kfuncs are not supported on this platform: %w", err) @@ -340,7 +348,7 @@ fixups: // findTargetInKernel returns btf.ErrNotFound if the input btf.Spec is nil. target := btf.Type((*btf.Func)(nil)) - spec, module, err := findTargetInKernel(kernelSpec, kfm.Func.Name, &target) + spec, module, err := findTargetInKernel(kfm.Func.Name, &target, cache) if errors.Is(err, btf.ErrNotFound) { if kfm.Binding == elf.STB_WEAK { if ins.IsKfuncCall() { @@ -485,7 +493,13 @@ func resolveKconfigReferences(insns asm.Instructions) (_ *Map, err error) { } func resolveKsymReferences(insns asm.Instructions) error { - var missing []string + type fixup struct { + *asm.Instruction + *ksymMeta + } + + var symbols map[string]uint64 + var fixups []fixup iter := insns.Iterate() for iter.Next() { @@ -495,28 +509,47 @@ func resolveKsymReferences(insns asm.Instructions) error { continue } - addr, err := kallsyms.Address(meta.Name) - if err != nil { - return fmt.Errorf("resolve ksym %s: %w", meta.Name, err) - } - if addr != 0 { - ins.Constant = int64(addr) - continue + if symbols == nil { + symbols = make(map[string]uint64) } - if meta.Binding == elf.STB_WEAK { - // A weak ksym variable in eBPF C means its resolution is optional. - // Set a zero constant explicitly for clarity. - ins.Constant = 0 + symbols[meta.Name] = 0 + fixups = append(fixups, fixup{ + iter.Ins, meta, + }) + } + + if len(symbols) == 0 { + return nil + } + + err := kallsyms.AssignAddresses(symbols) + // Tolerate ErrRestrictedKernel during initial lookup, user may have all weak + // ksyms and a fallback path. + if err != nil && !errors.Is(err, ErrRestrictedKernel) { + return fmt.Errorf("resolve ksyms: %w", err) + } + + var missing []string + for _, fixup := range fixups { + addr := symbols[fixup.Name] + // A weak ksym variable in eBPF C means its resolution is optional. + if addr == 0 && fixup.Binding != elf.STB_WEAK { + if !slices.Contains(missing, fixup.Name) { + missing = append(missing, fixup.Name) + } continue } - if !slices.Contains(missing, meta.Name) { - missing = append(missing, meta.Name) - } + fixup.Constant = int64(addr) } if len(missing) > 0 { + if err != nil { + // Program contains required ksyms, return the error from above. + return fmt.Errorf("resolve required ksyms: %s: %w", strings.Join(missing, ","), err) + } + return fmt.Errorf("kernel is missing symbol: %s", strings.Join(missing, ",")) } diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go index 55974b4eb..f9499272b 100644 --- a/vendor/github.com/cilium/ebpf/map.go +++ b/vendor/github.com/cilium/ebpf/map.go @@ -78,6 +78,11 @@ type MapSpec struct { // InnerMap is used as a template for ArrayOfMaps and HashOfMaps InnerMap *MapSpec + // MapExtra is an opaque field whose meaning is map-specific. + // + // Available from 5.16. + MapExtra uint64 + // Extra trailing bytes found in the ELF map definition when using structs // larger than libbpf's bpf_map_def. nil if no trailing bytes were present. // Must be nil or empty before instantiating the MapSpec into a Map. @@ -329,7 +334,7 @@ func NewMap(spec *MapSpec) (*Map, error) { // // May return an error wrapping ErrMapIncompatible. func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { - m, err := newMapWithOptions(spec, opts) + m, err := newMapWithOptions(spec, opts, btf.NewCache()) if err != nil { return nil, fmt.Errorf("creating map: %w", err) } @@ -342,7 +347,7 @@ func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { return m, nil } -func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) { +func newMapWithOptions(spec *MapSpec, opts MapOptions, c *btf.Cache) (_ *Map, err error) { closeOnError := func(c io.Closer) { if err != nil { c.Close() @@ -392,7 +397,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) { return nil, errors.New("inner maps cannot be pinned") } - template, err := spec.InnerMap.createMap(nil) + template, err := spec.InnerMap.createMap(nil, c) if err != nil { return nil, fmt.Errorf("inner map: %w", err) } @@ -404,7 +409,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) { innerFd = template.fd } - m, err := spec.createMap(innerFd) + m, err := spec.createMap(innerFd, c) if err != nil { return nil, err } @@ -499,7 +504,7 @@ func (m *Map) memorySize() (int, error) { // createMap validates the spec's properties and creates the map in the kernel // using the given opts. It does not populate or freeze the map. -func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) { +func (spec *MapSpec) createMap(inner *sys.FD, c *btf.Cache) (_ *Map, err error) { closeOnError := func(closer io.Closer) { if err != nil { closer.Close() @@ -534,6 +539,7 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) { MaxEntries: spec.MaxEntries, MapFlags: spec.Flags, NumaNode: spec.NumaNode, + MapExtra: spec.MapExtra, } if inner != nil { @@ -554,6 +560,42 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) { attr.BtfKeyTypeId = keyTypeID attr.BtfValueTypeId = valueTypeID } + + if spec.Type == StructOpsMap { + if handle == nil { + return nil, fmt.Errorf("struct_ops requires BTF") + } + + localValue, ok := btf.As[*btf.Struct](spec.Value) + if !ok { + return nil, fmt.Errorf("struct_ops: value must be struct") + } + + targetValue, targetID, module, err := structOpsFindTarget(localValue, c) + if err != nil { + return nil, fmt.Errorf("struct_ops: %w", err) + } + defer module.Close() + + spec = spec.Copy() + spec.ValueSize = targetValue.Size + + attr.ValueSize = targetValue.Size + attr.BtfVmlinuxValueTypeId = targetID + + if module != nil { + // BPF_F_VTYPE_BTF_OBJ_FD is required if the type comes from a module + attr.MapFlags |= sys.BPF_F_VTYPE_BTF_OBJ_FD + // set FD for the kernel module + attr.ValueTypeBtfObjFd = int32(module.FD()) + } + + // StructOpsMap forbids passing BtfKeyTypeId or BtfValueTypeId, but + // requires BtfFd. Do the simple thing and just zero out the fields. + // See https://github.com/torvalds/linux/blob/9b332cece987ee1790b2ed4c989e28162fa47860/kernel/bpf/syscall.c#L1382-L1384 + attr.BtfKeyTypeId = 0 + attr.BtfValueTypeId = 0 + } } fd, err := sys.MapCreate(&attr) @@ -1220,17 +1262,18 @@ func (m *Map) batchLookupPerCPU(cmd sys.Cmd, cursor *MapBatchCursor, keysOut, va return 0, fmt.Errorf("keys: %w", err) } - valueBuf := make([]byte, count*int(m.fullValueSize)) - valuePtr := sys.UnsafeSlicePointer(valueBuf) + valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize)) - n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valuePtr, opts) + n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts) if sysErr != nil && !errors.Is(sysErr, unix.ENOENT) { return 0, sysErr } - err = unmarshalBatchPerCPUValue(valuesOut, count, int(m.valueSize), valueBuf) - if err != nil { - return 0, err + if bytesBuf := valueBuf.Bytes(); bytesBuf != nil { + err = unmarshalBatchPerCPUValue(valuesOut, count, int(m.valueSize), bytesBuf) + if err != nil { + return 0, err + } } return n, sysErr diff --git a/vendor/github.com/cilium/ebpf/memory.go b/vendor/github.com/cilium/ebpf/memory.go index 3475fb07b..e470bf24f 100644 --- a/vendor/github.com/cilium/ebpf/memory.go +++ b/vendor/github.com/cilium/ebpf/memory.go @@ -38,6 +38,8 @@ type Memory struct { b []byte ro bool heap bool + + cleanup runtime.Cleanup } func newMemory(fd, size int) (*Memory, error) { @@ -62,20 +64,23 @@ func newMemory(fd, size int) (*Memory, error) { return nil, fmt.Errorf("setting up memory-mapped region: %w", err) } - mm := &Memory{ - b, - ro, - false, - } - runtime.SetFinalizer(mm, (*Memory).close) + mm := &Memory{b: b, ro: ro, heap: false} + mm.cleanup = runtime.AddCleanup(mm, memoryCleanupFunc(), b) return mm, nil } -func (mm *Memory) close() { - if err := unix.Munmap(mm.b); err != nil { - panic(fmt.Errorf("unmapping memory: %w", err)) +func memoryCleanupFunc() func([]byte) { + return func(b []byte) { + if err := unix.Munmap(b); err != nil { + panic(fmt.Errorf("unmapping memory: %w", err)) + } } +} + +func (mm *Memory) close() { + mm.cleanup.Stop() + memoryCleanupFunc()(mm.b) mm.b = nil } diff --git a/vendor/github.com/cilium/ebpf/memory_unsafe.go b/vendor/github.com/cilium/ebpf/memory_unsafe.go index cc254397f..9518ff35d 100644 --- a/vendor/github.com/cilium/ebpf/memory_unsafe.go +++ b/vendor/github.com/cilium/ebpf/memory_unsafe.go @@ -87,6 +87,7 @@ func newUnsafeMemory(fd, size int) (*Memory, error) { unsafe.Slice((*byte)(alloc), size), ro, true, + runtime.Cleanup{}, } return mm, nil diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go index 560c045ad..3e724234d 100644 --- a/vendor/github.com/cilium/ebpf/prog.go +++ b/vendor/github.com/cilium/ebpf/prog.go @@ -8,7 +8,8 @@ import ( "math" "path/filepath" "runtime" - "sort" + "slices" + "strings" "time" "github.com/cilium/ebpf/asm" @@ -95,13 +96,10 @@ type ProgramOptions struct { // use the kernel BTF from a well-known location if nil. KernelTypes *btf.Spec - // Type information used for CO-RE relocations of kernel modules, - // indexed by module name. - // - // This is useful in environments where the kernel BTF is not available - // (containers) or where it is in a non-standard location. Defaults to - // use the kernel module BTF from a well-known location if nil. - KernelModuleTypes map[string]*btf.Spec + // Additional targets to consider for CO-RE relocations. This can be used to + // pass BTF information for kernel modules when it's not present on + // KernelTypes. + ExtraRelocationTargets []*btf.Spec } // ProgramSpec defines a Program. @@ -114,6 +112,13 @@ type ProgramSpec struct { // Type determines at which hook in the kernel a program will run. Type ProgramType + // Network interface index the user intends to attach this program to after + // loading. Only valid for some program types. + // + // Provides driver-specific context about the target interface to the + // verifier, required when using certain BPF helpers. + Ifindex uint32 + // AttachType of the program, needed to differentiate allowed context // accesses in some newer program types like CGroupSockAddr. // @@ -233,7 +238,7 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er return nil, errors.New("can't load a program from a nil spec") } - prog, err := newProgramWithOptions(spec, opts, newBTFCache(&opts)) + prog, err := newProgramWithOptions(spec, opts, btf.NewCache()) if errors.Is(err, asm.ErrUnsatisfiedMapReference) { return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err) } @@ -284,6 +289,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache) ProgName: maybeFillObjName(spec.Name), ProgType: sys.ProgType(progType), ProgFlags: spec.Flags, + ProgIfindex: spec.Ifindex, ExpectedAttachType: sys.AttachType(spec.AttachType), License: sys.NewStringPointer(spec.License), KernVersion: kv, @@ -293,7 +299,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache) copy(insns, spec.Instructions) var b btf.Builder - if err := applyRelocations(insns, spec.ByteOrder, &b, c); err != nil { + if err := applyRelocations(insns, spec.ByteOrder, &b, c, opts.KernelTypes, opts.ExtraRelocationTargets); err != nil { return nil, fmt.Errorf("apply CO-RE relocations: %w", err) } @@ -346,7 +352,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache) return nil, err } - handles, err := fixupKfuncs(insns) + handles, err := fixupKfuncs(insns, c) if err != nil { return nil, fmt.Errorf("fixing up kfuncs: %w", err) } @@ -377,15 +383,51 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache) attr.AttachBtfObjFd = uint32(spec.AttachTarget.FD()) defer runtime.KeepAlive(spec.AttachTarget) } else if spec.AttachTo != "" { - module, targetID, err := findProgramTargetInKernel(spec.AttachTo, spec.Type, spec.AttachType) + var targetMember string + attachTo := spec.AttachTo + + if spec.Type == StructOps { + attachTo, targetMember, _ = strings.Cut(attachTo, ":") + if targetMember == "" { + return nil, fmt.Errorf("struct_ops: AttachTo must be ':' (got %s)", spec.AttachTo) + } + } + + module, targetID, err := findProgramTargetInKernel(attachTo, spec.Type, spec.AttachType, c) if err != nil && !errors.Is(err, errUnrecognizedAttachType) { // We ignore errUnrecognizedAttachType since AttachTo may be non-empty // for programs that don't attach anywhere. return nil, fmt.Errorf("attach %s/%s: %w", spec.Type, spec.AttachType, err) } + if spec.Type == StructOps { + var s *btf.Spec + + target := btf.Type((*btf.Struct)(nil)) + s, module, err = findTargetInKernel(attachTo, &target, c) + if err != nil { + return nil, fmt.Errorf("lookup struct_ops kern type %q: %w", attachTo, err) + } + kType := target.(*btf.Struct) + + targetID, err = s.TypeID(kType) + if err != nil { + return nil, fmt.Errorf("type id for %s: %w", kType.TypeName(), err) + } + + idx := slices.IndexFunc(kType.Members, func(m btf.Member) bool { + return m.Name == targetMember + }) + if idx < 0 { + return nil, fmt.Errorf("member %q not found in %s", targetMember, kType.Name) + } + + // ExpectedAttachType: index of the target member in the struct + attr.ExpectedAttachType = sys.AttachType(idx) + } + attr.AttachBtfId = targetID - if module != nil { + if module != nil && attr.AttachBtfObjFd == 0 { attr.AttachBtfObjFd = uint32(module.FD()) defer module.Close() } @@ -851,6 +893,9 @@ func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) { var ctxOut []byte if opts.ContextOut != nil { ctxOut = make([]byte, binary.Size(opts.ContextOut)) + } else if platform.IsWindows && len(ctxIn) > 0 { + // Windows rejects a non-zero ctxIn with a nil ctxOut. + ctxOut = make([]byte, len(ctxIn)) } attr := sys.ProgRunAttr{ @@ -868,6 +913,16 @@ func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) { Cpu: opts.CPU, } + if p.Type() == Syscall && ctxIn != nil && ctxOut != nil { + // Linux syscall program errors on non-nil ctxOut, uses ctxIn + // for both input and output. Shield the user from this wart. + if len(ctxIn) != len(ctxOut) { + return 0, 0, errors.New("length mismatch: Context and ContextOut") + } + attr.CtxOut, attr.CtxSizeOut = sys.TypedPointer[uint8]{}, 0 + ctxOut = ctxIn + } + retry: for { err := sys.ProgRun(&attr) @@ -914,7 +969,7 @@ retry: opts.DataOut = opts.DataOut[:int(attr.DataSizeOut)] } - if len(ctxOut) != 0 { + if opts.ContextOut != nil { b := bytes.NewReader(ctxOut) if err := binary.Read(b, internal.NativeEndian, opts.ContextOut); err != nil { return 0, 0, fmt.Errorf("failed to decode ContextOut: %v", err) @@ -968,20 +1023,16 @@ func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) return nil, fmt.Errorf("%s is not a Program", fileName) } - info, err := newProgramInfoFromFd(fd) - if err != nil { - _ = fd.Close() - return nil, fmt.Errorf("info for %s: %w", fileName, err) - } + p, err := newProgramFromFD(fd) + if err == nil { + p.pinnedPath = fileName - var progName string - if haveObjName() == nil { - progName = info.Name - } else { - progName = filepath.Base(fileName) + if haveObjName() != nil { + p.name = filepath.Base(fileName) + } } - return &Program{"", fd, progName, fileName, info.Type}, nil + return p, err } // ProgramGetNextID returns the ID of the next eBPF program. @@ -1017,7 +1068,7 @@ var errUnrecognizedAttachType = errors.New("unrecognized attach type") // // Returns errUnrecognizedAttachType if the combination of progType and attachType // is not recognised. -func findProgramTargetInKernel(name string, progType ProgramType, attachType AttachType) (*btf.Handle, btf.TypeID, error) { +func findProgramTargetInKernel(name string, progType ProgramType, attachType AttachType, cache *btf.Cache) (*btf.Handle, btf.TypeID, error) { type match struct { p ProgramType a AttachType @@ -1029,6 +1080,10 @@ func findProgramTargetInKernel(name string, progType ProgramType, attachType Att ) switch (match{progType, attachType}) { + case match{StructOps, AttachStructOps}: + typeName = name + featureName = "struct_ops " + name + target = (*btf.Struct)(nil) case match{LSM, AttachLSMMac}: typeName = "bpf_lsm_" + name featureName = name + " LSM hook" @@ -1057,12 +1112,7 @@ func findProgramTargetInKernel(name string, progType ProgramType, attachType Att return nil, 0, errUnrecognizedAttachType } - spec, err := btf.LoadKernelSpec() - if err != nil { - return nil, 0, fmt.Errorf("load kernel spec: %w", err) - } - - spec, module, err := findTargetInKernel(spec, typeName, &target) + spec, module, err := findTargetInKernel(typeName, &target, cache) if errors.Is(err, btf.ErrNotFound) { return nil, 0, &internal.UnsupportedFeatureError{Name: featureName} } @@ -1092,14 +1142,15 @@ func findProgramTargetInKernel(name string, progType ProgramType, attachType Att // // Returns a non-nil handle if the type was found in a module, or btf.ErrNotFound // if the type wasn't found at all. -func findTargetInKernel(kernelSpec *btf.Spec, typeName string, target *btf.Type) (*btf.Spec, *btf.Handle, error) { - if kernelSpec == nil { - return nil, nil, fmt.Errorf("nil kernelSpec: %w", btf.ErrNotFound) +func findTargetInKernel(typeName string, target *btf.Type, cache *btf.Cache) (*btf.Spec, *btf.Handle, error) { + kernelSpec, err := cache.Kernel() + if err != nil { + return nil, nil, err } - err := kernelSpec.TypeByName(typeName, target) + err = kernelSpec.TypeByName(typeName, target) if errors.Is(err, btf.ErrNotFound) { - spec, module, err := findTargetInModule(kernelSpec, typeName, target) + spec, module, err := findTargetInModule(typeName, target, cache) if err != nil { return nil, nil, fmt.Errorf("find target in modules: %w", err) } @@ -1117,7 +1168,7 @@ func findTargetInKernel(kernelSpec *btf.Spec, typeName string, target *btf.Type) // are searched in the order they were loaded. // // Returns btf.ErrNotFound if the target can't be found in any module. -func findTargetInModule(base *btf.Spec, typeName string, target *btf.Type) (*btf.Spec, *btf.Handle, error) { +func findTargetInModule(typeName string, target *btf.Type, cache *btf.Cache) (*btf.Spec, *btf.Handle, error) { it := new(btf.HandleIterator) defer it.Handle.Close() @@ -1131,7 +1182,7 @@ func findTargetInModule(base *btf.Spec, typeName string, target *btf.Type) (*btf continue } - spec, err := it.Handle.Spec(base) + spec, err := cache.Module(info.Name) if err != nil { return nil, nil, fmt.Errorf("parse types for module %s: %w", info.Name, err) } @@ -1191,19 +1242,3 @@ func findTargetInProgram(prog *Program, name string, progType ProgramType, attac return spec.TypeID(targetFunc) } - -func newBTFCache(opts *ProgramOptions) *btf.Cache { - c := btf.NewCache() - if opts.KernelTypes != nil { - c.KernelTypes = opts.KernelTypes - c.ModuleTypes = opts.KernelModuleTypes - if opts.KernelModuleTypes != nil { - c.LoadedModules = []string{} - for name := range opts.KernelModuleTypes { - c.LoadedModules = append(c.LoadedModules, name) - } - sort.Strings(c.LoadedModules) - } - } - return c -} diff --git a/vendor/github.com/cilium/ebpf/staticcheck.conf b/vendor/github.com/cilium/ebpf/staticcheck.conf new file mode 100644 index 000000000..cfc907da3 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/staticcheck.conf @@ -0,0 +1,3 @@ +# Default configuration from https://staticcheck.dev/docs/configuration with +# SA4003 disabled. Remove when https://github.com/cilium/ebpf/issues/1876 is fixed. +checks = ["all", "-SA9003", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022", "-ST1023", "-SA4003"] diff --git a/vendor/github.com/cilium/ebpf/struct_ops.go b/vendor/github.com/cilium/ebpf/struct_ops.go new file mode 100644 index 000000000..162f344ea --- /dev/null +++ b/vendor/github.com/cilium/ebpf/struct_ops.go @@ -0,0 +1,139 @@ +package ebpf + +import ( + "fmt" + "reflect" + "strings" + + "github.com/cilium/ebpf/btf" + "github.com/cilium/ebpf/internal" +) + +const structOpsValuePrefix = "bpf_struct_ops_" + +// structOpsFindInnerType returns the "inner" struct inside a value struct_ops type. +// +// Given a value like: +// +// struct bpf_struct_ops_bpf_testmod_ops { +// struct bpf_struct_ops_common common; +// struct bpf_testmod_ops data; +// }; +// +// this function returns the *btf.Struct for "bpf_testmod_ops" along with the +// byte offset of the "data" member inside the value type. +// +// The inner struct name is derived by trimming the "bpf_struct_ops_" prefix +// from the value's name. +func structOpsFindInnerType(vType *btf.Struct) (*btf.Struct, uint32, error) { + innerName := strings.TrimPrefix(vType.Name, structOpsValuePrefix) + + for _, m := range vType.Members { + if st, ok := btf.As[*btf.Struct](m.Type); ok && st.Name == innerName { + return st, m.Offset.Bytes(), nil + } + } + + return nil, 0, fmt.Errorf("inner struct %q not found in %s", innerName, vType.Name) +} + +// structOpsFindTarget resolves the kernel-side "value struct" for a struct_ops map. +func structOpsFindTarget(userType *btf.Struct, cache *btf.Cache) (vType *btf.Struct, id btf.TypeID, module *btf.Handle, err error) { + // the kernel value type name, e.g. "bpf_struct_ops_" + vTypeName := structOpsValuePrefix + userType.Name + + target := btf.Type((*btf.Struct)(nil)) + spec, module, err := findTargetInKernel(vTypeName, &target, cache) + if err != nil { + return nil, 0, nil, fmt.Errorf("lookup value type %q: %w", vTypeName, err) + } + + id, err = spec.TypeID(target) + if err != nil { + return nil, 0, nil, err + } + + return target.(*btf.Struct), id, module, nil +} + +// structOpsPopulateValue writes a `prog FD` which references to `p` into the +// struct_ops value buffer `kernVData` at byte offset `dstOff` corresponding to +// the member `km`. +func structOpsPopulateValue(km btf.Member, kernVData []byte, p *Program) error { + kmPtr, ok := btf.As[*btf.Pointer](km.Type) + if !ok { + return fmt.Errorf("member %s is not a func pointer", km.Name) + } + + if _, isFuncProto := btf.As[*btf.FuncProto](kmPtr.Target); !isFuncProto { + return fmt.Errorf("member %s is not a func pointer", km.Name) + } + + dstOff := int(km.Offset.Bytes()) + if dstOff < 0 || dstOff+8 > len(kernVData) { + return fmt.Errorf("member %q: value buffer too small for func ptr", km.Name) + } + + internal.NativeEndian.PutUint64(kernVData[dstOff:dstOff+8], uint64(p.FD())) + return nil +} + +// structOpsCopyMember copies a single member from the user struct (m) +// into the kernel value struct (km) for struct_ops. +func structOpsCopyMember(m, km btf.Member, data []byte, kernVData []byte) error { + mSize, err := btf.Sizeof(m.Type) + if err != nil { + return fmt.Errorf("sizeof(user.%s): %w", m.Name, err) + } + kSize, err := btf.Sizeof(km.Type) + if err != nil { + return fmt.Errorf("sizeof(kernel.%s): %w", km.Name, err) + } + if mSize != kSize { + return fmt.Errorf("size mismatch for %s: user=%d kernel=%d", m.Name, mSize, kSize) + } + if km.BitfieldSize > 0 || m.BitfieldSize > 0 { + return fmt.Errorf("bitfield %s not supported", m.Name) + } + + srcOff := int(m.Offset.Bytes()) + dstOff := int(km.Offset.Bytes()) + + if srcOff < 0 || srcOff+mSize > len(data) { + return fmt.Errorf("member %q: userdata is too small", m.Name) + } + + if dstOff < 0 || dstOff+mSize > len(kernVData) { + return fmt.Errorf("member %q: value type is too small", m.Name) + } + + // skip mods(const, restrict, volatile and typetag) + // and typedef to check type compatibility + mType := btf.UnderlyingType(m.Type) + kernMType := btf.UnderlyingType(km.Type) + if reflect.TypeOf(mType) != reflect.TypeOf(kernMType) { + return fmt.Errorf("unmatched member type %s != %s (kernel)", m.Name, km.Name) + } + + switch mType.(type) { + case *btf.Struct, *btf.Union: + if !structOpsIsMemZeroed(data[srcOff : srcOff+mSize]) { + return fmt.Errorf("non-zero nested struct %s: %w", m.Name, ErrNotSupported) + } + // the bytes has zeroed value, we simply skip the copy. + return nil + } + + copy(kernVData[dstOff:dstOff+mSize], data[srcOff:srcOff+mSize]) + return nil +} + +// structOpsIsMemZeroed() checks whether all bytes in data are zero. +func structOpsIsMemZeroed(data []byte) bool { + for _, b := range data { + if b != 0 { + return false + } + } + return true +} diff --git a/vendor/github.com/cilium/ebpf/types.go b/vendor/github.com/cilium/ebpf/types.go index 56e318208..52ff75b5c 100644 --- a/vendor/github.com/cilium/ebpf/types.go +++ b/vendor/github.com/cilium/ebpf/types.go @@ -5,7 +5,7 @@ import ( "github.com/cilium/ebpf/internal/sys" ) -//go:generate go run golang.org/x/tools/cmd/stringer@latest -output types_string.go -type=MapType,ProgramType,PinType +//go:generate go tool stringer -output types_string.go -type=MapType,ProgramType,PinType // MapType indicates the type map structure // that will be initialized in the kernel. @@ -144,7 +144,7 @@ func (mt MapType) hasPerCPUValue() bool { // canStoreMapOrProgram returns true if the Map stores references to another Map // or Program. func (mt MapType) canStoreMapOrProgram() bool { - return mt.canStoreMap() || mt.canStoreProgram() + return mt.canStoreMap() || mt.canStoreProgram() || mt == StructOpsMap } // canStoreMap returns true if the map type accepts a map fd @@ -252,7 +252,7 @@ func ProgramTypeForPlatform(plat string, value uint32) (ProgramType, error) { // Will cause invalid argument (EINVAL) at program load time if set incorrectly. type AttachType uint32 -//go:generate go run golang.org/x/tools/cmd/stringer@latest -type AttachType -trimprefix Attach +//go:generate go tool stringer -type AttachType -trimprefix Attach // AttachNone is an alias for AttachCGroupInetIngress for readability reasons. const AttachNone AttachType = 0 diff --git a/vendor/github.com/cilium/ebpf/types_string.go b/vendor/github.com/cilium/ebpf/types_string.go index efcd6a7dd..94bc2e26c 100644 --- a/vendor/github.com/cilium/ebpf/types_string.go +++ b/vendor/github.com/cilium/ebpf/types_string.go @@ -162,8 +162,9 @@ const _PinType_name = "PinNonePinByName" var _PinType_index = [...]uint8{0, 7, 16} func (i PinType) String() string { - if i >= PinType(len(_PinType_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_PinType_index)-1 { return "PinType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _PinType_name[_PinType_index[i]:_PinType_index[i+1]] + return _PinType_name[_PinType_index[idx]:_PinType_index[idx+1]] } diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/decode/decode_protobuf.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/decode/decode_protobuf.go index 784330059..8590a783d 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/decode/decode_protobuf.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/decode/decode_protobuf.go @@ -8,6 +8,7 @@ import ( "github.com/netobserv/flowlogs-pipeline/pkg/config" "github.com/netobserv/netobserv-ebpf-agent/pkg/model" "github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow" + "github.com/netobserv/netobserv-ebpf-agent/pkg/utils" "github.com/mdlayher/ethernet" log "github.com/sirupsen/logrus" @@ -120,6 +121,9 @@ func RecordToMap(fr *model.Record) config.GenericMap { out["DnsFlags"] = fr.Metrics.AdditionalMetrics.DnsRecord.Flags out["DnsFlagsResponseCode"] = DNSRcodeToStr(uint32(fr.Metrics.AdditionalMetrics.DnsRecord.Flags) & 0xF) out["DnsLatencyMs"] = fr.DNSLatency.Milliseconds() + if name := utils.DNSRawNameToDotted(fr.Metrics.AdditionalMetrics.DnsRecord.Name[:]); name != "" { + out["DnsName"] = name + } } if fr.Metrics.AdditionalMetrics.PktDrops.LatestDropCause != 0 { diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.go index 400595e5e..1d8e230d0 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.go @@ -54,6 +54,7 @@ type BpfDnsRecordT struct { Id uint16 Flags uint16 Errno uint8 + Name [32]int8 _ [3]byte } diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.o b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.o index 54d7d1d9d..8889cec6e 100644 Binary files a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.o and b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_arm64_bpfel.o differ diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.go index dd023874b..ef44d0fb4 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.go @@ -54,6 +54,7 @@ type BpfDnsRecordT struct { Id uint16 Flags uint16 Errno uint8 + Name [32]int8 _ [3]byte } diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.o b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.o index ae6a7fe2c..7d2c86ee0 100644 Binary files a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.o and b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_powerpc_bpfel.o differ diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.go index fc25078be..950e855ac 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.go @@ -54,6 +54,7 @@ type BpfDnsRecordT struct { Id uint16 Flags uint16 Errno uint8 + Name [32]int8 _ [3]byte } diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.o b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.o index aa38ced8a..ef31715a4 100644 Binary files a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.o and b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_s390_bpfeb.o differ diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.go index 22c157d7a..b0a7158e8 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.go @@ -54,6 +54,7 @@ type BpfDnsRecordT struct { Id uint16 Flags uint16 Errno uint8 + Name [32]int8 _ [3]byte } diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.o b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.o index a1fdefe76..cbbe0157d 100644 Binary files a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.o and b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf/bpf_x86_bpfel.o differ diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/flow.pb.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/flow.pb.go index 6c52e6f3b..4dfe8aa34 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/flow.pb.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/flow.pb.go @@ -299,6 +299,7 @@ type Record struct { Sampling uint32 `protobuf:"varint,29,opt,name=sampling,proto3" json:"sampling,omitempty"` IpsecEncrypted uint32 `protobuf:"varint,30,opt,name=ipsec_encrypted,json=ipsecEncrypted,proto3" json:"ipsec_encrypted,omitempty"` IpsecEncryptedRet int32 `protobuf:"varint,31,opt,name=ipsec_encrypted_ret,json=ipsecEncryptedRet,proto3" json:"ipsec_encrypted_ret,omitempty"` + DnsName string `protobuf:"bytes,32,opt,name=dns_name,json=dnsName,proto3" json:"dns_name,omitempty"` } func (x *Record) Reset() { @@ -548,6 +549,13 @@ func (x *Record) GetIpsecEncryptedRet() int32 { return 0 } +func (x *Record) GetDnsName() string { + if x != nil { + return x.DnsName + } + return "" +} + type DataLink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -909,7 +917,7 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x0a, 0x0a, 0x06, 0x52, 0x65, 0x63, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbc, 0x0a, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x2f, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, @@ -991,46 +999,47 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x73, 0x65, 0x63, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x70, 0x73, 0x65, 0x63, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x69, 0x70, 0x73, 0x65, 0x63, - 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x52, 0x65, 0x74, 0x22, 0x3c, 0x0a, 0x08, - 0x44, 0x61, 0x74, 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, - 0x6d, 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, - 0x63, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x64, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x6b, 0x0a, 0x07, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, - 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, - 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x73, 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x04, 0x64, 0x73, 0x63, 0x70, 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, - 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, - 0x70, 0x76, 0x34, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, - 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, - 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x58, 0x6c, 0x61, 0x74, 0x12, 0x25, - 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, - 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, - 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, - 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, - 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x06, 0x7a, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x2a, 0x24, 0x0a, 0x09, 0x44, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, - 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, - 0x01, 0x32, 0x3e, 0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, - 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x52, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x4c, + 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17, 0x0a, 0x07, + 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, + 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x6b, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, + 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, + 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x73, 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x64, 0x73, + 0x63, 0x70, 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, + 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, + 0x69, 0x70, 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, + 0x79, 0x22, 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x58, 0x6c, 0x61, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, + 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, + 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, + 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, + 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, + 0x07, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, + 0x7a, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x2a, 0x24, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, 0x09, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, 0x6e, + 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, + 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/proto.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/proto.go index b844c9a0a..360e15be9 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/proto.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow/proto.go @@ -3,9 +3,11 @@ package pbflow import ( "encoding/binary" "net" + "strings" "github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf" "github.com/netobserv/netobserv-ebpf-agent/pkg/model" + "github.com/netobserv/netobserv-ebpf-agent/pkg/utils" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -76,6 +78,10 @@ func FlowToPB(fr *model.Record) *Record { pbflowRecord.DnsId = uint32(fr.Metrics.AdditionalMetrics.DnsRecord.Id) pbflowRecord.DnsFlags = uint32(fr.Metrics.AdditionalMetrics.DnsRecord.Flags) pbflowRecord.DnsErrno = uint32(fr.Metrics.AdditionalMetrics.DnsRecord.Errno) + // Export DNS name if present (parse DNS label format) + if name := utils.DNSRawNameToDotted(fr.Metrics.AdditionalMetrics.DnsRecord.Name[:]); name != "" { + pbflowRecord.DnsName = name + } if fr.Metrics.AdditionalMetrics.DnsRecord.Latency != 0 { pbflowRecord.DnsLatency = durationpb.New(fr.DNSLatency) } @@ -159,6 +165,7 @@ func PBToFlow(pb *Record) *model.Record { }, DnsRecord: ebpf.BpfDnsRecordT{ Id: uint16(pb.DnsId), + Name: stringToInt8Array(pb.DnsName), Flags: uint16(pb.DnsFlags), Errno: uint8(pb.DnsErrno), Latency: uint64(pb.DnsLatency.AsDuration()), @@ -247,3 +254,46 @@ func macToUint8(mac uint64) [6]uint8 { uint8(mac), } } + +// stringToInt8Array converts a Go string to DNS label format in a fixed-size int8 array +func stringToInt8Array(s string) [32]int8 { + var result [32]int8 + pos := 0 + + // Handle empty string + if s == "" { + return result + } + + // Split string by dots and encode each label with length prefix + labels := strings.Split(s, ".") + for _, label := range labels { + if pos >= 31 { // Leave space for null terminator + break + } + labelLen := len(label) + if labelLen == 0 { // Skip empty labels + continue + } + if labelLen > 63 { // DNS label max length + labelLen = 63 + } + if pos+labelLen+1 > 31 { // Check if we have space for length + label + break + } + + result[pos] = int8(labelLen) + pos++ + for i := 0; i < labelLen; i++ { + result[pos] = int8(label[i]) + pos++ + } + } + + // Null terminate + if pos < 32 { + result[pos] = 0 + } + + return result +} diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/utils/utils.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/utils/utils.go index 3f6eac124..a1f5837e6 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/utils/utils.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/utils/utils.go @@ -14,3 +14,47 @@ func GetSocket(hostIP string, hostPort int) string { } return socket } + +// DNSRawNameToDotted parses a label-encoded DNS QNAME (raw bytes copied from kernel) +// into a dotted string. Stops on NUL, compression pointer, or bounds. +func DNSRawNameToDotted(rawI8 []int8) string { + // Convert to byte slice up to first NUL + b := make([]byte, 0, len(rawI8)) + for i := 0; i < len(rawI8); i++ { + if rawI8[i] == 0 { // NUL terminator placed in kernel copy + break + } + b = append(b, byte(rawI8[i])) + } + if len(b) == 0 { + return "" + } + out := make([]byte, 0, len(b)) + i := 0 + first := true + for i < len(b) { + l := int(b[i]) + if l == 0 { + break + } + // Stop on compression pointer (0xC0xx) since we didn't follow it in kernel + // l is the length byte of a DNS label. + // 0xC0 in binary is 11000000. + // The bitwise AND l & 0xC0 isolates the top two bits of l. + // If the result equals 0xC0, it indicates a compression pointer. + if (l & 0xC0) == 0xC0 { + break + } + i++ + if i+l > len(b) { + break + } + if !first { + out = append(out, '.') + } + first = false + out = append(out, b[i:i+l]...) + i += l + } + return string(out) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c9cec8d7a..8433f5117 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -42,8 +42,8 @@ github.com/cenkalti/rpc2/jsonrpc # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 -# github.com/cilium/ebpf v0.19.0 -## explicit; go 1.23.0 +# github.com/cilium/ebpf v0.20.0 +## explicit; go 1.24.0 github.com/cilium/ebpf github.com/cilium/ebpf/asm github.com/cilium/ebpf/btf @@ -306,7 +306,7 @@ github.com/netobserv/loki-client-go/pkg/logproto github.com/netobserv/loki-client-go/pkg/metric github.com/netobserv/loki-client-go/pkg/metrics github.com/netobserv/loki-client-go/pkg/urlutil -# github.com/netobserv/netobserv-ebpf-agent v1.10.0-community +# github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e ## explicit; go 1.24.0 github.com/netobserv/netobserv-ebpf-agent/pkg/decode github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf