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

     1  package link
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/cilium/ebpf"
     8  	"github.com/cilium/ebpf/btf"
     9  	"github.com/cilium/ebpf/internal/sys"
    10  )
    11  
    12  type tracing struct {
    13  	RawLink
    14  }
    15  
    16  func (f *tracing) Update(new *ebpf.Program) error {
    17  	return fmt.Errorf("tracing update: %w", ErrNotSupported)
    18  }
    19  
    20  // AttachFreplace attaches the given eBPF program to the function it replaces.
    21  //
    22  // The program and name can either be provided at link time, or can be provided
    23  // at program load time. If they were provided at load time, they should be nil
    24  // and empty respectively here, as they will be ignored by the kernel.
    25  // Examples:
    26  //
    27  //	AttachFreplace(dispatcher, "function", replacement)
    28  //	AttachFreplace(nil, "", replacement)
    29  func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (Link, error) {
    30  	if (name == "") != (targetProg == nil) {
    31  		return nil, fmt.Errorf("must provide both or neither of name and targetProg: %w", errInvalidInput)
    32  	}
    33  	if prog == nil {
    34  		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
    35  	}
    36  	if prog.Type() != ebpf.Extension {
    37  		return nil, fmt.Errorf("eBPF program type %s is not an Extension: %w", prog.Type(), errInvalidInput)
    38  	}
    39  
    40  	var (
    41  		target int
    42  		typeID btf.TypeID
    43  	)
    44  	if targetProg != nil {
    45  		btfHandle, err := targetProg.Handle()
    46  		if err != nil {
    47  			return nil, err
    48  		}
    49  		defer btfHandle.Close()
    50  
    51  		spec, err := btfHandle.Spec()
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		var function *btf.Func
    57  		if err := spec.TypeByName(name, &function); err != nil {
    58  			return nil, err
    59  		}
    60  
    61  		target = targetProg.FD()
    62  		typeID, err = spec.TypeID(function)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  	}
    67  
    68  	link, err := AttachRawLink(RawLinkOptions{
    69  		Target:  target,
    70  		Program: prog,
    71  		Attach:  ebpf.AttachNone,
    72  		BTF:     typeID,
    73  	})
    74  	if errors.Is(err, sys.ENOTSUPP) {
    75  		// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
    76  		return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
    77  	}
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return &tracing{*link}, nil
    83  }
    84  
    85  type TracingOptions struct {
    86  	// Program must be of type Tracing with attach type
    87  	// AttachTraceFEntry/AttachTraceFExit/AttachModifyReturn or
    88  	// AttachTraceRawTp.
    89  	Program *ebpf.Program
    90  }
    91  
    92  type LSMOptions struct {
    93  	// Program must be of type LSM with attach type
    94  	// AttachLSMMac.
    95  	Program *ebpf.Program
    96  }
    97  
    98  // attachBTFID links all BPF program types (Tracing/LSM) that they attach to a btf_id.
    99  func attachBTFID(program *ebpf.Program) (Link, error) {
   100  	if program.FD() < 0 {
   101  		return nil, fmt.Errorf("invalid program %w", sys.ErrClosedFd)
   102  	}
   103  
   104  	fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
   105  		ProgFd: uint32(program.FD()),
   106  	})
   107  	if errors.Is(err, sys.ENOTSUPP) {
   108  		// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
   109  		return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
   110  	}
   111  	if err != nil {
   112  		return nil, fmt.Errorf("create raw tracepoint: %w", err)
   113  	}
   114  
   115  	raw := RawLink{fd: fd}
   116  	info, err := raw.Info()
   117  	if err != nil {
   118  		raw.Close()
   119  		return nil, err
   120  	}
   121  
   122  	if info.Type == RawTracepointType {
   123  		// Sadness upon sadness: a Tracing program with AttachRawTp returns
   124  		// a raw_tracepoint link. Other types return a tracing link.
   125  		return &rawTracepoint{raw}, nil
   126  	}
   127  
   128  	return &tracing{RawLink: RawLink{fd: fd}}, nil
   129  }
   130  
   131  // AttachTracing links a tracing (fentry/fexit/fmod_ret) BPF program or
   132  // a BTF-powered raw tracepoint (tp_btf) BPF Program to a BPF hook defined
   133  // in kernel modules.
   134  func AttachTracing(opts TracingOptions) (Link, error) {
   135  	if t := opts.Program.Type(); t != ebpf.Tracing {
   136  		return nil, fmt.Errorf("invalid program type %s, expected Tracing", t)
   137  	}
   138  
   139  	return attachBTFID(opts.Program)
   140  }
   141  
   142  // AttachLSM links a Linux security module (LSM) BPF Program to a BPF
   143  // hook defined in kernel modules.
   144  func AttachLSM(opts LSMOptions) (Link, error) {
   145  	if t := opts.Program.Type(); t != ebpf.LSM {
   146  		return nil, fmt.Errorf("invalid program type %s, expected LSM", t)
   147  	}
   148  
   149  	return attachBTFID(opts.Program)
   150  }