...

Source file src/github.com/cilium/ebpf/prog.go

Documentation: github.com/cilium/ebpf

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

View as plain text