github.com/cilium/ebpf@v0.10.0/prog.go (about)

     1  package ebpf
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"math"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/cilium/ebpf/asm"
    15  	"github.com/cilium/ebpf/btf"
    16  	"github.com/cilium/ebpf/internal"
    17  	"github.com/cilium/ebpf/internal/sys"
    18  	"github.com/cilium/ebpf/internal/unix"
    19  )
    20  
    21  // ErrNotSupported is returned whenever the kernel doesn't support a feature.
    22  var ErrNotSupported = internal.ErrNotSupported
    23  
    24  // ProgramID represents the unique ID of an eBPF program.
    25  type ProgramID uint32
    26  
    27  const (
    28  	// Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN.
    29  	// This is currently the maximum of spare space allocated for SKB
    30  	// and XDP programs, and equal to XDP_PACKET_HEADROOM + NET_IP_ALIGN.
    31  	outputPad = 256 + 2
    32  )
    33  
    34  // DefaultVerifierLogSize is the default number of bytes allocated for the
    35  // verifier log.
    36  const DefaultVerifierLogSize = 64 * 1024
    37  
    38  // maxVerifierLogSize is the maximum size of verifier log buffer the kernel
    39  // will accept before returning EINVAL.
    40  const maxVerifierLogSize = math.MaxUint32 >> 2
    41  
    42  // ProgramOptions control loading a program into the kernel.
    43  type ProgramOptions struct {
    44  	// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
    45  	// LogLevel-type values can be ORed together to request specific kinds of
    46  	// verifier output. See the documentation on [ebpf.LogLevel] for details.
    47  	//
    48  	//  opts.LogLevel = (ebpf.LogLevelBranch | ebpf.LogLevelStats)
    49  	//
    50  	// If left to its default value, the program will first be loaded without
    51  	// verifier output enabled. Upon error, the program load will be repeated
    52  	// with LogLevelBranch and the given (or default) LogSize value.
    53  	//
    54  	// Setting this to a non-zero value will unconditionally enable the verifier
    55  	// log, populating the [ebpf.Program.VerifierLog] field on successful loads
    56  	// and including detailed verifier errors if the program is rejected. This
    57  	// will always allocate an output buffer, but will result in only a single
    58  	// attempt at loading the program.
    59  	LogLevel LogLevel
    60  
    61  	// Controls the output buffer size for the verifier log, in bytes. See the
    62  	// documentation on ProgramOptions.LogLevel for details about how this value
    63  	// is used.
    64  	//
    65  	// If this value is set too low to fit the verifier log, the resulting
    66  	// [ebpf.VerifierError]'s Truncated flag will be true, and the error string
    67  	// will also contain a hint to that effect.
    68  	//
    69  	// Defaults to DefaultVerifierLogSize.
    70  	LogSize int
    71  
    72  	// Disables the verifier log completely, regardless of other options.
    73  	LogDisabled bool
    74  
    75  	// Type information used for CO-RE relocations.
    76  	//
    77  	// This is useful in environments where the kernel BTF is not available
    78  	// (containers) or where it is in a non-standard location. Defaults to
    79  	// use the kernel BTF from a well-known location if nil.
    80  	KernelTypes *btf.Spec
    81  }
    82  
    83  // ProgramSpec defines a Program.
    84  type ProgramSpec struct {
    85  	// Name is passed to the kernel as a debug aid. Must only contain
    86  	// alpha numeric and '_' characters.
    87  	Name string
    88  
    89  	// Type determines at which hook in the kernel a program will run.
    90  	Type ProgramType
    91  
    92  	// AttachType of the program, needed to differentiate allowed context
    93  	// accesses in some newer program types like CGroupSockAddr.
    94  	//
    95  	// Available on kernels 4.17 and later.
    96  	AttachType AttachType
    97  
    98  	// Name of a kernel data structure or function to attach to. Its
    99  	// interpretation depends on Type and AttachType.
   100  	AttachTo string
   101  
   102  	// The program to attach to. Must be provided manually.
   103  	AttachTarget *Program
   104  
   105  	// The name of the ELF section this program originated from.
   106  	SectionName string
   107  
   108  	Instructions asm.Instructions
   109  
   110  	// Flags is passed to the kernel and specifies additional program
   111  	// load attributes.
   112  	Flags uint32
   113  
   114  	// License of the program. Some helpers are only available if
   115  	// the license is deemed compatible with the GPL.
   116  	//
   117  	// See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1
   118  	License string
   119  
   120  	// Version used by Kprobe programs.
   121  	//
   122  	// Deprecated on kernels 5.0 and later. Leave empty to let the library
   123  	// detect this value automatically.
   124  	KernelVersion uint32
   125  
   126  	// The byte order this program was compiled for, may be nil.
   127  	ByteOrder binary.ByteOrder
   128  }
   129  
   130  // Copy returns a copy of the spec.
   131  func (ps *ProgramSpec) Copy() *ProgramSpec {
   132  	if ps == nil {
   133  		return nil
   134  	}
   135  
   136  	cpy := *ps
   137  	cpy.Instructions = make(asm.Instructions, len(ps.Instructions))
   138  	copy(cpy.Instructions, ps.Instructions)
   139  	return &cpy
   140  }
   141  
   142  // Tag calculates the kernel tag for a series of instructions.
   143  //
   144  // Use asm.Instructions.Tag if you need to calculate for non-native endianness.
   145  func (ps *ProgramSpec) Tag() (string, error) {
   146  	return ps.Instructions.Tag(internal.NativeEndian)
   147  }
   148  
   149  // VerifierError is returned by [NewProgram] and [NewProgramWithOptions] if a
   150  // program is rejected by the verifier.
   151  //
   152  // Use [errors.As] to access the error.
   153  type VerifierError = internal.VerifierError
   154  
   155  // Program represents BPF program loaded into the kernel.
   156  //
   157  // It is not safe to close a Program which is used by other goroutines.
   158  type Program struct {
   159  	// Contains the output of the kernel verifier if enabled,
   160  	// otherwise it is empty.
   161  	VerifierLog string
   162  
   163  	fd         *sys.FD
   164  	name       string
   165  	pinnedPath string
   166  	typ        ProgramType
   167  }
   168  
   169  // NewProgram creates a new Program.
   170  //
   171  // See [NewProgramWithOptions] for details.
   172  func NewProgram(spec *ProgramSpec) (*Program, error) {
   173  	return NewProgramWithOptions(spec, ProgramOptions{})
   174  }
   175  
   176  // NewProgramWithOptions creates a new Program.
   177  //
   178  // Loading a program for the first time will perform
   179  // feature detection by loading small, temporary programs.
   180  //
   181  // Returns a [VerifierError] if the program is rejected by the kernel.
   182  func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
   183  	if spec == nil {
   184  		return nil, errors.New("can't load a program from a nil spec")
   185  	}
   186  
   187  	prog, err := newProgramWithOptions(spec, opts)
   188  	if errors.Is(err, asm.ErrUnsatisfiedMapReference) {
   189  		return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err)
   190  	}
   191  	return prog, err
   192  }
   193  
   194  func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
   195  	if len(spec.Instructions) == 0 {
   196  		return nil, errors.New("instructions cannot be empty")
   197  	}
   198  
   199  	if spec.Type == UnspecifiedProgram {
   200  		return nil, errors.New("can't load program of unspecified type")
   201  	}
   202  
   203  	if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
   204  		return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
   205  	}
   206  
   207  	if opts.LogSize < 0 {
   208  		return nil, errors.New("ProgramOptions.LogSize must be a positive value; disable verifier logs using ProgramOptions.LogDisabled")
   209  	}
   210  
   211  	// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
   212  	// require the version field to be set to the value of the KERNEL_VERSION
   213  	// macro for kprobe-type programs.
   214  	// Overwrite Kprobe program version if set to zero or the magic version constant.
   215  	kv := spec.KernelVersion
   216  	if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
   217  		v, err := internal.KernelVersion()
   218  		if err != nil {
   219  			return nil, fmt.Errorf("detecting kernel version: %w", err)
   220  		}
   221  		kv = v.Kernel()
   222  	}
   223  
   224  	attr := &sys.ProgLoadAttr{
   225  		ProgType:           sys.ProgType(spec.Type),
   226  		ProgFlags:          spec.Flags,
   227  		ExpectedAttachType: sys.AttachType(spec.AttachType),
   228  		License:            sys.NewStringPointer(spec.License),
   229  		KernVersion:        kv,
   230  	}
   231  
   232  	if haveObjName() == nil {
   233  		attr.ProgName = sys.NewObjName(spec.Name)
   234  	}
   235  
   236  	insns := make(asm.Instructions, len(spec.Instructions))
   237  	copy(insns, spec.Instructions)
   238  
   239  	handle, fib, lib, err := btf.MarshalExtInfos(insns)
   240  	if err != nil && !errors.Is(err, btf.ErrNotSupported) {
   241  		return nil, fmt.Errorf("load ext_infos: %w", err)
   242  	}
   243  	if handle != nil {
   244  		defer handle.Close()
   245  
   246  		attr.ProgBtfFd = uint32(handle.FD())
   247  
   248  		attr.FuncInfoRecSize = btf.FuncInfoSize
   249  		attr.FuncInfoCnt = uint32(len(fib)) / btf.FuncInfoSize
   250  		attr.FuncInfo = sys.NewSlicePointer(fib)
   251  
   252  		attr.LineInfoRecSize = btf.LineInfoSize
   253  		attr.LineInfoCnt = uint32(len(lib)) / btf.LineInfoSize
   254  		attr.LineInfo = sys.NewSlicePointer(lib)
   255  	}
   256  
   257  	if err := applyRelocations(insns, opts.KernelTypes, spec.ByteOrder); err != nil {
   258  		return nil, fmt.Errorf("apply CO-RE relocations: %w", err)
   259  	}
   260  
   261  	if err := fixupAndValidate(insns); err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	buf := bytes.NewBuffer(make([]byte, 0, insns.Size()))
   266  	err = insns.Marshal(buf, internal.NativeEndian)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	bytecode := buf.Bytes()
   272  	attr.Insns = sys.NewSlicePointer(bytecode)
   273  	attr.InsnCnt = uint32(len(bytecode) / asm.InstructionSize)
   274  
   275  	if spec.AttachTarget != nil {
   276  		targetID, err := findTargetInProgram(spec.AttachTarget, spec.AttachTo, spec.Type, spec.AttachType)
   277  		if err != nil {
   278  			return nil, fmt.Errorf("attach %s/%s: %w", spec.Type, spec.AttachType, err)
   279  		}
   280  
   281  		attr.AttachBtfId = uint32(targetID)
   282  		attr.AttachBtfObjFd = uint32(spec.AttachTarget.FD())
   283  		defer runtime.KeepAlive(spec.AttachTarget)
   284  	} else if spec.AttachTo != "" {
   285  		module, targetID, err := findTargetInKernel(spec.AttachTo, spec.Type, spec.AttachType)
   286  		if err != nil && !errors.Is(err, errUnrecognizedAttachType) {
   287  			// We ignore errUnrecognizedAttachType since AttachTo may be non-empty
   288  			// for programs that don't attach anywhere.
   289  			return nil, fmt.Errorf("attach %s/%s: %w", spec.Type, spec.AttachType, err)
   290  		}
   291  
   292  		attr.AttachBtfId = uint32(targetID)
   293  		if module != nil {
   294  			attr.AttachBtfObjFd = uint32(module.FD())
   295  			defer module.Close()
   296  		}
   297  	}
   298  
   299  	if opts.LogSize == 0 {
   300  		opts.LogSize = DefaultVerifierLogSize
   301  	}
   302  
   303  	// The caller requested a specific verifier log level. Set up the log buffer.
   304  	var logBuf []byte
   305  	if !opts.LogDisabled && opts.LogLevel != 0 {
   306  		logBuf = make([]byte, opts.LogSize)
   307  		attr.LogLevel = opts.LogLevel
   308  		attr.LogSize = uint32(len(logBuf))
   309  		attr.LogBuf = sys.NewSlicePointer(logBuf)
   310  	}
   311  
   312  	fd, err := sys.ProgLoad(attr)
   313  	if err == nil {
   314  		return &Program{unix.ByteSliceToString(logBuf), fd, spec.Name, "", spec.Type}, nil
   315  	}
   316  
   317  	// An error occurred loading the program, but the caller did not explicitly
   318  	// enable the verifier log. Re-run with branch-level verifier logs enabled to
   319  	// obtain more info. Preserve the original error to return it to the caller.
   320  	// An undersized log buffer will result in ENOSPC regardless of the underlying
   321  	// cause.
   322  	var err2 error
   323  	if !opts.LogDisabled && opts.LogLevel == 0 {
   324  		logBuf = make([]byte, opts.LogSize)
   325  		attr.LogLevel = LogLevelBranch
   326  		attr.LogSize = uint32(len(logBuf))
   327  		attr.LogBuf = sys.NewSlicePointer(logBuf)
   328  
   329  		_, err2 = sys.ProgLoad(attr)
   330  	}
   331  
   332  	switch {
   333  	case errors.Is(err, unix.EPERM):
   334  		if len(logBuf) > 0 && logBuf[0] == 0 {
   335  			// EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can
   336  			// check that the log is empty to reduce false positives.
   337  			return nil, fmt.Errorf("load program: %w (MEMLOCK may be too low, consider rlimit.RemoveMemlock)", err)
   338  		}
   339  
   340  		fallthrough
   341  
   342  	case errors.Is(err, unix.EINVAL):
   343  		if hasFunctionReferences(spec.Instructions) {
   344  			if err := haveBPFToBPFCalls(); err != nil {
   345  				return nil, fmt.Errorf("load program: %w", err)
   346  			}
   347  		}
   348  
   349  		if opts.LogSize > maxVerifierLogSize {
   350  			return nil, fmt.Errorf("load program: %w (ProgramOptions.LogSize exceeds maximum value of %d)", err, maxVerifierLogSize)
   351  		}
   352  	}
   353  
   354  	truncated := errors.Is(err, unix.ENOSPC) || errors.Is(err2, unix.ENOSPC)
   355  	return nil, internal.ErrorWithLog("load program", err, logBuf, truncated)
   356  }
   357  
   358  // NewProgramFromFD creates a program from a raw fd.
   359  //
   360  // You should not use fd after calling this function.
   361  //
   362  // Requires at least Linux 4.10.
   363  func NewProgramFromFD(fd int) (*Program, error) {
   364  	f, err := sys.NewFD(fd)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  
   369  	return newProgramFromFD(f)
   370  }
   371  
   372  // NewProgramFromID returns the program for a given id.
   373  //
   374  // Returns ErrNotExist, if there is no eBPF program with the given id.
   375  func NewProgramFromID(id ProgramID) (*Program, error) {
   376  	fd, err := sys.ProgGetFdById(&sys.ProgGetFdByIdAttr{
   377  		Id: uint32(id),
   378  	})
   379  	if err != nil {
   380  		return nil, fmt.Errorf("get program by id: %w", err)
   381  	}
   382  
   383  	return newProgramFromFD(fd)
   384  }
   385  
   386  func newProgramFromFD(fd *sys.FD) (*Program, error) {
   387  	info, err := newProgramInfoFromFd(fd)
   388  	if err != nil {
   389  		fd.Close()
   390  		return nil, fmt.Errorf("discover program type: %w", err)
   391  	}
   392  
   393  	return &Program{"", fd, info.Name, "", info.Type}, nil
   394  }
   395  
   396  func (p *Program) String() string {
   397  	if p.name != "" {
   398  		return fmt.Sprintf("%s(%s)#%v", p.typ, p.name, p.fd)
   399  	}
   400  	return fmt.Sprintf("%s(%v)", p.typ, p.fd)
   401  }
   402  
   403  // Type returns the underlying type of the program.
   404  func (p *Program) Type() ProgramType {
   405  	return p.typ
   406  }
   407  
   408  // Info returns metadata about the program.
   409  //
   410  // Requires at least 4.10.
   411  func (p *Program) Info() (*ProgramInfo, error) {
   412  	return newProgramInfoFromFd(p.fd)
   413  }
   414  
   415  // Handle returns a reference to the program's type information in the kernel.
   416  //
   417  // Returns ErrNotSupported if the kernel has no BTF support, or if there is no
   418  // BTF associated with the program.
   419  func (p *Program) Handle() (*btf.Handle, error) {
   420  	info, err := p.Info()
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	id, ok := info.BTFID()
   426  	if !ok {
   427  		return nil, fmt.Errorf("program %s: retrieve BTF ID: %w", p, ErrNotSupported)
   428  	}
   429  
   430  	return btf.NewHandleFromID(id)
   431  }
   432  
   433  // FD gets the file descriptor of the Program.
   434  //
   435  // It is invalid to call this function after Close has been called.
   436  func (p *Program) FD() int {
   437  	return p.fd.Int()
   438  }
   439  
   440  // Clone creates a duplicate of the Program.
   441  //
   442  // Closing the duplicate does not affect the original, and vice versa.
   443  //
   444  // Cloning a nil Program returns nil.
   445  func (p *Program) Clone() (*Program, error) {
   446  	if p == nil {
   447  		return nil, nil
   448  	}
   449  
   450  	dup, err := p.fd.Dup()
   451  	if err != nil {
   452  		return nil, fmt.Errorf("can't clone program: %w", err)
   453  	}
   454  
   455  	return &Program{p.VerifierLog, dup, p.name, "", p.typ}, nil
   456  }
   457  
   458  // Pin persists the Program on the BPF virtual file system past the lifetime of
   459  // the process that created it
   460  //
   461  // Calling Pin on a previously pinned program will overwrite the path, except when
   462  // the new path already exists. Re-pinning across filesystems is not supported.
   463  //
   464  // This requires bpffs to be mounted above fileName.
   465  // See https://docs.cilium.io/en/stable/concepts/kubernetes/configuration/#mounting-bpffs-with-systemd
   466  func (p *Program) Pin(fileName string) error {
   467  	if err := internal.Pin(p.pinnedPath, fileName, p.fd); err != nil {
   468  		return err
   469  	}
   470  	p.pinnedPath = fileName
   471  	return nil
   472  }
   473  
   474  // Unpin removes the persisted state for the Program from the BPF virtual filesystem.
   475  //
   476  // Failed calls to Unpin will not alter the state returned by IsPinned.
   477  //
   478  // Unpinning an unpinned Program returns nil.
   479  func (p *Program) Unpin() error {
   480  	if err := internal.Unpin(p.pinnedPath); err != nil {
   481  		return err
   482  	}
   483  	p.pinnedPath = ""
   484  	return nil
   485  }
   486  
   487  // IsPinned returns true if the Program has a non-empty pinned path.
   488  func (p *Program) IsPinned() bool {
   489  	return p.pinnedPath != ""
   490  }
   491  
   492  // Close the Program's underlying file descriptor, which could unload
   493  // the program from the kernel if it is not pinned or attached to a
   494  // kernel hook.
   495  func (p *Program) Close() error {
   496  	if p == nil {
   497  		return nil
   498  	}
   499  
   500  	return p.fd.Close()
   501  }
   502  
   503  // Various options for Run'ing a Program
   504  type RunOptions struct {
   505  	// Program's data input. Required field.
   506  	//
   507  	// The kernel expects at least 14 bytes input for an ethernet header for
   508  	// XDP and SKB programs.
   509  	Data []byte
   510  	// Program's data after Program has run. Caller must allocate. Optional field.
   511  	DataOut []byte
   512  	// Program's context input. Optional field.
   513  	Context interface{}
   514  	// Program's context after Program has run. Must be a pointer or slice. Optional field.
   515  	ContextOut interface{}
   516  	// Minimum number of times to run Program. Optional field. Defaults to 1.
   517  	//
   518  	// The program may be executed more often than this due to interruptions, e.g.
   519  	// when runtime.AllThreadsSyscall is invoked.
   520  	Repeat uint32
   521  	// Optional flags.
   522  	Flags uint32
   523  	// CPU to run Program on. Optional field.
   524  	// Note not all program types support this field.
   525  	CPU uint32
   526  	// Called whenever the syscall is interrupted, and should be set to testing.B.ResetTimer
   527  	// or similar. Typically used during benchmarking. Optional field.
   528  	//
   529  	// Deprecated: use [testing.B.ReportMetric] with unit "ns/op" instead.
   530  	Reset func()
   531  }
   532  
   533  // Test runs the Program in the kernel with the given input and returns the
   534  // value returned by the eBPF program. outLen may be zero.
   535  //
   536  // Note: the kernel expects at least 14 bytes input for an ethernet header for
   537  // XDP and SKB programs.
   538  //
   539  // This function requires at least Linux 4.12.
   540  func (p *Program) Test(in []byte) (uint32, []byte, error) {
   541  	// Older kernels ignore the dataSizeOut argument when copying to user space.
   542  	// Combined with things like bpf_xdp_adjust_head() we don't really know what the final
   543  	// size will be. Hence we allocate an output buffer which we hope will always be large
   544  	// enough, and panic if the kernel wrote past the end of the allocation.
   545  	// See https://patchwork.ozlabs.org/cover/1006822/
   546  	var out []byte
   547  	if len(in) > 0 {
   548  		out = make([]byte, len(in)+outputPad)
   549  	}
   550  
   551  	opts := RunOptions{
   552  		Data:    in,
   553  		DataOut: out,
   554  		Repeat:  1,
   555  	}
   556  
   557  	ret, _, err := p.run(&opts)
   558  	if err != nil {
   559  		return ret, nil, fmt.Errorf("test program: %w", err)
   560  	}
   561  	return ret, opts.DataOut, nil
   562  }
   563  
   564  // Run runs the Program in kernel with given RunOptions.
   565  //
   566  // Note: the same restrictions from Test apply.
   567  func (p *Program) Run(opts *RunOptions) (uint32, error) {
   568  	ret, _, err := p.run(opts)
   569  	if err != nil {
   570  		return ret, fmt.Errorf("run program: %w", err)
   571  	}
   572  	return ret, nil
   573  }
   574  
   575  // Benchmark runs the Program with the given input for a number of times
   576  // and returns the time taken per iteration.
   577  //
   578  // Returns the result of the last execution of the program and the time per
   579  // run or an error. reset is called whenever the benchmark syscall is
   580  // interrupted, and should be set to testing.B.ResetTimer or similar.
   581  //
   582  // Note: profiling a call to this function will skew its results, see
   583  // https://github.com/cilium/ebpf/issues/24
   584  //
   585  // This function requires at least Linux 4.12.
   586  func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
   587  	if uint(repeat) > math.MaxUint32 {
   588  		return 0, 0, fmt.Errorf("repeat is too high")
   589  	}
   590  
   591  	opts := RunOptions{
   592  		Data:   in,
   593  		Repeat: uint32(repeat),
   594  		Reset:  reset,
   595  	}
   596  
   597  	ret, total, err := p.run(&opts)
   598  	if err != nil {
   599  		return ret, total, fmt.Errorf("benchmark program: %w", err)
   600  	}
   601  	return ret, total, nil
   602  }
   603  
   604  var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error {
   605  	prog, err := NewProgram(&ProgramSpec{
   606  		// SocketFilter does not require privileges on newer kernels.
   607  		Type: SocketFilter,
   608  		Instructions: asm.Instructions{
   609  			asm.LoadImm(asm.R0, 0, asm.DWord),
   610  			asm.Return(),
   611  		},
   612  		License: "MIT",
   613  	})
   614  	if err != nil {
   615  		// This may be because we lack sufficient permissions, etc.
   616  		return err
   617  	}
   618  	defer prog.Close()
   619  
   620  	in := internal.EmptyBPFContext
   621  	attr := sys.ProgRunAttr{
   622  		ProgFd:     uint32(prog.FD()),
   623  		DataSizeIn: uint32(len(in)),
   624  		DataIn:     sys.NewSlicePointer(in),
   625  	}
   626  
   627  	err = sys.ProgRun(&attr)
   628  	switch {
   629  	case errors.Is(err, unix.EINVAL):
   630  		// Check for EINVAL specifically, rather than err != nil since we
   631  		// otherwise misdetect due to insufficient permissions.
   632  		return internal.ErrNotSupported
   633  
   634  	case errors.Is(err, unix.EINTR):
   635  		// We know that PROG_TEST_RUN is supported if we get EINTR.
   636  		return nil
   637  
   638  	case errors.Is(err, sys.ENOTSUPP):
   639  		// The first PROG_TEST_RUN patches shipped in 4.12 didn't include
   640  		// a test runner for SocketFilter. ENOTSUPP means PROG_TEST_RUN is
   641  		// supported, but not for the program type used in the probe.
   642  		return nil
   643  	}
   644  
   645  	return err
   646  })
   647  
   648  func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) {
   649  	if uint(len(opts.Data)) > math.MaxUint32 {
   650  		return 0, 0, fmt.Errorf("input is too long")
   651  	}
   652  
   653  	if err := haveProgRun(); err != nil {
   654  		return 0, 0, err
   655  	}
   656  
   657  	var ctxBytes []byte
   658  	if opts.Context != nil {
   659  		ctx := new(bytes.Buffer)
   660  		if err := binary.Write(ctx, internal.NativeEndian, opts.Context); err != nil {
   661  			return 0, 0, fmt.Errorf("cannot serialize context: %v", err)
   662  		}
   663  		ctxBytes = ctx.Bytes()
   664  	}
   665  
   666  	var ctxOut []byte
   667  	if opts.ContextOut != nil {
   668  		ctxOut = make([]byte, binary.Size(opts.ContextOut))
   669  	}
   670  
   671  	attr := sys.ProgRunAttr{
   672  		ProgFd:      p.fd.Uint(),
   673  		DataSizeIn:  uint32(len(opts.Data)),
   674  		DataSizeOut: uint32(len(opts.DataOut)),
   675  		DataIn:      sys.NewSlicePointer(opts.Data),
   676  		DataOut:     sys.NewSlicePointer(opts.DataOut),
   677  		Repeat:      uint32(opts.Repeat),
   678  		CtxSizeIn:   uint32(len(ctxBytes)),
   679  		CtxSizeOut:  uint32(len(ctxOut)),
   680  		CtxIn:       sys.NewSlicePointer(ctxBytes),
   681  		CtxOut:      sys.NewSlicePointer(ctxOut),
   682  		Flags:       opts.Flags,
   683  		Cpu:         opts.CPU,
   684  	}
   685  
   686  	if attr.Repeat == 0 {
   687  		attr.Repeat = 1
   688  	}
   689  
   690  retry:
   691  	for {
   692  		err := sys.ProgRun(&attr)
   693  		if err == nil {
   694  			break retry
   695  		}
   696  
   697  		if errors.Is(err, unix.EINTR) {
   698  			if attr.Repeat == 1 {
   699  				// Older kernels check whether enough repetitions have been
   700  				// executed only after checking for pending signals.
   701  				//
   702  				//     run signal? done? run ...
   703  				//
   704  				// As a result we can get EINTR for repeat==1 even though
   705  				// the program was run exactly once. Treat this as a
   706  				// successful run instead.
   707  				//
   708  				// Since commit 607b9cc92bd7 ("bpf: Consolidate shared test timing code")
   709  				// the conditions are reversed:
   710  				//     run done? signal? ...
   711  				break retry
   712  			}
   713  
   714  			if opts.Reset != nil {
   715  				opts.Reset()
   716  			}
   717  			continue retry
   718  		}
   719  
   720  		if errors.Is(err, sys.ENOTSUPP) {
   721  			return 0, 0, fmt.Errorf("kernel doesn't support running %s: %w", p.Type(), ErrNotSupported)
   722  		}
   723  
   724  		return 0, 0, err
   725  	}
   726  
   727  	if opts.DataOut != nil {
   728  		if int(attr.DataSizeOut) > cap(opts.DataOut) {
   729  			// Houston, we have a problem. The program created more data than we allocated,
   730  			// and the kernel wrote past the end of our buffer.
   731  			panic("kernel wrote past end of output buffer")
   732  		}
   733  		opts.DataOut = opts.DataOut[:int(attr.DataSizeOut)]
   734  	}
   735  
   736  	if len(ctxOut) != 0 {
   737  		b := bytes.NewReader(ctxOut)
   738  		if err := binary.Read(b, internal.NativeEndian, opts.ContextOut); err != nil {
   739  			return 0, 0, fmt.Errorf("failed to decode ContextOut: %v", err)
   740  		}
   741  	}
   742  
   743  	total := time.Duration(attr.Duration) * time.Nanosecond
   744  	return attr.Retval, total, nil
   745  }
   746  
   747  func unmarshalProgram(buf []byte) (*Program, error) {
   748  	if len(buf) != 4 {
   749  		return nil, errors.New("program id requires 4 byte value")
   750  	}
   751  
   752  	// Looking up an entry in a nested map or prog array returns an id,
   753  	// not an fd.
   754  	id := internal.NativeEndian.Uint32(buf)
   755  	return NewProgramFromID(ProgramID(id))
   756  }
   757  
   758  func marshalProgram(p *Program, length int) ([]byte, error) {
   759  	if length != 4 {
   760  		return nil, fmt.Errorf("can't marshal program to %d bytes", length)
   761  	}
   762  
   763  	buf := make([]byte, 4)
   764  	internal.NativeEndian.PutUint32(buf, p.fd.Uint())
   765  	return buf, nil
   766  }
   767  
   768  // LoadPinnedProgram loads a Program from a BPF file.
   769  //
   770  // Requires at least Linux 4.11.
   771  func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) {
   772  	fd, err := sys.ObjGet(&sys.ObjGetAttr{
   773  		Pathname:  sys.NewStringPointer(fileName),
   774  		FileFlags: opts.Marshal(),
   775  	})
   776  	if err != nil {
   777  		return nil, err
   778  	}
   779  
   780  	info, err := newProgramInfoFromFd(fd)
   781  	if err != nil {
   782  		_ = fd.Close()
   783  		return nil, fmt.Errorf("info for %s: %w", fileName, err)
   784  	}
   785  
   786  	return &Program{"", fd, filepath.Base(fileName), fileName, info.Type}, nil
   787  }
   788  
   789  // SanitizeName replaces all invalid characters in name with replacement.
   790  // Passing a negative value for replacement will delete characters instead
   791  // of replacing them. Use this to automatically generate valid names for maps
   792  // and programs at runtime.
   793  //
   794  // The set of allowed characters depends on the running kernel version.
   795  // Dots are only allowed as of kernel 5.2.
   796  func SanitizeName(name string, replacement rune) string {
   797  	return strings.Map(func(char rune) rune {
   798  		if invalidBPFObjNameChar(char) {
   799  			return replacement
   800  		}
   801  		return char
   802  	}, name)
   803  }
   804  
   805  // ProgramGetNextID returns the ID of the next eBPF program.
   806  //
   807  // Returns ErrNotExist, if there is no next eBPF program.
   808  func ProgramGetNextID(startID ProgramID) (ProgramID, error) {
   809  	attr := &sys.ProgGetNextIdAttr{Id: uint32(startID)}
   810  	return ProgramID(attr.NextId), sys.ProgGetNextId(attr)
   811  }
   812  
   813  // BindMap binds map to the program and is only released once program is released.
   814  //
   815  // This may be used in cases where metadata should be associated with the program
   816  // which otherwise does not contain any references to the map.
   817  func (p *Program) BindMap(m *Map) error {
   818  	attr := &sys.ProgBindMapAttr{
   819  		ProgFd: uint32(p.FD()),
   820  		MapFd:  uint32(m.FD()),
   821  	}
   822  
   823  	return sys.ProgBindMap(attr)
   824  }
   825  
   826  var errUnrecognizedAttachType = errors.New("unrecognized attach type")
   827  
   828  // find an attach target type in the kernel.
   829  //
   830  // name, progType and attachType determine which type we need to attach to.
   831  //
   832  // The attach target may be in a loaded kernel module.
   833  // In that case the returned handle will be non-nil.
   834  // The caller is responsible for closing the handle.
   835  //
   836  // Returns errUnrecognizedAttachType if the combination of progType and attachType
   837  // is not recognised.
   838  func findTargetInKernel(name string, progType ProgramType, attachType AttachType) (*btf.Handle, btf.TypeID, error) {
   839  	type match struct {
   840  		p ProgramType
   841  		a AttachType
   842  	}
   843  
   844  	var (
   845  		typeName, featureName string
   846  		target                btf.Type
   847  	)
   848  
   849  	switch (match{progType, attachType}) {
   850  	case match{LSM, AttachLSMMac}:
   851  		typeName = "bpf_lsm_" + name
   852  		featureName = name + " LSM hook"
   853  		target = (*btf.Func)(nil)
   854  	case match{Tracing, AttachTraceIter}:
   855  		typeName = "bpf_iter_" + name
   856  		featureName = name + " iterator"
   857  		target = (*btf.Func)(nil)
   858  	case match{Tracing, AttachTraceFEntry}:
   859  		typeName = name
   860  		featureName = fmt.Sprintf("fentry %s", name)
   861  		target = (*btf.Func)(nil)
   862  	case match{Tracing, AttachTraceFExit}:
   863  		typeName = name
   864  		featureName = fmt.Sprintf("fexit %s", name)
   865  		target = (*btf.Func)(nil)
   866  	case match{Tracing, AttachModifyReturn}:
   867  		typeName = name
   868  		featureName = fmt.Sprintf("fmod_ret %s", name)
   869  		target = (*btf.Func)(nil)
   870  	case match{Tracing, AttachTraceRawTp}:
   871  		typeName = fmt.Sprintf("btf_trace_%s", name)
   872  		featureName = fmt.Sprintf("raw_tp %s", name)
   873  		target = (*btf.Typedef)(nil)
   874  	default:
   875  		return nil, 0, errUnrecognizedAttachType
   876  	}
   877  
   878  	spec, err := btf.LoadKernelSpec()
   879  	if err != nil {
   880  		return nil, 0, fmt.Errorf("load kernel spec: %w", err)
   881  	}
   882  
   883  	err = spec.TypeByName(typeName, &target)
   884  	if errors.Is(err, btf.ErrNotFound) {
   885  		module, id, err := findTargetInModule(typeName, target)
   886  		if errors.Is(err, btf.ErrNotFound) {
   887  			return nil, 0, &internal.UnsupportedFeatureError{Name: featureName}
   888  		}
   889  		if err != nil {
   890  			return nil, 0, fmt.Errorf("find target for %s in modules: %w", featureName, err)
   891  		}
   892  		return module, id, nil
   893  	}
   894  	// See cilium/ebpf#894. Until we can disambiguate between equally-named kernel
   895  	// symbols, we should explicitly refuse program loads. They will not reliably
   896  	// do what the caller intended.
   897  	if errors.Is(err, btf.ErrMultipleMatches) {
   898  		return nil, 0, fmt.Errorf("attaching to ambiguous kernel symbol is not supported: %w", err)
   899  	}
   900  	if err != nil {
   901  		return nil, 0, fmt.Errorf("find target for %s in vmlinux: %w", featureName, err)
   902  	}
   903  
   904  	id, err := spec.TypeID(target)
   905  	return nil, id, err
   906  }
   907  
   908  // find an attach target type in a kernel module.
   909  //
   910  // vmlinux must contain the kernel's types and is used to parse kmod BTF.
   911  //
   912  // Returns btf.ErrNotFound if the target can't be found in any module.
   913  func findTargetInModule(typeName string, target btf.Type) (*btf.Handle, btf.TypeID, error) {
   914  	it := new(btf.HandleIterator)
   915  	defer it.Handle.Close()
   916  
   917  	for it.Next() {
   918  		info, err := it.Handle.Info()
   919  		if err != nil {
   920  			return nil, 0, fmt.Errorf("get info for BTF ID %d: %w", it.ID, err)
   921  		}
   922  
   923  		if !info.IsModule() {
   924  			continue
   925  		}
   926  
   927  		spec, err := it.Handle.Spec()
   928  		if err != nil {
   929  			return nil, 0, fmt.Errorf("parse types for module %s: %w", info.Name, err)
   930  		}
   931  
   932  		err = spec.TypeByName(typeName, &target)
   933  		if errors.Is(err, btf.ErrNotFound) {
   934  			continue
   935  		}
   936  		if err != nil {
   937  			return nil, 0, fmt.Errorf("lookup type in module %s: %w", info.Name, err)
   938  		}
   939  
   940  		id, err := spec.TypeID(target)
   941  		if err != nil {
   942  			return nil, 0, fmt.Errorf("lookup type id in module %s: %w", info.Name, err)
   943  		}
   944  
   945  		return it.Take(), id, nil
   946  	}
   947  	if err := it.Err(); err != nil {
   948  		return nil, 0, fmt.Errorf("iterate modules: %w", err)
   949  	}
   950  
   951  	return nil, 0, btf.ErrNotFound
   952  }
   953  
   954  // find an attach target type in a program.
   955  //
   956  // Returns errUnrecognizedAttachType.
   957  func findTargetInProgram(prog *Program, name string, progType ProgramType, attachType AttachType) (btf.TypeID, error) {
   958  	type match struct {
   959  		p ProgramType
   960  		a AttachType
   961  	}
   962  
   963  	var typeName string
   964  	switch (match{progType, attachType}) {
   965  	case match{Extension, AttachNone}:
   966  		typeName = name
   967  	default:
   968  		return 0, errUnrecognizedAttachType
   969  	}
   970  
   971  	btfHandle, err := prog.Handle()
   972  	if err != nil {
   973  		return 0, fmt.Errorf("load target BTF: %w", err)
   974  	}
   975  	defer btfHandle.Close()
   976  
   977  	spec, err := btfHandle.Spec()
   978  	if err != nil {
   979  		return 0, err
   980  	}
   981  
   982  	var targetFunc *btf.Func
   983  	err = spec.TypeByName(typeName, &targetFunc)
   984  	if err != nil {
   985  		return 0, fmt.Errorf("find target %s: %w", typeName, err)
   986  	}
   987  
   988  	return spec.TypeID(targetFunc)
   989  }