Upgrade containerd/cgroups to remove github.com/cilium/ebpf's fuzzer
The fuzzer is broken and it breaks OSS-Fuzz according to #7288. Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
This commit is contained in:
		
							
								
								
									
										14
									
								
								vendor/github.com/cilium/ebpf/link/cgroup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/cilium/ebpf/link/cgroup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -56,16 +56,6 @@ func AttachCgroup(opts CgroupOptions) (Link, error) {
 | 
			
		||||
	return cg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedCgroup loads a pinned cgroup from a bpffs.
 | 
			
		||||
func LoadPinnedCgroup(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
 | 
			
		||||
	link, err := LoadPinnedRawLink(fileName, CgroupType, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &linkCgroup{*link}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type progAttachCgroup struct {
 | 
			
		||||
	cgroup     *os.File
 | 
			
		||||
	current    *ebpf.Program
 | 
			
		||||
@@ -151,6 +141,10 @@ func (cg *progAttachCgroup) Unpin() error {
 | 
			
		||||
	return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cg *progAttachCgroup) Info() (*Info, error) {
 | 
			
		||||
	return nil, fmt.Errorf("can't get cgroup info: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type linkCgroup struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								vendor/github.com/cilium/ebpf/link/freplace.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/cilium/ebpf/link/freplace.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,88 +0,0 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type FreplaceLink struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachFreplace attaches the given eBPF program to the function it replaces.
 | 
			
		||||
//
 | 
			
		||||
// The program and name can either be provided at link time, or can be provided
 | 
			
		||||
// at program load time. If they were provided at load time, they should be nil
 | 
			
		||||
// and empty respectively here, as they will be ignored by the kernel.
 | 
			
		||||
// Examples:
 | 
			
		||||
//
 | 
			
		||||
//	AttachFreplace(dispatcher, "function", replacement)
 | 
			
		||||
//	AttachFreplace(nil, "", replacement)
 | 
			
		||||
func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (*FreplaceLink, error) {
 | 
			
		||||
	if (name == "") != (targetProg == nil) {
 | 
			
		||||
		return nil, fmt.Errorf("must provide both or neither of name and targetProg: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog == nil {
 | 
			
		||||
		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog.Type() != ebpf.Extension {
 | 
			
		||||
		return nil, fmt.Errorf("eBPF program type %s is not an Extension: %w", prog.Type(), errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		target int
 | 
			
		||||
		typeID btf.TypeID
 | 
			
		||||
	)
 | 
			
		||||
	if targetProg != nil {
 | 
			
		||||
		info, err := targetProg.Info()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		btfID, ok := info.BTFID()
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, fmt.Errorf("could not get BTF ID for program %s: %w", info.Name, errInvalidInput)
 | 
			
		||||
		}
 | 
			
		||||
		btfHandle, err := btf.NewHandleFromID(btfID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer btfHandle.Close()
 | 
			
		||||
 | 
			
		||||
		var function *btf.Func
 | 
			
		||||
		if err := btfHandle.Spec().FindType(name, &function); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		target = targetProg.FD()
 | 
			
		||||
		typeID = function.ID()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	link, err := AttachRawLink(RawLinkOptions{
 | 
			
		||||
		Target:  target,
 | 
			
		||||
		Program: prog,
 | 
			
		||||
		Attach:  ebpf.AttachNone,
 | 
			
		||||
		BTF:     typeID,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &FreplaceLink{*link}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update implements the Link interface.
 | 
			
		||||
func (f *FreplaceLink) Update(new *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("freplace update: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedFreplace loads a pinned iterator from a bpffs.
 | 
			
		||||
func LoadPinnedFreplace(fileName string, opts *ebpf.LoadPinOptions) (*FreplaceLink, error) {
 | 
			
		||||
	link, err := LoadPinnedRawLink(fileName, TracingType, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &FreplaceLink{*link}, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/cilium/ebpf/link/iter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/cilium/ebpf/link/iter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IterOptions struct {
 | 
			
		||||
@@ -31,26 +31,26 @@ func AttachIter(opts IterOptions) (*Iter, error) {
 | 
			
		||||
 | 
			
		||||
	progFd := opts.Program.FD()
 | 
			
		||||
	if progFd < 0 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var info bpfIterLinkInfoMap
 | 
			
		||||
	if opts.Map != nil {
 | 
			
		||||
		mapFd := opts.Map.FD()
 | 
			
		||||
		if mapFd < 0 {
 | 
			
		||||
			return nil, fmt.Errorf("invalid map: %w", internal.ErrClosedFd)
 | 
			
		||||
			return nil, fmt.Errorf("invalid map: %w", sys.ErrClosedFd)
 | 
			
		||||
		}
 | 
			
		||||
		info.map_fd = uint32(mapFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfLinkCreateIterAttr{
 | 
			
		||||
		prog_fd:       uint32(progFd),
 | 
			
		||||
		attach_type:   ebpf.AttachTraceIter,
 | 
			
		||||
		iter_info:     internal.NewPointer(unsafe.Pointer(&info)),
 | 
			
		||||
		iter_info_len: uint32(unsafe.Sizeof(info)),
 | 
			
		||||
	attr := sys.LinkCreateIterAttr{
 | 
			
		||||
		ProgFd:      uint32(progFd),
 | 
			
		||||
		AttachType:  sys.AttachType(ebpf.AttachTraceIter),
 | 
			
		||||
		IterInfo:    sys.NewPointer(unsafe.Pointer(&info)),
 | 
			
		||||
		IterInfoLen: uint32(unsafe.Sizeof(info)),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfLinkCreateIter(&attr)
 | 
			
		||||
	fd, err := sys.LinkCreateIter(&attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't link iterator: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -58,16 +58,6 @@ func AttachIter(opts IterOptions) (*Iter, error) {
 | 
			
		||||
	return &Iter{RawLink{fd, ""}}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedIter loads a pinned iterator from a bpffs.
 | 
			
		||||
func LoadPinnedIter(fileName string, opts *ebpf.LoadPinOptions) (*Iter, error) {
 | 
			
		||||
	link, err := LoadPinnedRawLink(fileName, IterType, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Iter{*link}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Iter represents an attached bpf_iter.
 | 
			
		||||
type Iter struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
@@ -77,16 +67,11 @@ type Iter struct {
 | 
			
		||||
//
 | 
			
		||||
// Reading from the returned reader triggers the BPF program.
 | 
			
		||||
func (it *Iter) Open() (io.ReadCloser, error) {
 | 
			
		||||
	linkFd, err := it.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	attr := &sys.IterCreateAttr{
 | 
			
		||||
		LinkFd: it.fd.Uint(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := &bpfIterCreateAttr{
 | 
			
		||||
		linkFd: linkFd,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfIterCreate(attr)
 | 
			
		||||
	fd, err := sys.IterCreate(attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't create iterator: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										234
									
								
								vendor/github.com/cilium/ebpf/link/kprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										234
									
								
								vendor/github.com/cilium/ebpf/link/kprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,11 +8,13 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -28,6 +30,27 @@ var (
 | 
			
		||||
 | 
			
		||||
type probeType uint8
 | 
			
		||||
 | 
			
		||||
type probeArgs struct {
 | 
			
		||||
	symbol, group, path          string
 | 
			
		||||
	offset, refCtrOffset, cookie uint64
 | 
			
		||||
	pid                          int
 | 
			
		||||
	ret                          bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KprobeOptions defines additional parameters that will be used
 | 
			
		||||
// when loading Kprobes.
 | 
			
		||||
type KprobeOptions struct {
 | 
			
		||||
	// Arbitrary value that can be fetched from an eBPF program
 | 
			
		||||
	// via `bpf_get_attach_cookie()`.
 | 
			
		||||
	//
 | 
			
		||||
	// Needs kernel 5.15+.
 | 
			
		||||
	Cookie uint64
 | 
			
		||||
	// Offset of the kprobe relative to the traced symbol.
 | 
			
		||||
	// Can be used to insert kprobes at arbitrary offsets in kernel functions,
 | 
			
		||||
	// e.g. in places where functions have been inlined.
 | 
			
		||||
	Offset uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	kprobeType probeType = iota
 | 
			
		||||
	uprobeType
 | 
			
		||||
@@ -71,70 +94,109 @@ func (pt probeType) RetprobeBit() (uint64, error) {
 | 
			
		||||
// given kernel symbol starts executing. See /proc/kallsyms for available
 | 
			
		||||
// symbols. For example, printk():
 | 
			
		||||
//
 | 
			
		||||
//	kp, err := Kprobe("printk", prog)
 | 
			
		||||
//	kp, err := Kprobe("printk", prog, nil)
 | 
			
		||||
//
 | 
			
		||||
// Losing the reference to the resulting Link (kp) will close the Kprobe
 | 
			
		||||
// and prevent further execution of prog. The Link must be Closed during
 | 
			
		||||
// program shutdown to avoid leaking system resources.
 | 
			
		||||
func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
	k, err := kprobe(symbol, prog, false)
 | 
			
		||||
func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
 | 
			
		||||
	k, err := kprobe(symbol, prog, opts, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = k.attach(prog)
 | 
			
		||||
	lnk, err := attachPerfEvent(k, prog)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		k.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k, nil
 | 
			
		||||
	return lnk, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Kretprobe attaches the given eBPF program to a perf event that fires right
 | 
			
		||||
// before the given kernel symbol exits, with the function stack left intact.
 | 
			
		||||
// See /proc/kallsyms for available symbols. For example, printk():
 | 
			
		||||
//
 | 
			
		||||
//	kp, err := Kretprobe("printk", prog)
 | 
			
		||||
//	kp, err := Kretprobe("printk", prog, nil)
 | 
			
		||||
//
 | 
			
		||||
// Losing the reference to the resulting Link (kp) will close the Kretprobe
 | 
			
		||||
// and prevent further execution of prog. The Link must be Closed during
 | 
			
		||||
// program shutdown to avoid leaking system resources.
 | 
			
		||||
func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
	k, err := kprobe(symbol, prog, true)
 | 
			
		||||
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
 | 
			
		||||
	k, err := kprobe(symbol, prog, opts, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = k.attach(prog)
 | 
			
		||||
	lnk, err := attachPerfEvent(k, prog)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		k.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return k, nil
 | 
			
		||||
	return lnk, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isValidKprobeSymbol implements the equivalent of a regex match
 | 
			
		||||
// against "^[a-zA-Z_][0-9a-zA-Z_.]*$".
 | 
			
		||||
func isValidKprobeSymbol(s string) bool {
 | 
			
		||||
	if len(s) < 1 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, c := range []byte(s) {
 | 
			
		||||
		switch {
 | 
			
		||||
		case c >= 'a' && c <= 'z':
 | 
			
		||||
		case c >= 'A' && c <= 'Z':
 | 
			
		||||
		case c == '_':
 | 
			
		||||
		case i > 0 && c >= '0' && c <= '9':
 | 
			
		||||
 | 
			
		||||
		// Allow `.` in symbol name. GCC-compiled kernel may change symbol name
 | 
			
		||||
		// to have a `.isra.$n` suffix, like `udp_send_skb.isra.52`.
 | 
			
		||||
		// See: https://gcc.gnu.org/gcc-10/changes.html
 | 
			
		||||
		case i > 0 && c == '.':
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// kprobe opens a perf event on the given symbol and attaches prog to it.
 | 
			
		||||
// If ret is true, create a kretprobe.
 | 
			
		||||
func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
 | 
			
		||||
func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*perfEvent, error) {
 | 
			
		||||
	if symbol == "" {
 | 
			
		||||
		return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog == nil {
 | 
			
		||||
		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if !rgxTraceEvent.MatchString(symbol) {
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s' must be alphanumeric or underscore: %w", symbol, errInvalidInput)
 | 
			
		||||
	if !isValidKprobeSymbol(symbol) {
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s' must be a valid symbol in /proc/kallsyms: %w", symbol, errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog.Type() != ebpf.Kprobe {
 | 
			
		||||
		return nil, fmt.Errorf("eBPF program type %s is not a Kprobe: %w", prog.Type(), errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	args := probeArgs{
 | 
			
		||||
		pid:    perfAllThreads,
 | 
			
		||||
		symbol: symbol,
 | 
			
		||||
		ret:    ret,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts != nil {
 | 
			
		||||
		args.cookie = opts.Cookie
 | 
			
		||||
		args.offset = opts.Offset
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use kprobe PMU if the kernel has it available.
 | 
			
		||||
	tp, err := pmuKprobe(platformPrefix(symbol), ret)
 | 
			
		||||
	tp, err := pmuKprobe(args)
 | 
			
		||||
	if errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
		tp, err = pmuKprobe(symbol, ret)
 | 
			
		||||
		args.symbol = platformPrefix(symbol)
 | 
			
		||||
		tp, err = pmuKprobe(args)
 | 
			
		||||
	}
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return tp, nil
 | 
			
		||||
@@ -144,9 +206,11 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use tracefs if kprobe PMU is missing.
 | 
			
		||||
	tp, err = tracefsKprobe(platformPrefix(symbol), ret)
 | 
			
		||||
	args.symbol = symbol
 | 
			
		||||
	tp, err = tracefsKprobe(args)
 | 
			
		||||
	if errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
		tp, err = tracefsKprobe(symbol, ret)
 | 
			
		||||
		args.symbol = platformPrefix(symbol)
 | 
			
		||||
		tp, err = tracefsKprobe(args)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err)
 | 
			
		||||
@@ -157,8 +221,8 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
 | 
			
		||||
 | 
			
		||||
// pmuKprobe opens a perf event based on the kprobe PMU.
 | 
			
		||||
// Returns os.ErrNotExist if the given symbol does not exist in the kernel.
 | 
			
		||||
func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
 | 
			
		||||
	return pmuProbe(kprobeType, symbol, "", 0, perfAllThreads, ret)
 | 
			
		||||
func pmuKprobe(args probeArgs) (*perfEvent, error) {
 | 
			
		||||
	return pmuProbe(kprobeType, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pmuProbe opens a perf event based on a Performance Monitoring Unit.
 | 
			
		||||
@@ -168,7 +232,7 @@ func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
 | 
			
		||||
// 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU"
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU
 | 
			
		||||
func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
 | 
			
		||||
func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
 | 
			
		||||
	// Getting the PMU type will fail if the kernel doesn't support
 | 
			
		||||
	// the perf_[k,u]probe PMU.
 | 
			
		||||
	et, err := getPMUEventType(typ)
 | 
			
		||||
@@ -177,7 +241,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var config uint64
 | 
			
		||||
	if ret {
 | 
			
		||||
	if args.ret {
 | 
			
		||||
		bit, err := typ.RetprobeBit()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
@@ -192,22 +256,30 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bo
 | 
			
		||||
	switch typ {
 | 
			
		||||
	case kprobeType:
 | 
			
		||||
		// Create a pointer to a NUL-terminated string for the kernel.
 | 
			
		||||
		sp, err = unsafeStringPtr(symbol)
 | 
			
		||||
		sp, err = unsafeStringPtr(args.symbol)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attr = unix.PerfEventAttr{
 | 
			
		||||
			// The minimum size required for PMU kprobes is PERF_ATTR_SIZE_VER1,
 | 
			
		||||
			// since it added the config2 (Ext2) field. Use Ext2 as probe_offset.
 | 
			
		||||
			Size:   unix.PERF_ATTR_SIZE_VER1,
 | 
			
		||||
			Type:   uint32(et),          // PMU event type read from sysfs
 | 
			
		||||
			Ext1:   uint64(uintptr(sp)), // Kernel symbol to trace
 | 
			
		||||
			Ext2:   args.offset,         // Kernel symbol offset
 | 
			
		||||
			Config: config,              // Retprobe flag
 | 
			
		||||
		}
 | 
			
		||||
	case uprobeType:
 | 
			
		||||
		sp, err = unsafeStringPtr(path)
 | 
			
		||||
		sp, err = unsafeStringPtr(args.path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if args.refCtrOffset != 0 {
 | 
			
		||||
			config |= args.refCtrOffset << uprobeRefCtrOffsetShift
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attr = unix.PerfEventAttr{
 | 
			
		||||
			// The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1,
 | 
			
		||||
			// since it added the config2 (Ext2) field. The Size field controls the
 | 
			
		||||
@@ -216,23 +288,34 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bo
 | 
			
		||||
			Size:   unix.PERF_ATTR_SIZE_VER1,
 | 
			
		||||
			Type:   uint32(et),          // PMU event type read from sysfs
 | 
			
		||||
			Ext1:   uint64(uintptr(sp)), // Uprobe path
 | 
			
		||||
			Ext2:   offset,              // Uprobe offset
 | 
			
		||||
			Config: config,              // Retprobe flag
 | 
			
		||||
			Ext2:   args.offset,         // Uprobe offset
 | 
			
		||||
			Config: config,              // RefCtrOffset, Retprobe flag
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
 | 
			
		||||
	rawFd, err := unix.PerfEventOpen(&attr, args.pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
 | 
			
		||||
 | 
			
		||||
	// On some old kernels, kprobe PMU doesn't allow `.` in symbol names and
 | 
			
		||||
	// return -EINVAL. Return ErrNotSupported to allow falling back to tracefs.
 | 
			
		||||
	// https://github.com/torvalds/linux/blob/94710cac0ef4/kernel/trace/trace_kprobe.c#L340-L343
 | 
			
		||||
	if errors.Is(err, unix.EINVAL) && strings.Contains(args.symbol, ".") {
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s+%#x': older kernels don't accept dots: %w", args.symbol, args.offset, ErrNotSupported)
 | 
			
		||||
	}
 | 
			
		||||
	// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
 | 
			
		||||
	// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
 | 
			
		||||
	// is returned to the caller.
 | 
			
		||||
	if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist)
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s+%#x' not found: %w", args.symbol, args.offset, os.ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
	// Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved
 | 
			
		||||
	// to an invalid insn boundary.
 | 
			
		||||
	if errors.Is(err, syscall.EILSEQ) {
 | 
			
		||||
		return nil, fmt.Errorf("symbol '%s+%#x' not found (bad insn boundary): %w", args.symbol, args.offset, os.ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
	// Since at least commit cb9a19fe4aa51, ENOTSUPP is returned
 | 
			
		||||
	// when attempting to set a uprobe on a trap instruction.
 | 
			
		||||
	if errors.Is(err, unix.ENOTSUPP) {
 | 
			
		||||
		return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", offset, err)
 | 
			
		||||
		return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", args.offset, err)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("opening perf event: %w", err)
 | 
			
		||||
@@ -241,18 +324,24 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bo
 | 
			
		||||
	// Ensure the string pointer is not collected before PerfEventOpen returns.
 | 
			
		||||
	runtime.KeepAlive(sp)
 | 
			
		||||
 | 
			
		||||
	fd, err := sys.NewFD(rawFd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Kernel has perf_[k,u]probe PMU available, initialize perf event.
 | 
			
		||||
	return &perfEvent{
 | 
			
		||||
		fd:    internal.NewFD(uint32(fd)),
 | 
			
		||||
		pmuID: et,
 | 
			
		||||
		name:  symbol,
 | 
			
		||||
		typ:   typ.PerfEventType(ret),
 | 
			
		||||
		typ:    typ.PerfEventType(args.ret),
 | 
			
		||||
		name:   args.symbol,
 | 
			
		||||
		pmuID:  et,
 | 
			
		||||
		cookie: args.cookie,
 | 
			
		||||
		fd:     fd,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tracefsKprobe creates a Kprobe tracefs entry.
 | 
			
		||||
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
 | 
			
		||||
	return tracefsProbe(kprobeType, symbol, "", 0, perfAllThreads, ret)
 | 
			
		||||
func tracefsKprobe(args probeArgs) (*perfEvent, error) {
 | 
			
		||||
	return tracefsProbe(kprobeType, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tracefsProbe creates a trace event by writing an entry to <tracefs>/[k,u]probe_events.
 | 
			
		||||
@@ -261,7 +350,7 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
 | 
			
		||||
// Path and offset are only set in the case of uprobe(s) and are used to set
 | 
			
		||||
// the executable/library path on the filesystem and the offset where the probe is inserted.
 | 
			
		||||
// A perf event is then opened on the newly-created trace event and returned to the caller.
 | 
			
		||||
func tracefsProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
 | 
			
		||||
func tracefsProbe(typ probeType, args probeArgs) (_ *perfEvent, err error) {
 | 
			
		||||
	// Generate a random string for each trace event we attempt to create.
 | 
			
		||||
	// This value is used as the 'group' token in tracefs to allow creating
 | 
			
		||||
	// multiple kprobe trace events with the same name.
 | 
			
		||||
@@ -269,42 +358,53 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, pid int, re
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("randomizing group name: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	args.group = group
 | 
			
		||||
 | 
			
		||||
	// Before attempting to create a trace event through tracefs,
 | 
			
		||||
	// check if an event with the same group and name already exists.
 | 
			
		||||
	// Kernels 4.x and earlier don't return os.ErrExist on writing a duplicate
 | 
			
		||||
	// entry, so we need to rely on reads for detecting uniqueness.
 | 
			
		||||
	_, err = getTraceEventID(group, symbol)
 | 
			
		||||
	_, err = getTraceEventID(group, args.symbol)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol)
 | 
			
		||||
		return nil, fmt.Errorf("trace event already exists: %s/%s", group, args.symbol)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil && !errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
		return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err)
 | 
			
		||||
		return nil, fmt.Errorf("checking trace event %s/%s: %w", group, args.symbol, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create the [k,u]probe trace event using tracefs.
 | 
			
		||||
	if err := createTraceFSProbeEvent(typ, group, symbol, path, offset, ret); err != nil {
 | 
			
		||||
	if err := createTraceFSProbeEvent(typ, args); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("creating probe entry on tracefs: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Make sure we clean up the created tracefs event when we return error.
 | 
			
		||||
			// If a livepatch handler is already active on the symbol, the write to
 | 
			
		||||
			// tracefs will succeed, a trace event will show up, but creating the
 | 
			
		||||
			// perf event will fail with EBUSY.
 | 
			
		||||
			_ = closeTraceFSProbeEvent(typ, args.group, args.symbol)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// Get the newly-created trace event's id.
 | 
			
		||||
	tid, err := getTraceEventID(group, symbol)
 | 
			
		||||
	tid, err := getTraceEventID(group, args.symbol)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("getting trace event id: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Kprobes are ephemeral tracepoints and share the same perf event type.
 | 
			
		||||
	fd, err := openTracepointPerfEvent(tid, pid)
 | 
			
		||||
	fd, err := openTracepointPerfEvent(tid, args.pid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &perfEvent{
 | 
			
		||||
		fd:        fd,
 | 
			
		||||
		typ:       typ.PerfEventType(args.ret),
 | 
			
		||||
		group:     group,
 | 
			
		||||
		name:      symbol,
 | 
			
		||||
		name:      args.symbol,
 | 
			
		||||
		tracefsID: tid,
 | 
			
		||||
		typ:       typ.PerfEventType(ret),
 | 
			
		||||
		cookie:    args.cookie,
 | 
			
		||||
		fd:        fd,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -312,7 +412,7 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, pid int, re
 | 
			
		||||
// <tracefs>/[k,u]probe_events. Returns os.ErrNotExist if symbol is not a valid
 | 
			
		||||
// kernel symbol, or if it is not traceable with kprobes. Returns os.ErrExist
 | 
			
		||||
// if a probe with the same group and symbol already exists.
 | 
			
		||||
func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset uint64, ret bool) error {
 | 
			
		||||
func createTraceFSProbeEvent(typ probeType, args probeArgs) error {
 | 
			
		||||
	// Open the kprobe_events file in tracefs.
 | 
			
		||||
	f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -320,7 +420,7 @@ func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset u
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	var pe string
 | 
			
		||||
	var pe, token string
 | 
			
		||||
	switch typ {
 | 
			
		||||
	case kprobeType:
 | 
			
		||||
		// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt):
 | 
			
		||||
@@ -337,7 +437,8 @@ func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset u
 | 
			
		||||
		// subsampling or rate limiting logic can be more accurately implemented in
 | 
			
		||||
		// the eBPF program itself.
 | 
			
		||||
		// See Documentation/kprobes.txt for more details.
 | 
			
		||||
		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, symbol)
 | 
			
		||||
		token = kprobeToken(args)
 | 
			
		||||
		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, sanitizeSymbol(args.symbol), token)
 | 
			
		||||
	case uprobeType:
 | 
			
		||||
		// The uprobe_events syntax is as follows:
 | 
			
		||||
		// p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a probe
 | 
			
		||||
@@ -346,18 +447,30 @@ func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset u
 | 
			
		||||
		//
 | 
			
		||||
		// Some examples:
 | 
			
		||||
		// r:ebpf_1234/readline /bin/bash:0x12345
 | 
			
		||||
		// p:ebpf_5678/main_mySymbol /bin/mybin:0x12345
 | 
			
		||||
		// p:ebpf_5678/main_mySymbol /bin/mybin:0x12345(0x123)
 | 
			
		||||
		//
 | 
			
		||||
		// See Documentation/trace/uprobetracer.txt for more details.
 | 
			
		||||
		pathOffset := uprobePathOffset(path, offset)
 | 
			
		||||
		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, pathOffset)
 | 
			
		||||
		token = uprobeToken(args)
 | 
			
		||||
		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, args.symbol, token)
 | 
			
		||||
	}
 | 
			
		||||
	_, err = f.WriteString(pe)
 | 
			
		||||
	// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
 | 
			
		||||
	// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
 | 
			
		||||
	// is returned to the caller.
 | 
			
		||||
	// EINVAL is also returned on pre-5.2 kernels when the `SYM[+offs]` token
 | 
			
		||||
	// is resolved to an invalid insn boundary.
 | 
			
		||||
	if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
 | 
			
		||||
		return fmt.Errorf("symbol %s not found: %w", symbol, os.ErrNotExist)
 | 
			
		||||
		return fmt.Errorf("token %s: %w", token, os.ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
	// Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved
 | 
			
		||||
	// to an invalid insn boundary.
 | 
			
		||||
	if errors.Is(err, syscall.EILSEQ) {
 | 
			
		||||
		return fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
	// ERANGE is returned when the `SYM[+offs]` token is too big and cannot
 | 
			
		||||
	// be resolved.
 | 
			
		||||
	if errors.Is(err, syscall.ERANGE) {
 | 
			
		||||
		return fmt.Errorf("token %s: offset too big: %w", token, os.ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err)
 | 
			
		||||
@@ -377,7 +490,7 @@ func closeTraceFSProbeEvent(typ probeType, group, symbol string) error {
 | 
			
		||||
 | 
			
		||||
	// See [k,u]probe_events syntax above. The probe type does not need to be specified
 | 
			
		||||
	// for removals.
 | 
			
		||||
	pe := fmt.Sprintf("-:%s/%s", group, symbol)
 | 
			
		||||
	pe := fmt.Sprintf("-:%s/%s", group, sanitizeSymbol(symbol))
 | 
			
		||||
	if _, err = f.WriteString(pe); err != nil {
 | 
			
		||||
		return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -388,9 +501,9 @@ func closeTraceFSProbeEvent(typ probeType, group, symbol string) error {
 | 
			
		||||
// randomGroup generates a pseudorandom string for use as a tracefs group name.
 | 
			
		||||
// Returns an error when the output string would exceed 63 characters (kernel
 | 
			
		||||
// limitation), when rand.Read() fails or when prefix contains characters not
 | 
			
		||||
// allowed by rgxTraceEvent.
 | 
			
		||||
// allowed by isValidTraceID.
 | 
			
		||||
func randomGroup(prefix string) (string, error) {
 | 
			
		||||
	if !rgxTraceEvent.MatchString(prefix) {
 | 
			
		||||
	if !isValidTraceID(prefix) {
 | 
			
		||||
		return "", fmt.Errorf("prefix '%s' must be alphanumeric or underscore: %w", prefix, errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -442,3 +555,14 @@ func kretprobeBit() (uint64, error) {
 | 
			
		||||
	})
 | 
			
		||||
	return kprobeRetprobeBit.value, kprobeRetprobeBit.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// kprobeToken creates the SYM[+offs] token for the tracefs api.
 | 
			
		||||
func kprobeToken(args probeArgs) string {
 | 
			
		||||
	po := args.symbol
 | 
			
		||||
 | 
			
		||||
	if args.offset != 0 {
 | 
			
		||||
		po += fmt.Sprintf("+%#x", args.offset)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return po
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										220
									
								
								vendor/github.com/cilium/ebpf/link/link.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										220
									
								
								vendor/github.com/cilium/ebpf/link/link.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,12 +1,14 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/btf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var ErrNotSupported = internal.ErrNotSupported
 | 
			
		||||
@@ -35,12 +37,53 @@ type Link interface {
 | 
			
		||||
	// not called.
 | 
			
		||||
	Close() error
 | 
			
		||||
 | 
			
		||||
	// Info returns metadata on a link.
 | 
			
		||||
	//
 | 
			
		||||
	// May return an error wrapping ErrNotSupported.
 | 
			
		||||
	Info() (*Info, error)
 | 
			
		||||
 | 
			
		||||
	// Prevent external users from implementing this interface.
 | 
			
		||||
	isLink()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedLink loads a link that was persisted into a bpffs.
 | 
			
		||||
func LoadPinnedLink(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
 | 
			
		||||
	raw, err := loadPinnedRawLink(fileName, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return wrapRawLink(raw)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wrap a RawLink in a more specific type if possible.
 | 
			
		||||
//
 | 
			
		||||
// The function takes ownership of raw and closes it on error.
 | 
			
		||||
func wrapRawLink(raw *RawLink) (Link, error) {
 | 
			
		||||
	info, err := raw.Info()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		raw.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch info.Type {
 | 
			
		||||
	case RawTracepointType:
 | 
			
		||||
		return &rawTracepoint{*raw}, nil
 | 
			
		||||
	case TracingType:
 | 
			
		||||
		return &tracing{*raw}, nil
 | 
			
		||||
	case CgroupType:
 | 
			
		||||
		return &linkCgroup{*raw}, nil
 | 
			
		||||
	case IterType:
 | 
			
		||||
		return &Iter{*raw}, nil
 | 
			
		||||
	case NetNsType:
 | 
			
		||||
		return &NetNsLink{*raw}, nil
 | 
			
		||||
	default:
 | 
			
		||||
		return raw, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID uniquely identifies a BPF link.
 | 
			
		||||
type ID uint32
 | 
			
		||||
type ID = sys.LinkID
 | 
			
		||||
 | 
			
		||||
// RawLinkOptions control the creation of a raw link.
 | 
			
		||||
type RawLinkOptions struct {
 | 
			
		||||
@@ -52,13 +95,53 @@ type RawLinkOptions struct {
 | 
			
		||||
	Attach ebpf.AttachType
 | 
			
		||||
	// BTF is the BTF of the attachment target.
 | 
			
		||||
	BTF btf.TypeID
 | 
			
		||||
	// Flags control the attach behaviour.
 | 
			
		||||
	Flags uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RawLinkInfo contains metadata on a link.
 | 
			
		||||
type RawLinkInfo struct {
 | 
			
		||||
// Info contains metadata on a link.
 | 
			
		||||
type Info struct {
 | 
			
		||||
	Type    Type
 | 
			
		||||
	ID      ID
 | 
			
		||||
	Program ebpf.ProgramID
 | 
			
		||||
	extra   interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TracingInfo sys.TracingLinkInfo
 | 
			
		||||
type CgroupInfo sys.CgroupLinkInfo
 | 
			
		||||
type NetNsInfo sys.NetNsLinkInfo
 | 
			
		||||
type XDPInfo sys.XDPLinkInfo
 | 
			
		||||
 | 
			
		||||
// Tracing returns tracing type-specific link info.
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if the type-specific link info isn't available.
 | 
			
		||||
func (r Info) Tracing() *TracingInfo {
 | 
			
		||||
	e, _ := r.extra.(*TracingInfo)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cgroup returns cgroup type-specific link info.
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if the type-specific link info isn't available.
 | 
			
		||||
func (r Info) Cgroup() *CgroupInfo {
 | 
			
		||||
	e, _ := r.extra.(*CgroupInfo)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NetNs returns netns type-specific link info.
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if the type-specific link info isn't available.
 | 
			
		||||
func (r Info) NetNs() *NetNsInfo {
 | 
			
		||||
	e, _ := r.extra.(*NetNsInfo)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExtraNetNs returns XDP type-specific link info.
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if the type-specific link info isn't available.
 | 
			
		||||
func (r Info) XDP() *XDPInfo {
 | 
			
		||||
	e, _ := r.extra.(*XDPInfo)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RawLink is the low-level API to bpf_link.
 | 
			
		||||
@@ -66,7 +149,7 @@ type RawLinkInfo struct {
 | 
			
		||||
// You should consider using the higher level interfaces in this
 | 
			
		||||
// package instead.
 | 
			
		||||
type RawLink struct {
 | 
			
		||||
	fd         *internal.FD
 | 
			
		||||
	fd         *sys.FD
 | 
			
		||||
	pinnedPath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -77,21 +160,22 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Target < 0 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd)
 | 
			
		||||
		return nil, fmt.Errorf("invalid target: %s", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	progFd := opts.Program.FD()
 | 
			
		||||
	if progFd < 0 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfLinkCreateAttr{
 | 
			
		||||
		targetFd:    uint32(opts.Target),
 | 
			
		||||
		progFd:      uint32(progFd),
 | 
			
		||||
		attachType:  opts.Attach,
 | 
			
		||||
		targetBTFID: uint32(opts.BTF),
 | 
			
		||||
	attr := sys.LinkCreateAttr{
 | 
			
		||||
		TargetFd:    uint32(opts.Target),
 | 
			
		||||
		ProgFd:      uint32(progFd),
 | 
			
		||||
		AttachType:  sys.AttachType(opts.Attach),
 | 
			
		||||
		TargetBtfId: uint32(opts.BTF),
 | 
			
		||||
		Flags:       opts.Flags,
 | 
			
		||||
	}
 | 
			
		||||
	fd, err := bpfLinkCreate(&attr)
 | 
			
		||||
	fd, err := sys.LinkCreate(&attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't create link: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -99,44 +183,23 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 | 
			
		||||
	return &RawLink{fd, ""}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedRawLink loads a persisted link from a bpffs.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if the pinned link type doesn't match linkType. Pass
 | 
			
		||||
// UnspecifiedType to disable this behaviour.
 | 
			
		||||
func LoadPinnedRawLink(fileName string, linkType Type, opts *ebpf.LoadPinOptions) (*RawLink, error) {
 | 
			
		||||
	fd, err := internal.BPFObjGet(fileName, opts.Marshal())
 | 
			
		||||
func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, error) {
 | 
			
		||||
	fd, err := sys.ObjGet(&sys.ObjGetAttr{
 | 
			
		||||
		Pathname:  sys.NewStringPointer(fileName),
 | 
			
		||||
		FileFlags: opts.Marshal(),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("load pinned link: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	link := &RawLink{fd, fileName}
 | 
			
		||||
	if linkType == UnspecifiedType {
 | 
			
		||||
		return link, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info, err := link.Info()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		link.Close()
 | 
			
		||||
		return nil, fmt.Errorf("get pinned link info: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if info.Type != linkType {
 | 
			
		||||
		link.Close()
 | 
			
		||||
		return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, linkType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return link, nil
 | 
			
		||||
	return &RawLink{fd, fileName}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *RawLink) isLink() {}
 | 
			
		||||
 | 
			
		||||
// FD returns the raw file descriptor.
 | 
			
		||||
func (l *RawLink) FD() int {
 | 
			
		||||
	fd, err := l.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
	return int(fd)
 | 
			
		||||
	return l.fd.Int()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close breaks the link.
 | 
			
		||||
@@ -185,49 +248,66 @@ type RawLinkUpdateOptions struct {
 | 
			
		||||
func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
 | 
			
		||||
	newFd := opts.New.FD()
 | 
			
		||||
	if newFd < 0 {
 | 
			
		||||
		return fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
 | 
			
		||||
		return fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var oldFd int
 | 
			
		||||
	if opts.Old != nil {
 | 
			
		||||
		oldFd = opts.Old.FD()
 | 
			
		||||
		if oldFd < 0 {
 | 
			
		||||
			return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
 | 
			
		||||
			return fmt.Errorf("invalid replacement program: %s", sys.ErrClosedFd)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	linkFd, err := l.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("can't update link: %s", err)
 | 
			
		||||
	attr := sys.LinkUpdateAttr{
 | 
			
		||||
		LinkFd:    l.fd.Uint(),
 | 
			
		||||
		NewProgFd: uint32(newFd),
 | 
			
		||||
		OldProgFd: uint32(oldFd),
 | 
			
		||||
		Flags:     opts.Flags,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfLinkUpdateAttr{
 | 
			
		||||
		linkFd:    linkFd,
 | 
			
		||||
		newProgFd: uint32(newFd),
 | 
			
		||||
		oldProgFd: uint32(oldFd),
 | 
			
		||||
		flags:     opts.Flags,
 | 
			
		||||
	}
 | 
			
		||||
	return bpfLinkUpdate(&attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// struct bpf_link_info
 | 
			
		||||
type bpfLinkInfo struct {
 | 
			
		||||
	typ     uint32
 | 
			
		||||
	id      uint32
 | 
			
		||||
	prog_id uint32
 | 
			
		||||
	return sys.LinkUpdate(&attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info returns metadata about the link.
 | 
			
		||||
func (l *RawLink) Info() (*RawLinkInfo, error) {
 | 
			
		||||
	var info bpfLinkInfo
 | 
			
		||||
	err := internal.BPFObjGetInfoByFD(l.fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
func (l *RawLink) Info() (*Info, error) {
 | 
			
		||||
	var info sys.LinkInfo
 | 
			
		||||
 | 
			
		||||
	if err := sys.ObjInfo(l.fd, &info); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("link info: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &RawLinkInfo{
 | 
			
		||||
		Type(info.typ),
 | 
			
		||||
		ID(info.id),
 | 
			
		||||
		ebpf.ProgramID(info.prog_id),
 | 
			
		||||
	var extra interface{}
 | 
			
		||||
	switch info.Type {
 | 
			
		||||
	case CgroupType:
 | 
			
		||||
		extra = &CgroupInfo{}
 | 
			
		||||
	case IterType:
 | 
			
		||||
		// not supported
 | 
			
		||||
	case NetNsType:
 | 
			
		||||
		extra = &NetNsInfo{}
 | 
			
		||||
	case RawTracepointType:
 | 
			
		||||
		// not supported
 | 
			
		||||
	case TracingType:
 | 
			
		||||
		extra = &TracingInfo{}
 | 
			
		||||
	case XDPType:
 | 
			
		||||
		extra = &XDPInfo{}
 | 
			
		||||
	case PerfEventType:
 | 
			
		||||
		// no extra
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("unknown link info type: %d", info.Type)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if info.Type != RawTracepointType && info.Type != IterType && info.Type != PerfEventType {
 | 
			
		||||
		buf := bytes.NewReader(info.Extra[:])
 | 
			
		||||
		err := binary.Read(buf, internal.NativeEndian, extra)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("can not read extra link info: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Info{
 | 
			
		||||
		info.Type,
 | 
			
		||||
		info.Id,
 | 
			
		||||
		ebpf.ProgramID(info.ProgId),
 | 
			
		||||
		extra,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/cilium/ebpf/link/netns.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/cilium/ebpf/link/netns.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,14 +6,9 @@ import (
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NetNsInfo contains metadata about a network namespace link.
 | 
			
		||||
type NetNsInfo struct {
 | 
			
		||||
	RawLinkInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NetNsLink is a program attached to a network namespace.
 | 
			
		||||
type NetNsLink struct {
 | 
			
		||||
	*RawLink
 | 
			
		||||
	RawLink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachNetNs attaches a program to a network namespace.
 | 
			
		||||
@@ -37,24 +32,5 @@ func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &NetNsLink{link}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedNetNs loads a network namespace link from bpffs.
 | 
			
		||||
func LoadPinnedNetNs(fileName string, opts *ebpf.LoadPinOptions) (*NetNsLink, error) {
 | 
			
		||||
	link, err := LoadPinnedRawLink(fileName, NetNsType, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &NetNsLink{link}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info returns information about the link.
 | 
			
		||||
func (nns *NetNsLink) Info() (*NetNsInfo, error) {
 | 
			
		||||
	info, err := nns.RawLink.Info()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &NetNsInfo{*info}, nil
 | 
			
		||||
	return &NetNsLink{*link}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										260
									
								
								vendor/github.com/cilium/ebpf/link/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										260
									
								
								vendor/github.com/cilium/ebpf/link/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,14 +6,15 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/asm"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -43,11 +44,6 @@ import (
 | 
			
		||||
var (
 | 
			
		||||
	tracefsPath = "/sys/kernel/debug/tracing"
 | 
			
		||||
 | 
			
		||||
	// 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.
 | 
			
		||||
	rgxTraceEvent = regexp.MustCompile("^[a-zA-Z_][0-9a-zA-Z_]*$")
 | 
			
		||||
 | 
			
		||||
	errInvalidInput = errors.New("invalid input")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +65,8 @@ const (
 | 
			
		||||
// can be attached to it. It is created based on a tracefs trace event or a
 | 
			
		||||
// Performance Monitoring Unit (PMU).
 | 
			
		||||
type perfEvent struct {
 | 
			
		||||
	// The event type determines the types of programs that can be attached.
 | 
			
		||||
	typ perfEventType
 | 
			
		||||
 | 
			
		||||
	// Group and name of the tracepoint/kprobe/uprobe.
 | 
			
		||||
	group string
 | 
			
		||||
@@ -79,53 +77,15 @@ type perfEvent struct {
 | 
			
		||||
	// ID of the trace event read from tracefs. Valid IDs are non-zero.
 | 
			
		||||
	tracefsID uint64
 | 
			
		||||
 | 
			
		||||
	// The event type determines the types of programs that can be attached.
 | 
			
		||||
	typ perfEventType
 | 
			
		||||
	// User provided arbitrary value.
 | 
			
		||||
	cookie uint64
 | 
			
		||||
 | 
			
		||||
	fd *internal.FD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pe *perfEvent) isLink() {}
 | 
			
		||||
 | 
			
		||||
func (pe *perfEvent) Pin(string) error {
 | 
			
		||||
	return fmt.Errorf("pin perf event: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pe *perfEvent) Unpin() error {
 | 
			
		||||
	return fmt.Errorf("unpin perf event: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Since 4.15 (e87c6bc3852b "bpf: permit multiple bpf attachments for a single perf event"),
 | 
			
		||||
// calling PERF_EVENT_IOC_SET_BPF appends the given program to a prog_array
 | 
			
		||||
// owned by the perf event, which means multiple programs can be attached
 | 
			
		||||
// simultaneously.
 | 
			
		||||
//
 | 
			
		||||
// Before 4.15, calling PERF_EVENT_IOC_SET_BPF more than once on a perf event
 | 
			
		||||
// returns EEXIST.
 | 
			
		||||
//
 | 
			
		||||
// Detaching a program from a perf event is currently not possible, so a
 | 
			
		||||
// program replacement mechanism cannot be implemented for perf events.
 | 
			
		||||
func (pe *perfEvent) Update(prog *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("can't replace eBPF program in perf event: %w", ErrNotSupported)
 | 
			
		||||
	// This is the perf event FD.
 | 
			
		||||
	fd *sys.FD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pe *perfEvent) Close() error {
 | 
			
		||||
	if pe.fd == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pfd, err := pe.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("getting perf event fd: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = unix.IoctlSetInt(int(pfd), unix.PERF_EVENT_IOC_DISABLE, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("disabling perf event: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = pe.fd.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if err := pe.fd.Close(); err != nil {
 | 
			
		||||
		return fmt.Errorf("closing perf event fd: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -148,49 +108,150 @@ func (pe *perfEvent) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// perfEventLink represents a bpf perf link.
 | 
			
		||||
type perfEventLink struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
	pe *perfEvent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pl *perfEventLink) isLink() {}
 | 
			
		||||
 | 
			
		||||
// Pinning requires the underlying perf event FD to stay open.
 | 
			
		||||
//
 | 
			
		||||
// | PerfEvent FD | BpfLink FD | Works |
 | 
			
		||||
// |--------------|------------|-------|
 | 
			
		||||
// | Open         | Open       | Yes   |
 | 
			
		||||
// | Closed       | Open       | No    |
 | 
			
		||||
// | Open         | Closed     | No (Pin() -> EINVAL) |
 | 
			
		||||
// | Closed       | Closed     | No (Pin() -> EINVAL) |
 | 
			
		||||
//
 | 
			
		||||
// There is currently no pretty way to recover the perf event FD
 | 
			
		||||
// when loading a pinned link, so leave as not supported for now.
 | 
			
		||||
func (pl *perfEventLink) Pin(string) error {
 | 
			
		||||
	return fmt.Errorf("perf event link pin: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pl *perfEventLink) Unpin() error {
 | 
			
		||||
	return fmt.Errorf("perf event link unpin: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pl *perfEventLink) Close() error {
 | 
			
		||||
	if err := pl.pe.Close(); err != nil {
 | 
			
		||||
		return fmt.Errorf("perf event link close: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return pl.fd.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pl *perfEventLink) Update(prog *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("perf event link update: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// perfEventIoctl implements Link and handles the perf event lifecycle
 | 
			
		||||
// via ioctl().
 | 
			
		||||
type perfEventIoctl struct {
 | 
			
		||||
	*perfEvent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pi *perfEventIoctl) isLink() {}
 | 
			
		||||
 | 
			
		||||
// Since 4.15 (e87c6bc3852b "bpf: permit multiple bpf attachments for a single perf event"),
 | 
			
		||||
// calling PERF_EVENT_IOC_SET_BPF appends the given program to a prog_array
 | 
			
		||||
// owned by the perf event, which means multiple programs can be attached
 | 
			
		||||
// simultaneously.
 | 
			
		||||
//
 | 
			
		||||
// Before 4.15, calling PERF_EVENT_IOC_SET_BPF more than once on a perf event
 | 
			
		||||
// returns EEXIST.
 | 
			
		||||
//
 | 
			
		||||
// Detaching a program from a perf event is currently not possible, so a
 | 
			
		||||
// program replacement mechanism cannot be implemented for perf events.
 | 
			
		||||
func (pi *perfEventIoctl) Update(prog *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("perf event ioctl update: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pi *perfEventIoctl) Pin(string) error {
 | 
			
		||||
	return fmt.Errorf("perf event ioctl pin: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pi *perfEventIoctl) Unpin() error {
 | 
			
		||||
	return fmt.Errorf("perf event ioctl unpin: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pi *perfEventIoctl) Info() (*Info, error) {
 | 
			
		||||
	return nil, fmt.Errorf("perf event ioctl info: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// attach the given eBPF prog to the perf event stored in pe.
 | 
			
		||||
// pe must contain a valid perf event fd.
 | 
			
		||||
// prog's type must match the program type stored in pe.
 | 
			
		||||
func (pe *perfEvent) attach(prog *ebpf.Program) error {
 | 
			
		||||
func attachPerfEvent(pe *perfEvent, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
	if prog == nil {
 | 
			
		||||
		return errors.New("cannot attach a nil program")
 | 
			
		||||
	}
 | 
			
		||||
	if pe.fd == nil {
 | 
			
		||||
		return errors.New("cannot attach to nil perf event")
 | 
			
		||||
		return nil, errors.New("cannot attach a nil program")
 | 
			
		||||
	}
 | 
			
		||||
	if prog.FD() < 0 {
 | 
			
		||||
		return fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %w", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch pe.typ {
 | 
			
		||||
	case kprobeEvent, kretprobeEvent, uprobeEvent, uretprobeEvent:
 | 
			
		||||
		if t := prog.Type(); t != ebpf.Kprobe {
 | 
			
		||||
			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t)
 | 
			
		||||
			return nil, fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t)
 | 
			
		||||
		}
 | 
			
		||||
	case tracepointEvent:
 | 
			
		||||
		if t := prog.Type(); t != ebpf.TracePoint {
 | 
			
		||||
			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t)
 | 
			
		||||
			return nil, fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("unknown perf event type: %d", pe.typ)
 | 
			
		||||
		return nil, fmt.Errorf("unknown perf event type: %d", pe.typ)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The ioctl below will fail when the fd is invalid.
 | 
			
		||||
	kfd, _ := pe.fd.Value()
 | 
			
		||||
	if err := haveBPFLinkPerfEvent(); err == nil {
 | 
			
		||||
		return attachPerfEventLink(pe, prog)
 | 
			
		||||
	}
 | 
			
		||||
	return attachPerfEventIoctl(pe, prog)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func attachPerfEventIoctl(pe *perfEvent, prog *ebpf.Program) (*perfEventIoctl, error) {
 | 
			
		||||
	if pe.cookie != 0 {
 | 
			
		||||
		return nil, fmt.Errorf("cookies are not supported: %w", ErrNotSupported)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assign the eBPF program to the perf event.
 | 
			
		||||
	err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_SET_BPF, prog.FD())
 | 
			
		||||
	err := unix.IoctlSetInt(pe.fd.Int(), unix.PERF_EVENT_IOC_SET_BPF, prog.FD())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("setting perf event bpf program: %w", err)
 | 
			
		||||
		return nil, fmt.Errorf("setting perf event bpf program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// PERF_EVENT_IOC_ENABLE and _DISABLE ignore their given values.
 | 
			
		||||
	if err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_ENABLE, 0); err != nil {
 | 
			
		||||
		return fmt.Errorf("enable perf event: %s", err)
 | 
			
		||||
	if err := unix.IoctlSetInt(pe.fd.Int(), unix.PERF_EVENT_IOC_ENABLE, 0); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("enable perf event: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pi := &perfEventIoctl{pe}
 | 
			
		||||
 | 
			
		||||
	// Close the perf event when its reference is lost to avoid leaking system resources.
 | 
			
		||||
	runtime.SetFinalizer(pe, (*perfEvent).Close)
 | 
			
		||||
	return nil
 | 
			
		||||
	runtime.SetFinalizer(pi, (*perfEventIoctl).Close)
 | 
			
		||||
	return pi, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Use the bpf api to attach the perf event (BPF_LINK_TYPE_PERF_EVENT, 5.15+).
 | 
			
		||||
//
 | 
			
		||||
// https://github.com/torvalds/linux/commit/b89fbfbb854c9afc3047e8273cc3a694650b802e
 | 
			
		||||
func attachPerfEventLink(pe *perfEvent, prog *ebpf.Program) (*perfEventLink, error) {
 | 
			
		||||
	fd, err := sys.LinkCreatePerfEvent(&sys.LinkCreatePerfEventAttr{
 | 
			
		||||
		ProgFd:     uint32(prog.FD()),
 | 
			
		||||
		TargetFd:   pe.fd.Uint(),
 | 
			
		||||
		AttachType: sys.BPF_PERF_EVENT,
 | 
			
		||||
		BpfCookie:  pe.cookie,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("cannot create bpf perf link: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pl := &perfEventLink{RawLink{fd: fd}, pe}
 | 
			
		||||
 | 
			
		||||
	// Close the perf event when its reference is lost to avoid leaking system resources.
 | 
			
		||||
	runtime.SetFinalizer(pl, (*perfEventLink).Close)
 | 
			
		||||
	return pl, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// unsafeStringPtr returns an unsafe.Pointer to a NUL-terminated copy of str.
 | 
			
		||||
@@ -203,8 +264,12 @@ func unsafeStringPtr(str string) (unsafe.Pointer, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getTraceEventID reads a trace event's ID from tracefs given its group and name.
 | 
			
		||||
// group and name must be alphanumeric or underscore, as required by the kernel.
 | 
			
		||||
// The kernel requires group and name to be alphanumeric or underscore.
 | 
			
		||||
//
 | 
			
		||||
// name automatically has its invalid symbols converted to underscores so the caller
 | 
			
		||||
// can pass a raw symbol name, e.g. a kernel symbol containing dots.
 | 
			
		||||
func getTraceEventID(group, name string) (uint64, error) {
 | 
			
		||||
	name = sanitizeSymbol(name)
 | 
			
		||||
	tid, err := uint64FromFile(tracefsPath, "events", group, name, "id")
 | 
			
		||||
	if errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
		return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist)
 | 
			
		||||
@@ -235,7 +300,7 @@ func getPMUEventType(typ probeType) (uint64, error) {
 | 
			
		||||
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
 | 
			
		||||
// [k,u]probes created by writing to <tracefs>/[k,u]probe_events are tracepoints
 | 
			
		||||
// behind the scenes, and can be attached to using these perf events.
 | 
			
		||||
func openTracepointPerfEvent(tid uint64, pid int) (*internal.FD, error) {
 | 
			
		||||
func openTracepointPerfEvent(tid uint64, pid int) (*sys.FD, error) {
 | 
			
		||||
	attr := unix.PerfEventAttr{
 | 
			
		||||
		Type:        unix.PERF_TYPE_TRACEPOINT,
 | 
			
		||||
		Config:      tid,
 | 
			
		||||
@@ -249,7 +314,7 @@ func openTracepointPerfEvent(tid uint64, pid int) (*internal.FD, error) {
 | 
			
		||||
		return nil, fmt.Errorf("opening tracepoint perf event: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return internal.NewFD(uint32(fd)), nil
 | 
			
		||||
	return sys.NewFD(fd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uint64FromFile reads a uint64 from a file. All elements of path are sanitized
 | 
			
		||||
@@ -270,3 +335,60 @@ func uint64FromFile(base string, path ...string) (uint64, error) {
 | 
			
		||||
	et := bytes.TrimSpace(data)
 | 
			
		||||
	return strconv.ParseUint(string(et), 10, 64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Probe BPF perf link.
 | 
			
		||||
//
 | 
			
		||||
// https://elixir.bootlin.com/linux/v5.16.8/source/kernel/bpf/syscall.c#L4307
 | 
			
		||||
// https://github.com/torvalds/linux/commit/b89fbfbb854c9afc3047e8273cc3a694650b802e
 | 
			
		||||
var haveBPFLinkPerfEvent = internal.FeatureTest("bpf_link_perf_event", "5.15", func() error {
 | 
			
		||||
	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
 | 
			
		||||
		Name: "probe_bpf_perf_link",
 | 
			
		||||
		Type: ebpf.Kprobe,
 | 
			
		||||
		Instructions: asm.Instructions{
 | 
			
		||||
			asm.Mov.Imm(asm.R0, 0),
 | 
			
		||||
			asm.Return(),
 | 
			
		||||
		},
 | 
			
		||||
		License: "MIT",
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer prog.Close()
 | 
			
		||||
 | 
			
		||||
	_, err = sys.LinkCreatePerfEvent(&sys.LinkCreatePerfEventAttr{
 | 
			
		||||
		ProgFd:     uint32(prog.FD()),
 | 
			
		||||
		AttachType: sys.BPF_PERF_EVENT,
 | 
			
		||||
	})
 | 
			
		||||
	if errors.Is(err, unix.EINVAL) {
 | 
			
		||||
		return internal.ErrNotSupported
 | 
			
		||||
	}
 | 
			
		||||
	if errors.Is(err, unix.EBADF) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// isValidTraceID implements the equivalent of a regex match
 | 
			
		||||
// 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.
 | 
			
		||||
func isValidTraceID(s string) bool {
 | 
			
		||||
	if len(s) < 1 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i, c := range []byte(s) {
 | 
			
		||||
		switch {
 | 
			
		||||
		case c >= 'a' && c <= 'z':
 | 
			
		||||
		case c >= 'A' && c <= 'Z':
 | 
			
		||||
		case c == '_':
 | 
			
		||||
		case i > 0 && c >= '0' && c <= '9':
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/cilium/ebpf/link/program.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/cilium/ebpf/link/program.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,7 +4,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RawAttachProgramOptions struct {
 | 
			
		||||
@@ -34,7 +34,7 @@ func RawAttachProgram(opts RawAttachProgramOptions) error {
 | 
			
		||||
		replaceFd = uint32(opts.Replace.FD())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := internal.BPFProgAttachAttr{
 | 
			
		||||
	attr := sys.ProgAttachAttr{
 | 
			
		||||
		TargetFd:     uint32(opts.Target),
 | 
			
		||||
		AttachBpfFd:  uint32(opts.Program.FD()),
 | 
			
		||||
		ReplaceBpfFd: replaceFd,
 | 
			
		||||
@@ -42,7 +42,7 @@ func RawAttachProgram(opts RawAttachProgramOptions) error {
 | 
			
		||||
		AttachFlags:  uint32(opts.Flags),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := internal.BPFProgAttach(&attr); err != nil {
 | 
			
		||||
	if err := sys.ProgAttach(&attr); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't attach program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -63,12 +63,12 @@ func RawDetachProgram(opts RawDetachProgramOptions) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := internal.BPFProgDetachAttr{
 | 
			
		||||
	attr := sys.ProgDetachAttr{
 | 
			
		||||
		TargetFd:    uint32(opts.Target),
 | 
			
		||||
		AttachBpfFd: uint32(opts.Program.FD()),
 | 
			
		||||
		AttachType:  uint32(opts.Attach),
 | 
			
		||||
	}
 | 
			
		||||
	if err := internal.BPFProgDetach(&attr); err != nil {
 | 
			
		||||
	if err := sys.ProgDetach(&attr); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't detach program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +1,11 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RawTracepointOptions struct {
 | 
			
		||||
@@ -22,40 +23,65 @@ func AttachRawTracepoint(opts RawTracepointOptions) (Link, error) {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program type %s, expected RawTracepoint(Writable)", t)
 | 
			
		||||
	}
 | 
			
		||||
	if opts.Program.FD() < 0 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
 | 
			
		||||
		return nil, fmt.Errorf("invalid program: %w", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfRawTracepointOpen(&bpfRawTracepointOpenAttr{
 | 
			
		||||
		name: internal.NewStringPointer(opts.Name),
 | 
			
		||||
		fd:   uint32(opts.Program.FD()),
 | 
			
		||||
	fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
 | 
			
		||||
		Name:   sys.NewStringPointer(opts.Name),
 | 
			
		||||
		ProgFd: uint32(opts.Program.FD()),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &progAttachRawTracepoint{fd: fd}, nil
 | 
			
		||||
	err = haveBPFLink()
 | 
			
		||||
	if errors.Is(err, ErrNotSupported) {
 | 
			
		||||
		// Prior to commit 70ed506c3bbc ("bpf: Introduce pinnable bpf_link abstraction")
 | 
			
		||||
		// raw_tracepoints are just a plain fd.
 | 
			
		||||
		return &simpleRawTracepoint{fd}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &rawTracepoint{RawLink{fd: fd}}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type progAttachRawTracepoint struct {
 | 
			
		||||
	fd *internal.FD
 | 
			
		||||
type simpleRawTracepoint struct {
 | 
			
		||||
	fd *sys.FD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Link = (*progAttachRawTracepoint)(nil)
 | 
			
		||||
var _ Link = (*simpleRawTracepoint)(nil)
 | 
			
		||||
 | 
			
		||||
func (rt *progAttachRawTracepoint) isLink() {}
 | 
			
		||||
func (frt *simpleRawTracepoint) isLink() {}
 | 
			
		||||
 | 
			
		||||
func (rt *progAttachRawTracepoint) Close() error {
 | 
			
		||||
	return rt.fd.Close()
 | 
			
		||||
func (frt *simpleRawTracepoint) Close() error {
 | 
			
		||||
	return frt.fd.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rt *progAttachRawTracepoint) Update(_ *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("can't update raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
func (frt *simpleRawTracepoint) Update(_ *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("update raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rt *progAttachRawTracepoint) Pin(_ string) error {
 | 
			
		||||
	return fmt.Errorf("can't pin raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
func (frt *simpleRawTracepoint) Pin(string) error {
 | 
			
		||||
	return fmt.Errorf("pin raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rt *progAttachRawTracepoint) Unpin() error {
 | 
			
		||||
func (frt *simpleRawTracepoint) Unpin() error {
 | 
			
		||||
	return fmt.Errorf("unpin raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frt *simpleRawTracepoint) Info() (*Info, error) {
 | 
			
		||||
	return nil, fmt.Errorf("can't get raw_tracepoint info: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type rawTracepoint struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Link = (*rawTracepoint)(nil)
 | 
			
		||||
 | 
			
		||||
func (rt *rawTracepoint) Update(_ *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("update raw_tracepoint: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								vendor/github.com/cilium/ebpf/link/socket_filter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/cilium/ebpf/link/socket_filter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AttachSocketFilter attaches a SocketFilter BPF program to a socket.
 | 
			
		||||
func AttachSocketFilter(conn syscall.Conn, program *ebpf.Program) error {
 | 
			
		||||
	rawConn, err := conn.SyscallConn()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	var ssoErr error
 | 
			
		||||
	err = rawConn.Control(func(fd uintptr) {
 | 
			
		||||
		ssoErr = syscall.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_ATTACH_BPF, program.FD())
 | 
			
		||||
	})
 | 
			
		||||
	if ssoErr != nil {
 | 
			
		||||
		return ssoErr
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetachSocketFilter detaches a SocketFilter BPF program from a socket.
 | 
			
		||||
func DetachSocketFilter(conn syscall.Conn) error {
 | 
			
		||||
	rawConn, err := conn.SyscallConn()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	var ssoErr error
 | 
			
		||||
	err = rawConn.Control(func(fd uintptr) {
 | 
			
		||||
		ssoErr = syscall.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_DETACH_BPF, 0)
 | 
			
		||||
	})
 | 
			
		||||
	if ssoErr != nil {
 | 
			
		||||
		return ssoErr
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								vendor/github.com/cilium/ebpf/link/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										126
									
								
								vendor/github.com/cilium/ebpf/link/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,35 +2,33 @@ package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/asm"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Type is the kind of link.
 | 
			
		||||
type Type uint32
 | 
			
		||||
type Type = sys.LinkType
 | 
			
		||||
 | 
			
		||||
// Valid link types.
 | 
			
		||||
//
 | 
			
		||||
// Equivalent to enum bpf_link_type.
 | 
			
		||||
const (
 | 
			
		||||
	UnspecifiedType Type = iota
 | 
			
		||||
	RawTracepointType
 | 
			
		||||
	TracingType
 | 
			
		||||
	CgroupType
 | 
			
		||||
	IterType
 | 
			
		||||
	NetNsType
 | 
			
		||||
	XDPType
 | 
			
		||||
	UnspecifiedType   = sys.BPF_LINK_TYPE_UNSPEC
 | 
			
		||||
	RawTracepointType = sys.BPF_LINK_TYPE_RAW_TRACEPOINT
 | 
			
		||||
	TracingType       = sys.BPF_LINK_TYPE_TRACING
 | 
			
		||||
	CgroupType        = sys.BPF_LINK_TYPE_CGROUP
 | 
			
		||||
	IterType          = sys.BPF_LINK_TYPE_ITER
 | 
			
		||||
	NetNsType         = sys.BPF_LINK_TYPE_NETNS
 | 
			
		||||
	XDPType           = sys.BPF_LINK_TYPE_XDP
 | 
			
		||||
	PerfEventType     = sys.BPF_LINK_TYPE_PERF_EVENT
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
 | 
			
		||||
	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
 | 
			
		||||
		Type:       ebpf.CGroupSKB,
 | 
			
		||||
		AttachType: ebpf.AttachCGroupInetIngress,
 | 
			
		||||
		License:    "MIT",
 | 
			
		||||
		Type:    ebpf.CGroupSKB,
 | 
			
		||||
		License: "MIT",
 | 
			
		||||
		Instructions: asm.Instructions{
 | 
			
		||||
			asm.Mov.Imm(asm.R0, 0),
 | 
			
		||||
			asm.Return(),
 | 
			
		||||
@@ -69,7 +67,7 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace
 | 
			
		||||
	// We know that we have BPF_PROG_ATTACH since we can load CGroupSKB programs.
 | 
			
		||||
	// If passing BPF_F_REPLACE gives us EINVAL we know that the feature isn't
 | 
			
		||||
	// present.
 | 
			
		||||
	attr := internal.BPFProgAttachAttr{
 | 
			
		||||
	attr := sys.ProgAttachAttr{
 | 
			
		||||
		// We rely on this being checked after attachFlags.
 | 
			
		||||
		TargetFd:    ^uint32(0),
 | 
			
		||||
		AttachBpfFd: uint32(prog.FD()),
 | 
			
		||||
@@ -77,7 +75,7 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace
 | 
			
		||||
		AttachFlags: uint32(flagReplace),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = internal.BPFProgAttach(&attr)
 | 
			
		||||
	err = sys.ProgAttach(&attr)
 | 
			
		||||
	if errors.Is(err, unix.EINVAL) {
 | 
			
		||||
		return internal.ErrNotSupported
 | 
			
		||||
	}
 | 
			
		||||
@@ -87,73 +85,14 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace
 | 
			
		||||
	return err
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
type bpfLinkCreateAttr struct {
 | 
			
		||||
	progFd      uint32
 | 
			
		||||
	targetFd    uint32
 | 
			
		||||
	attachType  ebpf.AttachType
 | 
			
		||||
	flags       uint32
 | 
			
		||||
	targetBTFID uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfLinkCreate(attr *bpfLinkCreateAttr) (*internal.FD, error) {
 | 
			
		||||
	ptr, err := internal.BPF(internal.BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfLinkCreateIterAttr struct {
 | 
			
		||||
	prog_fd       uint32
 | 
			
		||||
	target_fd     uint32
 | 
			
		||||
	attach_type   ebpf.AttachType
 | 
			
		||||
	flags         uint32
 | 
			
		||||
	iter_info     internal.Pointer
 | 
			
		||||
	iter_info_len uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfLinkCreateIter(attr *bpfLinkCreateIterAttr) (*internal.FD, error) {
 | 
			
		||||
	ptr, err := internal.BPF(internal.BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfLinkUpdateAttr struct {
 | 
			
		||||
	linkFd    uint32
 | 
			
		||||
	newProgFd uint32
 | 
			
		||||
	flags     uint32
 | 
			
		||||
	oldProgFd uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfLinkUpdate(attr *bpfLinkUpdateAttr) error {
 | 
			
		||||
	_, err := internal.BPF(internal.BPF_LINK_UPDATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var haveBPFLink = internal.FeatureTest("bpf_link", "5.7", func() error {
 | 
			
		||||
	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
 | 
			
		||||
		Type:       ebpf.CGroupSKB,
 | 
			
		||||
		AttachType: ebpf.AttachCGroupInetIngress,
 | 
			
		||||
		License:    "MIT",
 | 
			
		||||
		Instructions: asm.Instructions{
 | 
			
		||||
			asm.Mov.Imm(asm.R0, 0),
 | 
			
		||||
			asm.Return(),
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return internal.ErrNotSupported
 | 
			
		||||
	}
 | 
			
		||||
	defer prog.Close()
 | 
			
		||||
 | 
			
		||||
	attr := bpfLinkCreateAttr{
 | 
			
		||||
	attr := sys.LinkCreateAttr{
 | 
			
		||||
		// This is a hopefully invalid file descriptor, which triggers EBADF.
 | 
			
		||||
		targetFd:   ^uint32(0),
 | 
			
		||||
		progFd:     uint32(prog.FD()),
 | 
			
		||||
		attachType: ebpf.AttachCGroupInetIngress,
 | 
			
		||||
		TargetFd:   ^uint32(0),
 | 
			
		||||
		ProgFd:     ^uint32(0),
 | 
			
		||||
		AttachType: sys.AttachType(ebpf.AttachCGroupInetIngress),
 | 
			
		||||
	}
 | 
			
		||||
	_, err = bpfLinkCreate(&attr)
 | 
			
		||||
	_, err := sys.LinkCreate(&attr)
 | 
			
		||||
	if errors.Is(err, unix.EINVAL) {
 | 
			
		||||
		return internal.ErrNotSupported
 | 
			
		||||
	}
 | 
			
		||||
@@ -162,30 +101,3 @@ var haveBPFLink = internal.FeatureTest("bpf_link", "5.7", func() error {
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
type bpfIterCreateAttr struct {
 | 
			
		||||
	linkFd uint32
 | 
			
		||||
	flags  uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfIterCreate(attr *bpfIterCreateAttr) (*internal.FD, error) {
 | 
			
		||||
	ptr, err := internal.BPF(internal.BPF_ITER_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfRawTracepointOpenAttr struct {
 | 
			
		||||
	name internal.Pointer
 | 
			
		||||
	fd   uint32
 | 
			
		||||
	_    uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfRawTracepointOpen(attr *bpfRawTracepointOpenAttr) (*internal.FD, error) {
 | 
			
		||||
	ptr, err := internal.BPF(internal.BPF_RAW_TRACEPOINT_OPEN, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/cilium/ebpf/link/tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/cilium/ebpf/link/tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,12 +6,22 @@ import (
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TracepointOptions defines additional parameters that will be used
 | 
			
		||||
// when loading Tracepoints.
 | 
			
		||||
type TracepointOptions struct {
 | 
			
		||||
	// Arbitrary value that can be fetched from an eBPF program
 | 
			
		||||
	// via `bpf_get_attach_cookie()`.
 | 
			
		||||
	//
 | 
			
		||||
	// Needs kernel 5.15+.
 | 
			
		||||
	Cookie uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tracepoint attaches the given eBPF program to the tracepoint with the given
 | 
			
		||||
// group and name. See /sys/kernel/debug/tracing/events to find available
 | 
			
		||||
// tracepoints. The top-level directory is the group, the event's subdirectory
 | 
			
		||||
// is the name. Example:
 | 
			
		||||
//
 | 
			
		||||
//	tp, err := Tracepoint("syscalls", "sys_enter_fork", prog)
 | 
			
		||||
//	tp, err := Tracepoint("syscalls", "sys_enter_fork", prog, nil)
 | 
			
		||||
//
 | 
			
		||||
// Losing the reference to the resulting Link (tp) will close the Tracepoint
 | 
			
		||||
// and prevent further execution of prog. The Link must be Closed during
 | 
			
		||||
@@ -19,14 +29,14 @@ import (
 | 
			
		||||
//
 | 
			
		||||
// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is
 | 
			
		||||
// only possible as of kernel 4.14 (commit cf5f5ce).
 | 
			
		||||
func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
func Tracepoint(group, name string, prog *ebpf.Program, opts *TracepointOptions) (Link, error) {
 | 
			
		||||
	if group == "" || name == "" {
 | 
			
		||||
		return nil, fmt.Errorf("group and name cannot be empty: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog == nil {
 | 
			
		||||
		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if !rgxTraceEvent.MatchString(group) || !rgxTraceEvent.MatchString(name) {
 | 
			
		||||
	if !isValidTraceID(group) || !isValidTraceID(name) {
 | 
			
		||||
		return nil, fmt.Errorf("group and name '%s/%s' must be alphanumeric or underscore: %w", group, name, errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog.Type() != ebpf.TracePoint {
 | 
			
		||||
@@ -43,18 +53,25 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pe := &perfEvent{
 | 
			
		||||
		fd:        fd,
 | 
			
		||||
		tracefsID: tid,
 | 
			
		||||
		group:     group,
 | 
			
		||||
		name:      name,
 | 
			
		||||
		typ:       tracepointEvent,
 | 
			
		||||
	var cookie uint64
 | 
			
		||||
	if opts != nil {
 | 
			
		||||
		cookie = opts.Cookie
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := pe.attach(prog); err != nil {
 | 
			
		||||
	pe := &perfEvent{
 | 
			
		||||
		typ:       tracepointEvent,
 | 
			
		||||
		group:     group,
 | 
			
		||||
		name:      name,
 | 
			
		||||
		tracefsID: tid,
 | 
			
		||||
		cookie:    cookie,
 | 
			
		||||
		fd:        fd,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lnk, err := attachPerfEvent(pe, prog)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		pe.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pe, nil
 | 
			
		||||
	return lnk, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										141
									
								
								vendor/github.com/cilium/ebpf/link/tracing.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								vendor/github.com/cilium/ebpf/link/tracing.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
	"github.com/cilium/ebpf/btf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/sys"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tracing struct {
 | 
			
		||||
	RawLink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *tracing) Update(new *ebpf.Program) error {
 | 
			
		||||
	return fmt.Errorf("tracing update: %w", ErrNotSupported)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachFreplace attaches the given eBPF program to the function it replaces.
 | 
			
		||||
//
 | 
			
		||||
// The program and name can either be provided at link time, or can be provided
 | 
			
		||||
// at program load time. If they were provided at load time, they should be nil
 | 
			
		||||
// and empty respectively here, as they will be ignored by the kernel.
 | 
			
		||||
// Examples:
 | 
			
		||||
//
 | 
			
		||||
//	AttachFreplace(dispatcher, "function", replacement)
 | 
			
		||||
//	AttachFreplace(nil, "", replacement)
 | 
			
		||||
func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (Link, error) {
 | 
			
		||||
	if (name == "") != (targetProg == nil) {
 | 
			
		||||
		return nil, fmt.Errorf("must provide both or neither of name and targetProg: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog == nil {
 | 
			
		||||
		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
	if prog.Type() != ebpf.Extension {
 | 
			
		||||
		return nil, fmt.Errorf("eBPF program type %s is not an Extension: %w", prog.Type(), errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		target int
 | 
			
		||||
		typeID btf.TypeID
 | 
			
		||||
	)
 | 
			
		||||
	if targetProg != nil {
 | 
			
		||||
		btfHandle, err := targetProg.Handle()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer btfHandle.Close()
 | 
			
		||||
 | 
			
		||||
		spec, err := btfHandle.Spec(nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var function *btf.Func
 | 
			
		||||
		if err := spec.TypeByName(name, &function); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		target = targetProg.FD()
 | 
			
		||||
		typeID, err = spec.TypeID(function)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	link, err := AttachRawLink(RawLinkOptions{
 | 
			
		||||
		Target:  target,
 | 
			
		||||
		Program: prog,
 | 
			
		||||
		Attach:  ebpf.AttachNone,
 | 
			
		||||
		BTF:     typeID,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &tracing{*link}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TracingOptions struct {
 | 
			
		||||
	// Program must be of type Tracing with attach type
 | 
			
		||||
	// AttachTraceFEntry/AttachTraceFExit/AttachModifyReturn or
 | 
			
		||||
	// AttachTraceRawTp.
 | 
			
		||||
	Program *ebpf.Program
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LSMOptions struct {
 | 
			
		||||
	// Program must be of type LSM with attach type
 | 
			
		||||
	// AttachLSMMac.
 | 
			
		||||
	Program *ebpf.Program
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// attachBTFID links all BPF program types (Tracing/LSM) that they attach to a btf_id.
 | 
			
		||||
func attachBTFID(program *ebpf.Program) (Link, error) {
 | 
			
		||||
	if program.FD() < 0 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program %w", sys.ErrClosedFd)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
 | 
			
		||||
		ProgFd: uint32(program.FD()),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	raw := RawLink{fd: fd}
 | 
			
		||||
	info, err := raw.Info()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		raw.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if info.Type == RawTracepointType {
 | 
			
		||||
		// Sadness upon sadness: a Tracing program with AttachRawTp returns
 | 
			
		||||
		// a raw_tracepoint link. Other types return a tracing link.
 | 
			
		||||
		return &rawTracepoint{raw}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &tracing{RawLink: RawLink{fd: fd}}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachTracing links a tracing (fentry/fexit/fmod_ret) BPF program or
 | 
			
		||||
// a BTF-powered raw tracepoint (tp_btf) BPF Program to a BPF hook defined
 | 
			
		||||
// in kernel modules.
 | 
			
		||||
func AttachTracing(opts TracingOptions) (Link, error) {
 | 
			
		||||
	if t := opts.Program.Type(); t != ebpf.Tracing {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program type %s, expected Tracing", t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return attachBTFID(opts.Program)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachLSM links a Linux security module (LSM) BPF Program to a BPF
 | 
			
		||||
// hook defined in kernel modules.
 | 
			
		||||
func AttachLSM(opts LSMOptions) (Link, error) {
 | 
			
		||||
	if t := opts.Program.Type(); t != ebpf.LSM {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program type %s, expected LSM", t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return attachBTFID(opts.Program)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										205
									
								
								vendor/github.com/cilium/ebpf/link/uprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										205
									
								
								vendor/github.com/cilium/ebpf/link/uprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
@@ -16,16 +16,23 @@ import (
 | 
			
		||||
var (
 | 
			
		||||
	uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events")
 | 
			
		||||
 | 
			
		||||
	// rgxUprobeSymbol is used to strip invalid characters from the uprobe symbol
 | 
			
		||||
	// as they are not allowed to be used as the EVENT token in tracefs.
 | 
			
		||||
	rgxUprobeSymbol = regexp.MustCompile("[^a-zA-Z0-9]+")
 | 
			
		||||
 | 
			
		||||
	uprobeRetprobeBit = struct {
 | 
			
		||||
		once  sync.Once
 | 
			
		||||
		value uint64
 | 
			
		||||
		err   error
 | 
			
		||||
	}{}
 | 
			
		||||
 | 
			
		||||
	uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
 | 
			
		||||
	// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
 | 
			
		||||
	uprobeRefCtrOffsetShift = 32
 | 
			
		||||
	haveRefCtrOffsetPMU     = internal.FeatureTest("RefCtrOffsetPMU", "4.20", func() error {
 | 
			
		||||
		_, err := os.Stat(uprobeRefCtrOffsetPMUPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return internal.ErrNotSupported
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// ErrNoSymbol indicates that the given symbol was not found
 | 
			
		||||
	// in the ELF symbols table.
 | 
			
		||||
	ErrNoSymbol = errors.New("not found")
 | 
			
		||||
@@ -35,24 +42,46 @@ var (
 | 
			
		||||
type Executable struct {
 | 
			
		||||
	// Path of the executable on the filesystem.
 | 
			
		||||
	path string
 | 
			
		||||
	// Parsed ELF symbols and dynamic symbols offsets.
 | 
			
		||||
	offsets map[string]uint64
 | 
			
		||||
	// Parsed ELF and dynamic symbols' addresses.
 | 
			
		||||
	addresses map[string]uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UprobeOptions defines additional parameters that will be used
 | 
			
		||||
// when loading Uprobes.
 | 
			
		||||
type UprobeOptions struct {
 | 
			
		||||
	// Symbol offset. Must be provided in case of external symbols (shared libs).
 | 
			
		||||
	// If set, overrides the offset eventually parsed from the executable.
 | 
			
		||||
	// Symbol address. Must be provided in case of external symbols (shared libs).
 | 
			
		||||
	// If set, overrides the address eventually parsed from the executable.
 | 
			
		||||
	Address uint64
 | 
			
		||||
	// The offset relative to given symbol. Useful when tracing an arbitrary point
 | 
			
		||||
	// inside the frame of given symbol.
 | 
			
		||||
	//
 | 
			
		||||
	// Note: this field changed from being an absolute offset to being relative
 | 
			
		||||
	// to Address.
 | 
			
		||||
	Offset uint64
 | 
			
		||||
	// Only set the uprobe on the given process ID. Useful when tracing
 | 
			
		||||
	// shared library calls or programs that have many running instances.
 | 
			
		||||
	PID int
 | 
			
		||||
	// Automatically manage SDT reference counts (semaphores).
 | 
			
		||||
	//
 | 
			
		||||
	// If this field is set, the Kernel will increment/decrement the
 | 
			
		||||
	// semaphore located in the process memory at the provided address on
 | 
			
		||||
	// probe attach/detach.
 | 
			
		||||
	//
 | 
			
		||||
	// See also:
 | 
			
		||||
	// sourceware.org/systemtap/wiki/UserSpaceProbeImplementation (Semaphore Handling)
 | 
			
		||||
	// github.com/torvalds/linux/commit/1cc33161a83d
 | 
			
		||||
	// github.com/torvalds/linux/commit/a6ca88b241d5
 | 
			
		||||
	RefCtrOffset uint64
 | 
			
		||||
	// Arbitrary value that can be fetched from an eBPF program
 | 
			
		||||
	// via `bpf_get_attach_cookie()`.
 | 
			
		||||
	//
 | 
			
		||||
	// Needs kernel 5.15+.
 | 
			
		||||
	Cookie uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// To open a new Executable, use:
 | 
			
		||||
//
 | 
			
		||||
//	OpenExecutable("/bin/bash")
 | 
			
		||||
//  OpenExecutable("/bin/bash")
 | 
			
		||||
//
 | 
			
		||||
// The returned value can then be used to open Uprobe(s).
 | 
			
		||||
func OpenExecutable(path string) (*Executable, error) {
 | 
			
		||||
@@ -77,8 +106,8 @@ func OpenExecutable(path string) (*Executable, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ex := Executable{
 | 
			
		||||
		path:    path,
 | 
			
		||||
		offsets: make(map[string]uint64),
 | 
			
		||||
		path:      path,
 | 
			
		||||
		addresses: make(map[string]uint64),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ex.load(se); err != nil {
 | 
			
		||||
@@ -107,7 +136,7 @@ func (ex *Executable) load(f *internal.SafeELFFile) error {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		off := s.Value
 | 
			
		||||
		address := s.Value
 | 
			
		||||
 | 
			
		||||
		// Loop over ELF segments.
 | 
			
		||||
		for _, prog := range f.Progs {
 | 
			
		||||
@@ -123,32 +152,42 @@ func (ex *Executable) load(f *internal.SafeELFFile) error {
 | 
			
		||||
				// fn symbol offset = fn symbol VA - .text VA + .text offset
 | 
			
		||||
				//
 | 
			
		||||
				// stackoverflow.com/a/40249502
 | 
			
		||||
				off = s.Value - prog.Vaddr + prog.Off
 | 
			
		||||
				address = s.Value - prog.Vaddr + prog.Off
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ex.offsets[s.Name] = off
 | 
			
		||||
		ex.addresses[s.Name] = address
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ex *Executable) offset(symbol string) (uint64, error) {
 | 
			
		||||
	if off, ok := ex.offsets[symbol]; ok {
 | 
			
		||||
		// Symbols with location 0 from section undef are shared library calls and
 | 
			
		||||
		// are relocated before the binary is executed. Dynamic linking is not
 | 
			
		||||
		// implemented by the library, so mark this as unsupported for now.
 | 
			
		||||
		//
 | 
			
		||||
		// Since only offset values are stored and not elf.Symbol, if the value is 0,
 | 
			
		||||
		// assume it's an external symbol.
 | 
			
		||||
		if off == 0 {
 | 
			
		||||
			return 0, fmt.Errorf("cannot resolve %s library call '%s', "+
 | 
			
		||||
				"consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported)
 | 
			
		||||
		}
 | 
			
		||||
		return off, nil
 | 
			
		||||
// address calculates the address of a symbol in the executable.
 | 
			
		||||
//
 | 
			
		||||
// opts must not be nil.
 | 
			
		||||
func (ex *Executable) address(symbol string, opts *UprobeOptions) (uint64, error) {
 | 
			
		||||
	if opts.Address > 0 {
 | 
			
		||||
		return opts.Address + opts.Offset, nil
 | 
			
		||||
	}
 | 
			
		||||
	return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol)
 | 
			
		||||
 | 
			
		||||
	address, ok := ex.addresses[symbol]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Symbols with location 0 from section undef are shared library calls and
 | 
			
		||||
	// are relocated before the binary is executed. Dynamic linking is not
 | 
			
		||||
	// implemented by the library, so mark this as unsupported for now.
 | 
			
		||||
	//
 | 
			
		||||
	// Since only offset values are stored and not elf.Symbol, if the value is 0,
 | 
			
		||||
	// assume it's an external symbol.
 | 
			
		||||
	if address == 0 {
 | 
			
		||||
		return 0, fmt.Errorf("cannot resolve %s library call '%s': %w "+
 | 
			
		||||
			"(consider providing UprobeOptions.Address)", ex.path, symbol, ErrNotSupported)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return address + opts.Offset, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Uprobe attaches the given eBPF program to a perf event that fires when the
 | 
			
		||||
@@ -161,7 +200,9 @@ func (ex *Executable) offset(symbol string) (uint64, error) {
 | 
			
		||||
// When using symbols which belongs to shared libraries,
 | 
			
		||||
// an offset must be provided via options:
 | 
			
		||||
//
 | 
			
		||||
//	up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
 | 
			
		||||
//  up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
 | 
			
		||||
//
 | 
			
		||||
// Note: Setting the Offset field in the options supersedes the symbol's offset.
 | 
			
		||||
//
 | 
			
		||||
// Losing the reference to the resulting Link (up) will close the Uprobe
 | 
			
		||||
// and prevent further execution of prog. The Link must be Closed during
 | 
			
		||||
@@ -175,13 +216,13 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = u.attach(prog)
 | 
			
		||||
	lnk, err := attachPerfEvent(u, prog)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		u.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return u, nil
 | 
			
		||||
	return lnk, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Uretprobe attaches the given eBPF program to a perf event that fires right
 | 
			
		||||
@@ -193,7 +234,9 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 | 
			
		||||
// When using symbols which belongs to shared libraries,
 | 
			
		||||
// an offset must be provided via options:
 | 
			
		||||
//
 | 
			
		||||
//	up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
 | 
			
		||||
//  up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
 | 
			
		||||
//
 | 
			
		||||
// Note: Setting the Offset field in the options supersedes the symbol's offset.
 | 
			
		||||
//
 | 
			
		||||
// Losing the reference to the resulting Link (up) will close the Uprobe
 | 
			
		||||
// and prevent further execution of prog. The Link must be Closed during
 | 
			
		||||
@@ -207,13 +250,13 @@ func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeO
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = u.attach(prog)
 | 
			
		||||
	lnk, err := attachPerfEvent(u, prog)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		u.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return u, nil
 | 
			
		||||
	return lnk, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uprobe opens a perf event for the given binary/symbol and attaches prog to it.
 | 
			
		||||
@@ -225,25 +268,38 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 | 
			
		||||
	if prog.Type() != ebpf.Kprobe {
 | 
			
		||||
		return nil, fmt.Errorf("eBPF program type %s is not Kprobe: %w", prog.Type(), errInvalidInput)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var offset uint64
 | 
			
		||||
	if opts != nil && opts.Offset != 0 {
 | 
			
		||||
		offset = opts.Offset
 | 
			
		||||
	} else {
 | 
			
		||||
		off, err := ex.offset(symbol)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		offset = off
 | 
			
		||||
	if opts == nil {
 | 
			
		||||
		opts = &UprobeOptions{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pid := perfAllThreads
 | 
			
		||||
	if opts != nil && opts.PID != 0 {
 | 
			
		||||
		pid = opts.PID
 | 
			
		||||
	offset, err := ex.address(symbol, opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pid := opts.PID
 | 
			
		||||
	if pid == 0 {
 | 
			
		||||
		pid = perfAllThreads
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.RefCtrOffset != 0 {
 | 
			
		||||
		if err := haveRefCtrOffsetPMU(); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("uprobe ref_ctr_offset: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	args := probeArgs{
 | 
			
		||||
		symbol:       symbol,
 | 
			
		||||
		path:         ex.path,
 | 
			
		||||
		offset:       offset,
 | 
			
		||||
		pid:          pid,
 | 
			
		||||
		refCtrOffset: opts.RefCtrOffset,
 | 
			
		||||
		ret:          ret,
 | 
			
		||||
		cookie:       opts.Cookie,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use uprobe PMU if the kernel has it available.
 | 
			
		||||
	tp, err := pmuUprobe(symbol, ex.path, offset, pid, ret)
 | 
			
		||||
	tp, err := pmuUprobe(args)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return tp, nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -252,7 +308,8 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use tracefs if uprobe PMU is missing.
 | 
			
		||||
	tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, pid, ret)
 | 
			
		||||
	args.symbol = sanitizeSymbol(symbol)
 | 
			
		||||
	tp, err = tracefsUprobe(args)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -261,23 +318,51 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pmuUprobe opens a perf event based on the uprobe PMU.
 | 
			
		||||
func pmuUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
 | 
			
		||||
	return pmuProbe(uprobeType, symbol, path, offset, pid, ret)
 | 
			
		||||
func pmuUprobe(args probeArgs) (*perfEvent, error) {
 | 
			
		||||
	return pmuProbe(uprobeType, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tracefsUprobe creates a Uprobe tracefs entry.
 | 
			
		||||
func tracefsUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
 | 
			
		||||
	return tracefsProbe(uprobeType, symbol, path, offset, pid, ret)
 | 
			
		||||
func tracefsUprobe(args probeArgs) (*perfEvent, error) {
 | 
			
		||||
	return tracefsProbe(uprobeType, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore.
 | 
			
		||||
func uprobeSanitizedSymbol(symbol string) string {
 | 
			
		||||
	return rgxUprobeSymbol.ReplaceAllString(symbol, "_")
 | 
			
		||||
// sanitizeSymbol replaces every invalid character for the tracefs api with an underscore.
 | 
			
		||||
// It is equivalent to calling regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString("_").
 | 
			
		||||
func sanitizeSymbol(s string) string {
 | 
			
		||||
	var b strings.Builder
 | 
			
		||||
	b.Grow(len(s))
 | 
			
		||||
	var skip bool
 | 
			
		||||
	for _, c := range []byte(s) {
 | 
			
		||||
		switch {
 | 
			
		||||
		case c >= 'a' && c <= 'z',
 | 
			
		||||
			c >= 'A' && c <= 'Z',
 | 
			
		||||
			c >= '0' && c <= '9':
 | 
			
		||||
			skip = false
 | 
			
		||||
			b.WriteByte(c)
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			if !skip {
 | 
			
		||||
				b.WriteByte('_')
 | 
			
		||||
				skip = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// uprobePathOffset creates the PATH:OFFSET token for the tracefs api.
 | 
			
		||||
func uprobePathOffset(path string, offset uint64) string {
 | 
			
		||||
	return fmt.Sprintf("%s:%#x", path, offset)
 | 
			
		||||
// uprobeToken creates the PATH:OFFSET(REF_CTR_OFFSET) token for the tracefs api.
 | 
			
		||||
func uprobeToken(args probeArgs) string {
 | 
			
		||||
	po := fmt.Sprintf("%s:%#x", args.path, args.offset)
 | 
			
		||||
 | 
			
		||||
	if args.refCtrOffset != 0 {
 | 
			
		||||
		// This is not documented in Documentation/trace/uprobetracer.txt.
 | 
			
		||||
		// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/trace/trace.c#L5564
 | 
			
		||||
		po += fmt.Sprintf("(%#x)", args.refCtrOffset)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return po
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func uretprobeBit() (uint64, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/github.com/cilium/ebpf/link/xdp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/cilium/ebpf/link/xdp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
package link
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// XDPAttachFlags represents how XDP program will be attached to interface.
 | 
			
		||||
type XDPAttachFlags uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// XDPGenericMode (SKB) links XDP BPF program for drivers which do
 | 
			
		||||
	// not yet support native XDP.
 | 
			
		||||
	XDPGenericMode XDPAttachFlags = 1 << (iota + 1)
 | 
			
		||||
	// XDPDriverMode links XDP BPF program into the driver’s receive path.
 | 
			
		||||
	XDPDriverMode
 | 
			
		||||
	// XDPOffloadMode offloads the entire XDP BPF program into hardware.
 | 
			
		||||
	XDPOffloadMode
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type XDPOptions struct {
 | 
			
		||||
	// Program must be an XDP BPF program.
 | 
			
		||||
	Program *ebpf.Program
 | 
			
		||||
 | 
			
		||||
	// Interface is the interface index to attach program to.
 | 
			
		||||
	Interface int
 | 
			
		||||
 | 
			
		||||
	// Flags is one of XDPAttachFlags (optional).
 | 
			
		||||
	//
 | 
			
		||||
	// Only one XDP mode should be set, without flag defaults
 | 
			
		||||
	// to driver/generic mode (best effort).
 | 
			
		||||
	Flags XDPAttachFlags
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachXDP links an XDP BPF program to an XDP hook.
 | 
			
		||||
func AttachXDP(opts XDPOptions) (Link, error) {
 | 
			
		||||
	if t := opts.Program.Type(); t != ebpf.XDP {
 | 
			
		||||
		return nil, fmt.Errorf("invalid program type %s, expected XDP", t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Interface < 1 {
 | 
			
		||||
		return nil, fmt.Errorf("invalid interface index: %d", opts.Interface)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rawLink, err := AttachRawLink(RawLinkOptions{
 | 
			
		||||
		Program: opts.Program,
 | 
			
		||||
		Attach:  ebpf.AttachXDP,
 | 
			
		||||
		Target:  opts.Interface,
 | 
			
		||||
		Flags:   uint32(opts.Flags),
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return rawLink, err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user