prog.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. package ebpf
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "math"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/cilium/ebpf/asm"
  13. "github.com/cilium/ebpf/internal"
  14. "github.com/cilium/ebpf/internal/btf"
  15. "github.com/cilium/ebpf/internal/unix"
  16. )
  17. // ErrNotSupported is returned whenever the kernel doesn't support a feature.
  18. var ErrNotSupported = internal.ErrNotSupported
  19. var errUnsatisfiedReference = errors.New("unsatisfied reference")
  20. // ProgramID represents the unique ID of an eBPF program.
  21. type ProgramID uint32
  22. const (
  23. // Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN.
  24. // This is currently the maximum of spare space allocated for SKB
  25. // and XDP programs, and equal to XDP_PACKET_HEADROOM + NET_IP_ALIGN.
  26. outputPad = 256 + 2
  27. )
  28. // DefaultVerifierLogSize is the default number of bytes allocated for the
  29. // verifier log.
  30. const DefaultVerifierLogSize = 64 * 1024
  31. // ProgramOptions control loading a program into the kernel.
  32. type ProgramOptions struct {
  33. // Controls the detail emitted by the kernel verifier. Set to non-zero
  34. // to enable logging.
  35. LogLevel uint32
  36. // Controls the output buffer size for the verifier. Defaults to
  37. // DefaultVerifierLogSize.
  38. LogSize int
  39. // An ELF containing the target BTF for this program. It is used both to
  40. // find the correct function to trace and to apply CO-RE relocations.
  41. // This is useful in environments where the kernel BTF is not available
  42. // (containers) or where it is in a non-standard location. Defaults to
  43. // use the kernel BTF from a well-known location.
  44. TargetBTF io.ReaderAt
  45. }
  46. // ProgramSpec defines a Program.
  47. type ProgramSpec struct {
  48. // Name is passed to the kernel as a debug aid. Must only contain
  49. // alpha numeric and '_' characters.
  50. Name string
  51. // Type determines at which hook in the kernel a program will run.
  52. Type ProgramType
  53. AttachType AttachType
  54. // Name of a kernel data structure or function to attach to. Its
  55. // interpretation depends on Type and AttachType.
  56. AttachTo string
  57. // The program to attach to. Must be provided manually.
  58. AttachTarget *Program
  59. Instructions asm.Instructions
  60. // Flags is passed to the kernel and specifies additional program
  61. // load attributes.
  62. Flags uint32
  63. // License of the program. Some helpers are only available if
  64. // the license is deemed compatible with the GPL.
  65. //
  66. // See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1
  67. License string
  68. // Version used by Kprobe programs.
  69. //
  70. // Deprecated on kernels 5.0 and later. Leave empty to let the library
  71. // detect this value automatically.
  72. KernelVersion uint32
  73. // The BTF associated with this program. Changing Instructions
  74. // will most likely invalidate the contained data, and may
  75. // result in errors when attempting to load it into the kernel.
  76. BTF *btf.Program
  77. // The byte order this program was compiled for, may be nil.
  78. ByteOrder binary.ByteOrder
  79. }
  80. // Copy returns a copy of the spec.
  81. func (ps *ProgramSpec) Copy() *ProgramSpec {
  82. if ps == nil {
  83. return nil
  84. }
  85. cpy := *ps
  86. cpy.Instructions = make(asm.Instructions, len(ps.Instructions))
  87. copy(cpy.Instructions, ps.Instructions)
  88. return &cpy
  89. }
  90. // Tag calculates the kernel tag for a series of instructions.
  91. //
  92. // Use asm.Instructions.Tag if you need to calculate for non-native endianness.
  93. func (ps *ProgramSpec) Tag() (string, error) {
  94. return ps.Instructions.Tag(internal.NativeEndian)
  95. }
  96. // Program represents BPF program loaded into the kernel.
  97. //
  98. // It is not safe to close a Program which is used by other goroutines.
  99. type Program struct {
  100. // Contains the output of the kernel verifier if enabled,
  101. // otherwise it is empty.
  102. VerifierLog string
  103. fd *internal.FD
  104. name string
  105. pinnedPath string
  106. typ ProgramType
  107. }
  108. // NewProgram creates a new Program.
  109. //
  110. // Loading a program for the first time will perform
  111. // feature detection by loading small, temporary programs.
  112. func NewProgram(spec *ProgramSpec) (*Program, error) {
  113. return NewProgramWithOptions(spec, ProgramOptions{})
  114. }
  115. // NewProgramWithOptions creates a new Program.
  116. //
  117. // Loading a program for the first time will perform
  118. // feature detection by loading small, temporary programs.
  119. func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
  120. handles := newHandleCache()
  121. defer handles.close()
  122. prog, err := newProgramWithOptions(spec, opts, handles)
  123. if errors.Is(err, errUnsatisfiedReference) {
  124. return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err)
  125. }
  126. return prog, err
  127. }
  128. func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) {
  129. if len(spec.Instructions) == 0 {
  130. return nil, errors.New("instructions cannot be empty")
  131. }
  132. if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
  133. return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
  134. }
  135. // Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
  136. // require the version field to be set to the value of the KERNEL_VERSION
  137. // macro for kprobe-type programs.
  138. // Overwrite Kprobe program version if set to zero or the magic version constant.
  139. kv := spec.KernelVersion
  140. if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
  141. v, err := internal.KernelVersion()
  142. if err != nil {
  143. return nil, fmt.Errorf("detecting kernel version: %w", err)
  144. }
  145. kv = v.Kernel()
  146. }
  147. attr := &internal.BPFProgLoadAttr{
  148. ProgType: uint32(spec.Type),
  149. ProgFlags: spec.Flags,
  150. ExpectedAttachType: uint32(spec.AttachType),
  151. License: internal.NewStringPointer(spec.License),
  152. KernelVersion: kv,
  153. }
  154. if haveObjName() == nil {
  155. attr.ProgName = internal.NewBPFObjName(spec.Name)
  156. }
  157. var err error
  158. var targetBTF *btf.Spec
  159. if opts.TargetBTF != nil {
  160. targetBTF, err = handles.btfSpec(opts.TargetBTF)
  161. if err != nil {
  162. return nil, fmt.Errorf("load target BTF: %w", err)
  163. }
  164. }
  165. var btfDisabled bool
  166. var core btf.COREFixups
  167. if spec.BTF != nil {
  168. core, err = spec.BTF.Fixups(targetBTF)
  169. if err != nil {
  170. return nil, fmt.Errorf("CO-RE relocations: %w", err)
  171. }
  172. handle, err := handles.btfHandle(spec.BTF.Spec())
  173. btfDisabled = errors.Is(err, btf.ErrNotSupported)
  174. if err != nil && !btfDisabled {
  175. return nil, fmt.Errorf("load BTF: %w", err)
  176. }
  177. if handle != nil {
  178. attr.ProgBTFFd = uint32(handle.FD())
  179. recSize, bytes, err := spec.BTF.LineInfos()
  180. if err != nil {
  181. return nil, fmt.Errorf("get BTF line infos: %w", err)
  182. }
  183. attr.LineInfoRecSize = recSize
  184. attr.LineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
  185. attr.LineInfo = internal.NewSlicePointer(bytes)
  186. recSize, bytes, err = spec.BTF.FuncInfos()
  187. if err != nil {
  188. return nil, fmt.Errorf("get BTF function infos: %w", err)
  189. }
  190. attr.FuncInfoRecSize = recSize
  191. attr.FuncInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
  192. attr.FuncInfo = internal.NewSlicePointer(bytes)
  193. }
  194. }
  195. insns, err := core.Apply(spec.Instructions)
  196. if err != nil {
  197. return nil, fmt.Errorf("CO-RE fixup: %w", err)
  198. }
  199. if err := fixupJumpsAndCalls(insns); err != nil {
  200. return nil, err
  201. }
  202. buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
  203. err = insns.Marshal(buf, internal.NativeEndian)
  204. if err != nil {
  205. return nil, err
  206. }
  207. bytecode := buf.Bytes()
  208. attr.Instructions = internal.NewSlicePointer(bytecode)
  209. attr.InsCount = uint32(len(bytecode) / asm.InstructionSize)
  210. if spec.AttachTo != "" {
  211. if spec.AttachTarget != nil {
  212. info, err := spec.AttachTarget.Info()
  213. if err != nil {
  214. return nil, fmt.Errorf("load target BTF: %w", err)
  215. }
  216. btfID, ok := info.BTFID()
  217. if !ok {
  218. return nil, fmt.Errorf("load target BTF: no BTF info available")
  219. }
  220. btfHandle, err := btf.NewHandleFromID(btfID)
  221. if err != nil {
  222. return nil, fmt.Errorf("load target BTF: %w", err)
  223. }
  224. defer btfHandle.Close()
  225. targetBTF = btfHandle.Spec()
  226. if err != nil {
  227. return nil, fmt.Errorf("load target BTF: %w", err)
  228. }
  229. }
  230. target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType)
  231. if err != nil {
  232. return nil, err
  233. }
  234. if target != nil {
  235. attr.AttachBTFID = uint32(target.ID())
  236. }
  237. if spec.AttachTarget != nil {
  238. attr.AttachProgFd = uint32(spec.AttachTarget.FD())
  239. }
  240. }
  241. logSize := DefaultVerifierLogSize
  242. if opts.LogSize > 0 {
  243. logSize = opts.LogSize
  244. }
  245. var logBuf []byte
  246. if opts.LogLevel > 0 {
  247. logBuf = make([]byte, logSize)
  248. attr.LogLevel = opts.LogLevel
  249. attr.LogSize = uint32(len(logBuf))
  250. attr.LogBuf = internal.NewSlicePointer(logBuf)
  251. }
  252. fd, err := internal.BPFProgLoad(attr)
  253. if err == nil {
  254. return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil
  255. }
  256. logErr := err
  257. if opts.LogLevel == 0 && opts.LogSize >= 0 {
  258. // Re-run with the verifier enabled to get better error messages.
  259. logBuf = make([]byte, logSize)
  260. attr.LogLevel = 1
  261. attr.LogSize = uint32(len(logBuf))
  262. attr.LogBuf = internal.NewSlicePointer(logBuf)
  263. fd, logErr = internal.BPFProgLoad(attr)
  264. if logErr == nil {
  265. fd.Close()
  266. }
  267. }
  268. if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 {
  269. // EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can
  270. // check that the log is empty to reduce false positives.
  271. return nil, fmt.Errorf("load program: %w (MEMLOCK bay be too low, consider rlimit.RemoveMemlock)", logErr)
  272. }
  273. err = internal.ErrorWithLog(err, logBuf, logErr)
  274. if btfDisabled {
  275. return nil, fmt.Errorf("load program without BTF: %w", err)
  276. }
  277. return nil, fmt.Errorf("load program: %w", err)
  278. }
  279. // NewProgramFromFD creates a program from a raw fd.
  280. //
  281. // You should not use fd after calling this function.
  282. //
  283. // Requires at least Linux 4.10.
  284. func NewProgramFromFD(fd int) (*Program, error) {
  285. if fd < 0 {
  286. return nil, errors.New("invalid fd")
  287. }
  288. return newProgramFromFD(internal.NewFD(uint32(fd)))
  289. }
  290. // NewProgramFromID returns the program for a given id.
  291. //
  292. // Returns ErrNotExist, if there is no eBPF program with the given id.
  293. func NewProgramFromID(id ProgramID) (*Program, error) {
  294. fd, err := internal.BPFObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id))
  295. if err != nil {
  296. return nil, fmt.Errorf("get program by id: %w", err)
  297. }
  298. return newProgramFromFD(fd)
  299. }
  300. func newProgramFromFD(fd *internal.FD) (*Program, error) {
  301. info, err := newProgramInfoFromFd(fd)
  302. if err != nil {
  303. fd.Close()
  304. return nil, fmt.Errorf("discover program type: %w", err)
  305. }
  306. return &Program{"", fd, "", "", info.Type}, nil
  307. }
  308. func (p *Program) String() string {
  309. if p.name != "" {
  310. return fmt.Sprintf("%s(%s)#%v", p.typ, p.name, p.fd)
  311. }
  312. return fmt.Sprintf("%s(%v)", p.typ, p.fd)
  313. }
  314. // Type returns the underlying type of the program.
  315. func (p *Program) Type() ProgramType {
  316. return p.typ
  317. }
  318. // Info returns metadata about the program.
  319. //
  320. // Requires at least 4.10.
  321. func (p *Program) Info() (*ProgramInfo, error) {
  322. return newProgramInfoFromFd(p.fd)
  323. }
  324. // FD gets the file descriptor of the Program.
  325. //
  326. // It is invalid to call this function after Close has been called.
  327. func (p *Program) FD() int {
  328. fd, err := p.fd.Value()
  329. if err != nil {
  330. // Best effort: -1 is the number most likely to be an
  331. // invalid file descriptor.
  332. return -1
  333. }
  334. return int(fd)
  335. }
  336. // Clone creates a duplicate of the Program.
  337. //
  338. // Closing the duplicate does not affect the original, and vice versa.
  339. //
  340. // Cloning a nil Program returns nil.
  341. func (p *Program) Clone() (*Program, error) {
  342. if p == nil {
  343. return nil, nil
  344. }
  345. dup, err := p.fd.Dup()
  346. if err != nil {
  347. return nil, fmt.Errorf("can't clone program: %w", err)
  348. }
  349. return &Program{p.VerifierLog, dup, p.name, "", p.typ}, nil
  350. }
  351. // Pin persists the Program on the BPF virtual file system past the lifetime of
  352. // the process that created it
  353. //
  354. // Calling Pin on a previously pinned program will overwrite the path, except when
  355. // the new path already exists. Re-pinning across filesystems is not supported.
  356. //
  357. // This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs
  358. func (p *Program) Pin(fileName string) error {
  359. if err := internal.Pin(p.pinnedPath, fileName, p.fd); err != nil {
  360. return err
  361. }
  362. p.pinnedPath = fileName
  363. return nil
  364. }
  365. // Unpin removes the persisted state for the Program from the BPF virtual filesystem.
  366. //
  367. // Failed calls to Unpin will not alter the state returned by IsPinned.
  368. //
  369. // Unpinning an unpinned Program returns nil.
  370. func (p *Program) Unpin() error {
  371. if err := internal.Unpin(p.pinnedPath); err != nil {
  372. return err
  373. }
  374. p.pinnedPath = ""
  375. return nil
  376. }
  377. // IsPinned returns true if the Program has a non-empty pinned path.
  378. func (p *Program) IsPinned() bool {
  379. return p.pinnedPath != ""
  380. }
  381. // Close unloads the program from the kernel.
  382. func (p *Program) Close() error {
  383. if p == nil {
  384. return nil
  385. }
  386. return p.fd.Close()
  387. }
  388. // Test runs the Program in the kernel with the given input and returns the
  389. // value returned by the eBPF program. outLen may be zero.
  390. //
  391. // Note: the kernel expects at least 14 bytes input for an ethernet header for
  392. // XDP and SKB programs.
  393. //
  394. // This function requires at least Linux 4.12.
  395. func (p *Program) Test(in []byte) (uint32, []byte, error) {
  396. ret, out, _, err := p.testRun(in, 1, nil)
  397. if err != nil {
  398. return ret, nil, fmt.Errorf("can't test program: %w", err)
  399. }
  400. return ret, out, nil
  401. }
  402. // Benchmark runs the Program with the given input for a number of times
  403. // and returns the time taken per iteration.
  404. //
  405. // Returns the result of the last execution of the program and the time per
  406. // run or an error. reset is called whenever the benchmark syscall is
  407. // interrupted, and should be set to testing.B.ResetTimer or similar.
  408. //
  409. // Note: profiling a call to this function will skew it's results, see
  410. // https://github.com/cilium/ebpf/issues/24
  411. //
  412. // This function requires at least Linux 4.12.
  413. func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
  414. ret, _, total, err := p.testRun(in, repeat, reset)
  415. if err != nil {
  416. return ret, total, fmt.Errorf("can't benchmark program: %w", err)
  417. }
  418. return ret, total, nil
  419. }
  420. var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() error {
  421. prog, err := NewProgram(&ProgramSpec{
  422. Type: SocketFilter,
  423. Instructions: asm.Instructions{
  424. asm.LoadImm(asm.R0, 0, asm.DWord),
  425. asm.Return(),
  426. },
  427. License: "MIT",
  428. })
  429. if err != nil {
  430. // This may be because we lack sufficient permissions, etc.
  431. return err
  432. }
  433. defer prog.Close()
  434. // Programs require at least 14 bytes input
  435. in := make([]byte, 14)
  436. attr := bpfProgTestRunAttr{
  437. fd: uint32(prog.FD()),
  438. dataSizeIn: uint32(len(in)),
  439. dataIn: internal.NewSlicePointer(in),
  440. }
  441. err = bpfProgTestRun(&attr)
  442. if errors.Is(err, unix.EINVAL) {
  443. // Check for EINVAL specifically, rather than err != nil since we
  444. // otherwise misdetect due to insufficient permissions.
  445. return internal.ErrNotSupported
  446. }
  447. if errors.Is(err, unix.EINTR) {
  448. // We know that PROG_TEST_RUN is supported if we get EINTR.
  449. return nil
  450. }
  451. return err
  452. })
  453. func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) {
  454. if uint(repeat) > math.MaxUint32 {
  455. return 0, nil, 0, fmt.Errorf("repeat is too high")
  456. }
  457. if len(in) == 0 {
  458. return 0, nil, 0, fmt.Errorf("missing input")
  459. }
  460. if uint(len(in)) > math.MaxUint32 {
  461. return 0, nil, 0, fmt.Errorf("input is too long")
  462. }
  463. if err := haveProgTestRun(); err != nil {
  464. return 0, nil, 0, err
  465. }
  466. // Older kernels ignore the dataSizeOut argument when copying to user space.
  467. // Combined with things like bpf_xdp_adjust_head() we don't really know what the final
  468. // size will be. Hence we allocate an output buffer which we hope will always be large
  469. // enough, and panic if the kernel wrote past the end of the allocation.
  470. // See https://patchwork.ozlabs.org/cover/1006822/
  471. out := make([]byte, len(in)+outputPad)
  472. fd, err := p.fd.Value()
  473. if err != nil {
  474. return 0, nil, 0, err
  475. }
  476. attr := bpfProgTestRunAttr{
  477. fd: fd,
  478. dataSizeIn: uint32(len(in)),
  479. dataSizeOut: uint32(len(out)),
  480. dataIn: internal.NewSlicePointer(in),
  481. dataOut: internal.NewSlicePointer(out),
  482. repeat: uint32(repeat),
  483. }
  484. for {
  485. err = bpfProgTestRun(&attr)
  486. if err == nil {
  487. break
  488. }
  489. if errors.Is(err, unix.EINTR) {
  490. if reset != nil {
  491. reset()
  492. }
  493. continue
  494. }
  495. return 0, nil, 0, fmt.Errorf("can't run test: %w", err)
  496. }
  497. if int(attr.dataSizeOut) > cap(out) {
  498. // Houston, we have a problem. The program created more data than we allocated,
  499. // and the kernel wrote past the end of our buffer.
  500. panic("kernel wrote past end of output buffer")
  501. }
  502. out = out[:int(attr.dataSizeOut)]
  503. total := time.Duration(attr.duration) * time.Nanosecond
  504. return attr.retval, out, total, nil
  505. }
  506. func unmarshalProgram(buf []byte) (*Program, error) {
  507. if len(buf) != 4 {
  508. return nil, errors.New("program id requires 4 byte value")
  509. }
  510. // Looking up an entry in a nested map or prog array returns an id,
  511. // not an fd.
  512. id := internal.NativeEndian.Uint32(buf)
  513. return NewProgramFromID(ProgramID(id))
  514. }
  515. func marshalProgram(p *Program, length int) ([]byte, error) {
  516. if length != 4 {
  517. return nil, fmt.Errorf("can't marshal program to %d bytes", length)
  518. }
  519. value, err := p.fd.Value()
  520. if err != nil {
  521. return nil, err
  522. }
  523. buf := make([]byte, 4)
  524. internal.NativeEndian.PutUint32(buf, value)
  525. return buf, nil
  526. }
  527. // Attach a Program.
  528. //
  529. // Deprecated: use link.RawAttachProgram instead.
  530. func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
  531. if fd < 0 {
  532. return errors.New("invalid fd")
  533. }
  534. pfd, err := p.fd.Value()
  535. if err != nil {
  536. return err
  537. }
  538. attr := internal.BPFProgAttachAttr{
  539. TargetFd: uint32(fd),
  540. AttachBpfFd: pfd,
  541. AttachType: uint32(typ),
  542. AttachFlags: uint32(flags),
  543. }
  544. return internal.BPFProgAttach(&attr)
  545. }
  546. // Detach a Program.
  547. //
  548. // Deprecated: use link.RawDetachProgram instead.
  549. func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
  550. if fd < 0 {
  551. return errors.New("invalid fd")
  552. }
  553. if flags != 0 {
  554. return errors.New("flags must be zero")
  555. }
  556. pfd, err := p.fd.Value()
  557. if err != nil {
  558. return err
  559. }
  560. attr := internal.BPFProgDetachAttr{
  561. TargetFd: uint32(fd),
  562. AttachBpfFd: pfd,
  563. AttachType: uint32(typ),
  564. }
  565. return internal.BPFProgDetach(&attr)
  566. }
  567. // LoadPinnedProgram loads a Program from a BPF file.
  568. //
  569. // Requires at least Linux 4.11.
  570. func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) {
  571. fd, err := internal.BPFObjGet(fileName, opts.Marshal())
  572. if err != nil {
  573. return nil, err
  574. }
  575. info, err := newProgramInfoFromFd(fd)
  576. if err != nil {
  577. _ = fd.Close()
  578. return nil, fmt.Errorf("info for %s: %w", fileName, err)
  579. }
  580. return &Program{"", fd, filepath.Base(fileName), fileName, info.Type}, nil
  581. }
  582. // SanitizeName replaces all invalid characters in name with replacement.
  583. // Passing a negative value for replacement will delete characters instead
  584. // of replacing them. Use this to automatically generate valid names for maps
  585. // and programs at runtime.
  586. //
  587. // The set of allowed characters depends on the running kernel version.
  588. // Dots are only allowed as of kernel 5.2.
  589. func SanitizeName(name string, replacement rune) string {
  590. return strings.Map(func(char rune) rune {
  591. if invalidBPFObjNameChar(char) {
  592. return replacement
  593. }
  594. return char
  595. }, name)
  596. }
  597. // ProgramGetNextID returns the ID of the next eBPF program.
  598. //
  599. // Returns ErrNotExist, if there is no next eBPF program.
  600. func ProgramGetNextID(startID ProgramID) (ProgramID, error) {
  601. id, err := objGetNextID(internal.BPF_PROG_GET_NEXT_ID, uint32(startID))
  602. return ProgramID(id), err
  603. }
  604. // ID returns the systemwide unique ID of the program.
  605. //
  606. // Deprecated: use ProgramInfo.ID() instead.
  607. func (p *Program) ID() (ProgramID, error) {
  608. info, err := bpfGetProgInfoByFD(p.fd, nil)
  609. if err != nil {
  610. return ProgramID(0), err
  611. }
  612. return ProgramID(info.id), nil
  613. }
  614. func resolveBTFType(spec *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
  615. type match struct {
  616. p ProgramType
  617. a AttachType
  618. }
  619. var typeName, featureName string
  620. switch (match{progType, attachType}) {
  621. case match{LSM, AttachLSMMac}:
  622. typeName = "bpf_lsm_" + name
  623. featureName = name + " LSM hook"
  624. case match{Tracing, AttachTraceIter}:
  625. typeName = "bpf_iter_" + name
  626. featureName = name + " iterator"
  627. case match{Extension, AttachNone}:
  628. typeName = name
  629. featureName = fmt.Sprintf("freplace %s", name)
  630. default:
  631. return nil, nil
  632. }
  633. if spec == nil {
  634. var err error
  635. spec, err = btf.LoadKernelSpec()
  636. if err != nil {
  637. return nil, fmt.Errorf("load kernel spec: %w", err)
  638. }
  639. }
  640. var target *btf.Func
  641. err := spec.FindType(typeName, &target)
  642. if errors.Is(err, btf.ErrNotFound) {
  643. return nil, &internal.UnsupportedFeatureError{
  644. Name: featureName,
  645. }
  646. }
  647. if err != nil {
  648. return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err)
  649. }
  650. return target, nil
  651. }