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