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 }