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