1 package ebpf
2
3 import (
4 "bufio"
5 "bytes"
6 "debug/elf"
7 "encoding/binary"
8 "errors"
9 "fmt"
10 "io"
11 "math"
12 "os"
13 "strings"
14
15 "github.com/cilium/ebpf/asm"
16 "github.com/cilium/ebpf/btf"
17 "github.com/cilium/ebpf/internal"
18 "github.com/cilium/ebpf/internal/unix"
19 )
20
21
22
23 type elfCode struct {
24 *internal.SafeELFFile
25 sections map[elf.SectionIndex]*elfSection
26 license string
27 version uint32
28 btf *btf.Spec
29 extInfo *btf.ExtInfos
30 }
31
32
33 func LoadCollectionSpec(file string) (*CollectionSpec, error) {
34 f, err := os.Open(file)
35 if err != nil {
36 return nil, err
37 }
38 defer f.Close()
39
40 spec, err := LoadCollectionSpecFromReader(f)
41 if err != nil {
42 return nil, fmt.Errorf("file %s: %w", file, err)
43 }
44 return spec, nil
45 }
46
47
48 func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
49 f, err := internal.NewSafeELFFile(rd)
50 if err != nil {
51 return nil, err
52 }
53
54 var (
55 licenseSection *elf.Section
56 versionSection *elf.Section
57 sections = make(map[elf.SectionIndex]*elfSection)
58 relSections = make(map[elf.SectionIndex]*elf.Section)
59 )
60
61
62 sections[elf.SHN_UNDEF] = newElfSection(new(elf.Section), undefSection)
63
64
65
66 for i, sec := range f.Sections {
67 idx := elf.SectionIndex(i)
68
69 switch {
70 case strings.HasPrefix(sec.Name, "license"):
71 licenseSection = sec
72 case strings.HasPrefix(sec.Name, "version"):
73 versionSection = sec
74 case strings.HasPrefix(sec.Name, "maps"):
75 sections[idx] = newElfSection(sec, mapSection)
76 case sec.Name == ".maps":
77 sections[idx] = newElfSection(sec, btfMapSection)
78 case sec.Name == ".bss" || sec.Name == ".data" || strings.HasPrefix(sec.Name, ".rodata"):
79 sections[idx] = newElfSection(sec, dataSection)
80 case sec.Type == elf.SHT_REL:
81
82 relSections[elf.SectionIndex(sec.Info)] = sec
83 case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
84 sections[idx] = newElfSection(sec, programSection)
85 }
86 }
87
88 license, err := loadLicense(licenseSection)
89 if err != nil {
90 return nil, fmt.Errorf("load license: %w", err)
91 }
92
93 version, err := loadVersion(versionSection, f.ByteOrder)
94 if err != nil {
95 return nil, fmt.Errorf("load version: %w", err)
96 }
97
98 btfSpec, btfExtInfo, err := btf.LoadSpecAndExtInfosFromReader(rd)
99 if err != nil && !errors.Is(err, btf.ErrNotFound) {
100 return nil, fmt.Errorf("load BTF: %w", err)
101 }
102
103 ec := &elfCode{
104 SafeELFFile: f,
105 sections: sections,
106 license: license,
107 version: version,
108 btf: btfSpec,
109 extInfo: btfExtInfo,
110 }
111
112 symbols, err := f.Symbols()
113 if err != nil {
114 return nil, fmt.Errorf("load symbols: %v", err)
115 }
116
117 ec.assignSymbols(symbols)
118
119 if err := ec.loadRelocations(relSections, symbols); err != nil {
120 return nil, fmt.Errorf("load relocations: %w", err)
121 }
122
123
124 maps := make(map[string]*MapSpec)
125 if err := ec.loadMaps(maps); err != nil {
126 return nil, fmt.Errorf("load maps: %w", err)
127 }
128
129 if err := ec.loadBTFMaps(maps); err != nil {
130 return nil, fmt.Errorf("load BTF maps: %w", err)
131 }
132
133 if err := ec.loadDataSections(maps); err != nil {
134 return nil, fmt.Errorf("load data sections: %w", err)
135 }
136
137
138 progs, err := ec.loadProgramSections()
139 if err != nil {
140 return nil, fmt.Errorf("load programs: %w", err)
141 }
142
143 return &CollectionSpec{maps, progs, btfSpec, ec.ByteOrder}, nil
144 }
145
146 func loadLicense(sec *elf.Section) (string, error) {
147 if sec == nil {
148 return "", nil
149 }
150
151 data, err := sec.Data()
152 if err != nil {
153 return "", fmt.Errorf("section %s: %v", sec.Name, err)
154 }
155 return string(bytes.TrimRight(data, "\000")), nil
156 }
157
158 func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
159 if sec == nil {
160 return 0, nil
161 }
162
163 var version uint32
164 if err := binary.Read(sec.Open(), bo, &version); err != nil {
165 return 0, fmt.Errorf("section %s: %v", sec.Name, err)
166 }
167 return version, nil
168 }
169
170 type elfSectionKind int
171
172 const (
173 undefSection elfSectionKind = iota
174 mapSection
175 btfMapSection
176 programSection
177 dataSection
178 )
179
180 type elfSection struct {
181 *elf.Section
182 kind elfSectionKind
183
184 symbols map[uint64]elf.Symbol
185
186
187 relocations map[uint64]elf.Symbol
188
189 references int
190 }
191
192 func newElfSection(section *elf.Section, kind elfSectionKind) *elfSection {
193 return &elfSection{
194 section,
195 kind,
196 make(map[uint64]elf.Symbol),
197 make(map[uint64]elf.Symbol),
198 0,
199 }
200 }
201
202
203
204 func (ec *elfCode) assignSymbols(symbols []elf.Symbol) {
205 for _, symbol := range symbols {
206 symType := elf.ST_TYPE(symbol.Info)
207 symSection := ec.sections[symbol.Section]
208 if symSection == nil {
209 continue
210 }
211
212
213
214 if symbol.Name == "" {
215 continue
216 }
217
218
219
220 switch symSection.kind {
221 case mapSection, btfMapSection, dataSection:
222 if symType != elf.STT_NOTYPE && symType != elf.STT_OBJECT {
223 continue
224 }
225 case programSection:
226 if symType != elf.STT_NOTYPE && symType != elf.STT_FUNC {
227 continue
228 }
229
230
231 if symType == elf.STT_NOTYPE && elf.ST_BIND(symbol.Info) == elf.STB_LOCAL &&
232 strings.HasPrefix(symbol.Name, "LBB") {
233 continue
234 }
235
236 default:
237 continue
238 }
239
240 symSection.symbols[symbol.Value] = symbol
241 }
242 }
243
244
245
246 func (ec *elfCode) loadRelocations(relSections map[elf.SectionIndex]*elf.Section, symbols []elf.Symbol) error {
247 for idx, relSection := range relSections {
248 section := ec.sections[idx]
249 if section == nil {
250 continue
251 }
252
253 rels, err := ec.loadSectionRelocations(relSection, symbols)
254 if err != nil {
255 return fmt.Errorf("relocation for section %q: %w", section.Name, err)
256 }
257
258 for _, rel := range rels {
259 target := ec.sections[rel.Section]
260 if target == nil {
261 return fmt.Errorf("section %q: reference to %q in section %s: %w", section.Name, rel.Name, rel.Section, ErrNotSupported)
262 }
263
264 if target.Flags&elf.SHF_STRINGS > 0 {
265 return fmt.Errorf("section %q: string is not stack allocated: %w", section.Name, ErrNotSupported)
266 }
267
268 target.references++
269 }
270
271 section.relocations = rels
272 }
273
274 return nil
275 }
276
277
278
279
280
281 func (ec *elfCode) loadProgramSections() (map[string]*ProgramSpec, error) {
282
283 progs := make(map[string]*ProgramSpec)
284
285
286 var export []string
287 for _, sec := range ec.sections {
288 if sec.kind != programSection {
289 continue
290 }
291
292 if len(sec.symbols) == 0 {
293 return nil, fmt.Errorf("section %v: missing symbols", sec.Name)
294 }
295
296 funcs, err := ec.loadFunctions(sec)
297 if err != nil {
298 return nil, fmt.Errorf("section %v: %w", sec.Name, err)
299 }
300
301 progType, attachType, progFlags, attachTo := getProgType(sec.Name)
302
303 for name, insns := range funcs {
304 spec := &ProgramSpec{
305 Name: name,
306 Type: progType,
307 Flags: progFlags,
308 AttachType: attachType,
309 AttachTo: attachTo,
310 SectionName: sec.Name,
311 License: ec.license,
312 KernelVersion: ec.version,
313 Instructions: insns,
314 ByteOrder: ec.ByteOrder,
315 BTF: ec.btf,
316 }
317
318
319 if progs[name] != nil {
320 return nil, fmt.Errorf("duplicate program name %s", name)
321 }
322 progs[name] = spec
323
324 if spec.SectionName != ".text" {
325 export = append(export, name)
326 }
327 }
328 }
329
330 flattenPrograms(progs, export)
331
332
333
334
335 for n, p := range progs {
336 if p.SectionName == ".text" {
337 delete(progs, n)
338 }
339 }
340
341 return progs, nil
342 }
343
344
345
346
347
348
349 func (ec *elfCode) loadFunctions(section *elfSection) (map[string]asm.Instructions, error) {
350 r := bufio.NewReader(section.Open())
351
352
353 var insns asm.Instructions
354 if err := insns.Unmarshal(r, ec.ByteOrder); err != nil {
355 return nil, fmt.Errorf("decoding instructions for section %s: %w", section.Name, err)
356 }
357 if len(insns) == 0 {
358 return nil, fmt.Errorf("no instructions found in section %s", section.Name)
359 }
360
361 iter := insns.Iterate()
362 for iter.Next() {
363 ins := iter.Ins
364 offset := iter.Offset.Bytes()
365
366
367 if sym, ok := section.symbols[offset]; ok {
368 *ins = ins.WithSymbol(sym.Name)
369 }
370
371
372
373 if rel, ok := section.relocations[offset]; ok {
374 if err := ec.relocateInstruction(ins, rel); err != nil {
375 return nil, fmt.Errorf("offset %d: relocating instruction: %w", offset, err)
376 }
377 } else {
378 if err := referenceRelativeJump(ins, offset, section.symbols); err != nil {
379 return nil, fmt.Errorf("offset %d: resolving relative jump: %w", offset, err)
380 }
381 }
382 }
383
384 if ec.extInfo != nil {
385 ec.extInfo.Assign(insns, section.Name)
386 }
387
388 return splitSymbols(insns)
389 }
390
391
392
393
394
395
396
397
398
399
400
401 func referenceRelativeJump(ins *asm.Instruction, offset uint64, symbols map[uint64]elf.Symbol) error {
402 if !ins.IsFunctionReference() || ins.Constant == -1 {
403 return nil
404 }
405
406 tgt := jumpTarget(offset, *ins)
407 sym := symbols[tgt].Name
408 if sym == "" {
409 return fmt.Errorf("no jump target found at offset %d", tgt)
410 }
411
412 *ins = ins.WithReference(sym)
413 ins.Constant = -1
414
415 return nil
416 }
417
418
419
420
421 func jumpTarget(offset uint64, ins asm.Instruction) uint64 {
422
423
424 dest := ins.Constant * asm.InstructionSize
425
426
427 dest += int64(offset + asm.InstructionSize)
428
429 if dest < 0 {
430 return 0
431 }
432
433 return uint64(dest)
434 }
435
436 func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) error {
437 var (
438 typ = elf.ST_TYPE(rel.Info)
439 bind = elf.ST_BIND(rel.Info)
440 name = rel.Name
441 )
442
443 target := ec.sections[rel.Section]
444
445 switch target.kind {
446 case mapSection, btfMapSection:
447 if bind != elf.STB_GLOBAL {
448 return fmt.Errorf("possible erroneous static qualifier on map definition: found reference to %q", name)
449 }
450
451 if typ != elf.STT_OBJECT && typ != elf.STT_NOTYPE {
452
453
454 return fmt.Errorf("map load: incorrect relocation type %v", typ)
455 }
456
457 ins.Src = asm.PseudoMapFD
458
459 case dataSection:
460 var offset uint32
461 switch typ {
462 case elf.STT_SECTION:
463 if bind != elf.STB_LOCAL {
464 return fmt.Errorf("direct load: %s: unsupported section relocation %s", name, bind)
465 }
466
467
468
469
470 offset = uint32(uint64(ins.Constant))
471
472 case elf.STT_OBJECT:
473
474 if bind != elf.STB_GLOBAL && bind != elf.STB_LOCAL {
475 return fmt.Errorf("direct load: %s: unsupported object relocation %s", name, bind)
476 }
477
478 offset = uint32(rel.Value)
479
480 case elf.STT_NOTYPE:
481
482 if bind != elf.STB_LOCAL {
483 return fmt.Errorf("direct load: %s: unsupported untyped relocation %s", name, bind)
484 }
485
486 offset = uint32(rel.Value)
487
488 default:
489 return fmt.Errorf("incorrect relocation type %v for direct map load", typ)
490 }
491
492
493
494
495 name = target.Name
496
497
498 ins.Constant = int64(uint64(offset) << 32)
499 ins.Src = asm.PseudoMapValue
500
501 case programSection:
502 switch opCode := ins.OpCode; {
503 case opCode.JumpOp() == asm.Call:
504 if ins.Src != asm.PseudoCall {
505 return fmt.Errorf("call: %s: incorrect source register", name)
506 }
507
508 switch typ {
509 case elf.STT_NOTYPE, elf.STT_FUNC:
510 if bind != elf.STB_GLOBAL {
511 return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
512 }
513
514 case elf.STT_SECTION:
515 if bind != elf.STB_LOCAL {
516 return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
517 }
518
519
520
521
522
523 offset := int64(int32(ins.Constant)+1) * asm.InstructionSize
524 sym, ok := target.symbols[uint64(offset)]
525 if !ok {
526 return fmt.Errorf("call: no symbol at offset %d", offset)
527 }
528
529 name = sym.Name
530 ins.Constant = -1
531
532 default:
533 return fmt.Errorf("call: %s: invalid symbol type %s", name, typ)
534 }
535 case opCode.IsDWordLoad():
536 switch typ {
537 case elf.STT_FUNC:
538 if bind != elf.STB_GLOBAL {
539 return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
540 }
541
542 case elf.STT_SECTION:
543 if bind != elf.STB_LOCAL {
544 return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
545 }
546
547
548
549
550
551 default:
552 return fmt.Errorf("load: %s: invalid symbol type %s", name, typ)
553 }
554
555 sym, ok := target.symbols[uint64(ins.Constant)]
556 if !ok {
557 return fmt.Errorf("load: no symbol at offset %d", ins.Constant)
558 }
559
560 name = sym.Name
561 ins.Constant = -1
562 ins.Src = asm.PseudoFunc
563
564 default:
565 return fmt.Errorf("neither a call nor a load instruction: %v", ins)
566 }
567
568 case undefSection:
569 if bind != elf.STB_GLOBAL {
570 return fmt.Errorf("asm relocation: %s: unsupported binding: %s", name, bind)
571 }
572
573 if typ != elf.STT_NOTYPE {
574 return fmt.Errorf("asm relocation: %s: unsupported type %s", name, typ)
575 }
576
577
578
579 default:
580 return fmt.Errorf("relocation to %q: %w", target.Name, ErrNotSupported)
581 }
582
583 *ins = ins.WithReference(name)
584 return nil
585 }
586
587 func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
588 for _, sec := range ec.sections {
589 if sec.kind != mapSection {
590 continue
591 }
592
593 nSym := len(sec.symbols)
594 if nSym == 0 {
595 return fmt.Errorf("section %v: no symbols", sec.Name)
596 }
597
598 if sec.Size%uint64(nSym) != 0 {
599 return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name)
600 }
601
602 var (
603 r = bufio.NewReader(sec.Open())
604 size = sec.Size / uint64(nSym)
605 )
606 for i, offset := 0, uint64(0); i < nSym; i, offset = i+1, offset+size {
607 mapSym, ok := sec.symbols[offset]
608 if !ok {
609 return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
610 }
611
612 mapName := mapSym.Name
613 if maps[mapName] != nil {
614 return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym)
615 }
616
617 lr := io.LimitReader(r, int64(size))
618
619 spec := MapSpec{
620 Name: SanitizeName(mapName, -1),
621 }
622 switch {
623 case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
624 return fmt.Errorf("map %s: missing type", mapName)
625 case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
626 return fmt.Errorf("map %s: missing key size", mapName)
627 case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
628 return fmt.Errorf("map %s: missing value size", mapName)
629 case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
630 return fmt.Errorf("map %s: missing max entries", mapName)
631 case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
632 return fmt.Errorf("map %s: missing flags", mapName)
633 }
634
635 extra, err := io.ReadAll(lr)
636 if err != nil {
637 return fmt.Errorf("map %s: reading map tail: %w", mapName, err)
638 }
639 if len(extra) > 0 {
640 spec.Extra = bytes.NewReader(extra)
641 }
642
643 if err := spec.clampPerfEventArraySize(); err != nil {
644 return fmt.Errorf("map %s: %w", mapName, err)
645 }
646
647 maps[mapName] = &spec
648 }
649 }
650
651 return nil
652 }
653
654
655
656
657 func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
658 for _, sec := range ec.sections {
659 if sec.kind != btfMapSection {
660 continue
661 }
662
663 if ec.btf == nil {
664 return fmt.Errorf("missing BTF")
665 }
666
667
668 var ds *btf.Datasec
669 if err := ec.btf.TypeByName(sec.Name, &ds); err != nil {
670 return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err)
671 }
672
673
674
675
676 rs := sec.Open()
677
678 for _, vs := range ds.Vars {
679
680
681 v, ok := vs.Type.(*btf.Var)
682 if !ok {
683 return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type)
684 }
685 name := string(v.Name)
686
687
688
689
690
691 _, err := io.Copy(internal.DiscardZeroes{}, io.LimitReader(rs, int64(vs.Size)))
692 if err != nil {
693 return fmt.Errorf("section %v: map %s: initializing BTF map definitions: %w", sec.Name, name, internal.ErrNotSupported)
694 }
695
696 if maps[name] != nil {
697 return fmt.Errorf("section %v: map %s already exists", sec.Name, name)
698 }
699
700
701 mapStruct, ok := v.Type.(*btf.Struct)
702 if !ok {
703 return fmt.Errorf("expected struct, got %s", v.Type)
704 }
705
706 mapSpec, err := mapSpecFromBTF(sec, &vs, mapStruct, ec.btf, name, false)
707 if err != nil {
708 return fmt.Errorf("map %v: %w", name, err)
709 }
710
711 if err := mapSpec.clampPerfEventArraySize(); err != nil {
712 return fmt.Errorf("map %v: %w", name, err)
713 }
714
715 maps[name] = mapSpec
716 }
717
718
719
720 i, err := io.Copy(io.Discard, rs)
721 if err != nil {
722 return fmt.Errorf("section %v: unexpected error reading remainder of ELF section: %w", sec.Name, err)
723 }
724 if i > 0 {
725 return fmt.Errorf("section %v: %d unexpected remaining bytes in ELF section, invalid BTF?", sec.Name, i)
726 }
727 }
728
729 return nil
730 }
731
732
733
734
735 func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) {
736 var (
737 key, value btf.Type
738 keySize, valueSize uint32
739 mapType MapType
740 flags, maxEntries uint32
741 pinType PinType
742 innerMapSpec *MapSpec
743 contents []MapKV
744 err error
745 )
746
747 for i, member := range def.Members {
748 switch member.Name {
749 case "type":
750 mt, err := uintFromBTF(member.Type)
751 if err != nil {
752 return nil, fmt.Errorf("can't get type: %w", err)
753 }
754 mapType = MapType(mt)
755
756 case "map_flags":
757 flags, err = uintFromBTF(member.Type)
758 if err != nil {
759 return nil, fmt.Errorf("can't get BTF map flags: %w", err)
760 }
761
762 case "max_entries":
763 maxEntries, err = uintFromBTF(member.Type)
764 if err != nil {
765 return nil, fmt.Errorf("can't get BTF map max entries: %w", err)
766 }
767
768 case "key":
769 if keySize != 0 {
770 return nil, errors.New("both key and key_size given")
771 }
772
773 pk, ok := member.Type.(*btf.Pointer)
774 if !ok {
775 return nil, fmt.Errorf("key type is not a pointer: %T", member.Type)
776 }
777
778 key = pk.Target
779
780 size, err := btf.Sizeof(pk.Target)
781 if err != nil {
782 return nil, fmt.Errorf("can't get size of BTF key: %w", err)
783 }
784
785 keySize = uint32(size)
786
787 case "value":
788 if valueSize != 0 {
789 return nil, errors.New("both value and value_size given")
790 }
791
792 vk, ok := member.Type.(*btf.Pointer)
793 if !ok {
794 return nil, fmt.Errorf("value type is not a pointer: %T", member.Type)
795 }
796
797 value = vk.Target
798
799 size, err := btf.Sizeof(vk.Target)
800 if err != nil {
801 return nil, fmt.Errorf("can't get size of BTF value: %w", err)
802 }
803
804 valueSize = uint32(size)
805
806 case "key_size":
807
808
809 if key != nil || keySize != 0 {
810 return nil, errors.New("both key and key_size given")
811 }
812
813 keySize, err = uintFromBTF(member.Type)
814 if err != nil {
815 return nil, fmt.Errorf("can't get BTF key size: %w", err)
816 }
817
818 case "value_size":
819
820
821 if value != nil || valueSize != 0 {
822 return nil, errors.New("both value and value_size given")
823 }
824
825 valueSize, err = uintFromBTF(member.Type)
826 if err != nil {
827 return nil, fmt.Errorf("can't get BTF value size: %w", err)
828 }
829
830 case "pinning":
831 if inner {
832 return nil, errors.New("inner maps can't be pinned")
833 }
834
835 pinning, err := uintFromBTF(member.Type)
836 if err != nil {
837 return nil, fmt.Errorf("can't get pinning: %w", err)
838 }
839
840 pinType = PinType(pinning)
841
842 case "values":
843
844
845
846 if i != len(def.Members)-1 {
847 return nil, errors.New("'values' must be the last member in a BTF map definition")
848 }
849
850 if valueSize != 0 && valueSize != 4 {
851 return nil, errors.New("value_size must be 0 or 4")
852 }
853 valueSize = 4
854
855 valueType, err := resolveBTFArrayMacro(member.Type)
856 if err != nil {
857 return nil, fmt.Errorf("can't resolve type of member 'values': %w", err)
858 }
859
860 switch t := valueType.(type) {
861 case *btf.Struct:
862
863
864 if mapType != ArrayOfMaps && mapType != HashOfMaps {
865 return nil, errors.New("outer map needs to be an array or a hash of maps")
866 }
867 if inner {
868 return nil, fmt.Errorf("nested inner maps are not supported")
869 }
870
871
872
873
874
875
876
877
878 innerMapSpec, err = mapSpecFromBTF(es, vs, t, spec, name+"_inner", true)
879 if err != nil {
880 return nil, fmt.Errorf("can't parse BTF map definition of inner map: %w", err)
881 }
882
883 case *btf.FuncProto:
884
885
886 if mapType != ProgramArray {
887 return nil, errors.New("map needs to be a program array")
888 }
889
890 default:
891 return nil, fmt.Errorf("unsupported value type %q in 'values' field", t)
892 }
893
894 contents, err = resolveBTFValuesContents(es, vs, member)
895 if err != nil {
896 return nil, fmt.Errorf("resolving values contents: %w", err)
897 }
898
899 default:
900 return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name)
901 }
902 }
903
904 if key == nil {
905 key = &btf.Void{}
906 }
907 if value == nil {
908 value = &btf.Void{}
909 }
910
911 return &MapSpec{
912 Name: SanitizeName(name, -1),
913 Type: MapType(mapType),
914 KeySize: keySize,
915 ValueSize: valueSize,
916 MaxEntries: maxEntries,
917 Flags: flags,
918 Key: key,
919 Value: value,
920 BTF: spec,
921 Pinning: pinType,
922 InnerMap: innerMapSpec,
923 Contents: contents,
924 }, nil
925 }
926
927
928
929 func uintFromBTF(typ btf.Type) (uint32, error) {
930 ptr, ok := typ.(*btf.Pointer)
931 if !ok {
932 return 0, fmt.Errorf("not a pointer: %v", typ)
933 }
934
935 arr, ok := ptr.Target.(*btf.Array)
936 if !ok {
937 return 0, fmt.Errorf("not a pointer to array: %v", typ)
938 }
939
940 return arr.Nelems, nil
941 }
942
943
944
945
946 func resolveBTFArrayMacro(typ btf.Type) (btf.Type, error) {
947 arr, ok := typ.(*btf.Array)
948 if !ok {
949 return nil, fmt.Errorf("not an array: %v", typ)
950 }
951
952 ptr, ok := arr.Type.(*btf.Pointer)
953 if !ok {
954 return nil, fmt.Errorf("not an array of pointers: %v", typ)
955 }
956
957 return ptr.Target, nil
958 }
959
960
961
962
963 func resolveBTFValuesContents(es *elfSection, vs *btf.VarSecinfo, member btf.Member) ([]MapKV, error) {
964
965
966
967
968
969
970
971
972 start := member.Offset.Bytes() + vs.Offset
973
974
975
976 end := vs.Size + vs.Offset
977
978
979 align := uint32(es.SectionHeader.Addralign)
980
981
982 if (end-start)%align != 0 {
983 return nil, errors.New("unaligned static values section")
984 }
985 elems := (end - start) / align
986
987 if elems == 0 {
988 return nil, nil
989 }
990
991 contents := make([]MapKV, 0, elems)
992
993
994 for k, off := uint32(0), start; k < elems; k, off = k+1, off+align {
995 r, ok := es.relocations[uint64(off)]
996 if !ok {
997 continue
998 }
999
1000
1001
1002
1003
1004
1005 switch t := elf.ST_TYPE(r.Info); t {
1006 case elf.STT_FUNC:
1007 contents = append(contents, MapKV{uint32(k), r.Name})
1008 case elf.STT_OBJECT:
1009 contents = append(contents, MapKV{uint32(k), r.Name})
1010 default:
1011 return nil, fmt.Errorf("unknown relocation type %v", t)
1012 }
1013 }
1014
1015 return contents, nil
1016 }
1017
1018 func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
1019 for _, sec := range ec.sections {
1020 if sec.kind != dataSection {
1021 continue
1022 }
1023
1024 if sec.references == 0 {
1025
1026
1027 continue
1028 }
1029
1030 data, err := sec.Data()
1031 if err != nil {
1032 return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
1033 }
1034
1035 if uint64(len(data)) > math.MaxUint32 {
1036 return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
1037 }
1038
1039 mapSpec := &MapSpec{
1040 Name: SanitizeName(sec.Name, -1),
1041 Type: Array,
1042 KeySize: 4,
1043 ValueSize: uint32(len(data)),
1044 MaxEntries: 1,
1045 Contents: []MapKV{{uint32(0), data}},
1046 }
1047
1048
1049
1050 if ec.btf != nil {
1051 var ds *btf.Datasec
1052 if ec.btf.TypeByName(sec.Name, &ds) == nil {
1053
1054 mapSpec.BTF = ec.btf
1055 mapSpec.Key = &btf.Void{}
1056 mapSpec.Value = ds
1057 }
1058 }
1059
1060 switch n := sec.Name; {
1061 case strings.HasPrefix(n, ".rodata"):
1062 mapSpec.Flags = unix.BPF_F_RDONLY_PROG
1063 mapSpec.Freeze = true
1064 case n == ".bss":
1065
1066 mapSpec.Contents = nil
1067 }
1068
1069 maps[sec.Name] = mapSpec
1070 }
1071 return nil
1072 }
1073
1074 func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
1075 types := []struct {
1076 prefix string
1077 progType ProgramType
1078 attachType AttachType
1079 progFlags uint32
1080 }{
1081
1082
1083 {"socket", SocketFilter, AttachNone, 0},
1084 {"sk_reuseport/migrate", SkReuseport, AttachSkReuseportSelectOrMigrate, 0},
1085 {"sk_reuseport", SkReuseport, AttachSkReuseportSelect, 0},
1086 {"kprobe/", Kprobe, AttachNone, 0},
1087 {"uprobe/", Kprobe, AttachNone, 0},
1088 {"kretprobe/", Kprobe, AttachNone, 0},
1089 {"uretprobe/", Kprobe, AttachNone, 0},
1090 {"tc", SchedCLS, AttachNone, 0},
1091 {"classifier", SchedCLS, AttachNone, 0},
1092 {"action", SchedACT, AttachNone, 0},
1093 {"tracepoint/", TracePoint, AttachNone, 0},
1094 {"tp/", TracePoint, AttachNone, 0},
1095 {"raw_tracepoint/", RawTracepoint, AttachNone, 0},
1096 {"raw_tp/", RawTracepoint, AttachNone, 0},
1097 {"raw_tracepoint.w/", RawTracepointWritable, AttachNone, 0},
1098 {"raw_tp.w/", RawTracepointWritable, AttachNone, 0},
1099 {"tp_btf/", Tracing, AttachTraceRawTp, 0},
1100 {"fentry/", Tracing, AttachTraceFEntry, 0},
1101 {"fmod_ret/", Tracing, AttachModifyReturn, 0},
1102 {"fexit/", Tracing, AttachTraceFExit, 0},
1103 {"fentry.s/", Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
1104 {"fmod_ret.s/", Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
1105 {"fexit.s/", Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
1106 {"freplace/", Extension, AttachNone, 0},
1107 {"lsm/", LSM, AttachLSMMac, 0},
1108 {"lsm.s/", LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
1109 {"iter/", Tracing, AttachTraceIter, 0},
1110 {"syscall", Syscall, AttachNone, 0},
1111 {"xdp_devmap/", XDP, AttachXDPDevMap, 0},
1112 {"xdp_cpumap/", XDP, AttachXDPCPUMap, 0},
1113 {"xdp", XDP, AttachNone, 0},
1114 {"perf_event", PerfEvent, AttachNone, 0},
1115 {"lwt_in", LWTIn, AttachNone, 0},
1116 {"lwt_out", LWTOut, AttachNone, 0},
1117 {"lwt_xmit", LWTXmit, AttachNone, 0},
1118 {"lwt_seg6local", LWTSeg6Local, AttachNone, 0},
1119 {"cgroup_skb/ingress", CGroupSKB, AttachCGroupInetIngress, 0},
1120 {"cgroup_skb/egress", CGroupSKB, AttachCGroupInetEgress, 0},
1121 {"cgroup/skb", CGroupSKB, AttachNone, 0},
1122 {"cgroup/sock_create", CGroupSock, AttachCGroupInetSockCreate, 0},
1123 {"cgroup/sock_release", CGroupSock, AttachCgroupInetSockRelease, 0},
1124 {"cgroup/sock", CGroupSock, AttachCGroupInetSockCreate, 0},
1125 {"cgroup/post_bind4", CGroupSock, AttachCGroupInet4PostBind, 0},
1126 {"cgroup/post_bind6", CGroupSock, AttachCGroupInet6PostBind, 0},
1127 {"cgroup/dev", CGroupDevice, AttachCGroupDevice, 0},
1128 {"sockops", SockOps, AttachCGroupSockOps, 0},
1129 {"sk_skb/stream_parser", SkSKB, AttachSkSKBStreamParser, 0},
1130 {"sk_skb/stream_verdict", SkSKB, AttachSkSKBStreamVerdict, 0},
1131 {"sk_skb", SkSKB, AttachNone, 0},
1132 {"sk_msg", SkMsg, AttachSkMsgVerdict, 0},
1133 {"lirc_mode2", LircMode2, AttachLircMode2, 0},
1134 {"flow_dissector", FlowDissector, AttachFlowDissector, 0},
1135 {"cgroup/bind4", CGroupSockAddr, AttachCGroupInet4Bind, 0},
1136 {"cgroup/bind6", CGroupSockAddr, AttachCGroupInet6Bind, 0},
1137 {"cgroup/connect4", CGroupSockAddr, AttachCGroupInet4Connect, 0},
1138 {"cgroup/connect6", CGroupSockAddr, AttachCGroupInet6Connect, 0},
1139 {"cgroup/sendmsg4", CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
1140 {"cgroup/sendmsg6", CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
1141 {"cgroup/recvmsg4", CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
1142 {"cgroup/recvmsg6", CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
1143 {"cgroup/getpeername4", CGroupSockAddr, AttachCgroupInet4GetPeername, 0},
1144 {"cgroup/getpeername6", CGroupSockAddr, AttachCgroupInet6GetPeername, 0},
1145 {"cgroup/getsockname4", CGroupSockAddr, AttachCgroupInet4GetSockname, 0},
1146 {"cgroup/getsockname6", CGroupSockAddr, AttachCgroupInet6GetSockname, 0},
1147 {"cgroup/sysctl", CGroupSysctl, AttachCGroupSysctl, 0},
1148 {"cgroup/getsockopt", CGroupSockopt, AttachCGroupGetsockopt, 0},
1149 {"cgroup/setsockopt", CGroupSockopt, AttachCGroupSetsockopt, 0},
1150 {"struct_ops+", StructOps, AttachNone, 0},
1151 {"sk_lookup/", SkLookup, AttachSkLookup, 0},
1152
1153 {"seccomp", SocketFilter, AttachNone, 0},
1154 }
1155
1156 for _, t := range types {
1157 if !strings.HasPrefix(sectionName, t.prefix) {
1158 continue
1159 }
1160
1161 if !strings.HasSuffix(t.prefix, "/") {
1162 return t.progType, t.attachType, t.progFlags, ""
1163 }
1164
1165 return t.progType, t.attachType, t.progFlags, sectionName[len(t.prefix):]
1166 }
1167
1168 return UnspecifiedProgram, AttachNone, 0, ""
1169 }
1170
1171 func (ec *elfCode) loadSectionRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) {
1172 rels := make(map[uint64]elf.Symbol)
1173
1174 if sec.Entsize < 16 {
1175 return nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
1176 }
1177
1178 r := bufio.NewReader(sec.Open())
1179 for off := uint64(0); off < sec.Size; off += sec.Entsize {
1180 ent := io.LimitReader(r, int64(sec.Entsize))
1181
1182 var rel elf.Rel64
1183 if binary.Read(ent, ec.ByteOrder, &rel) != nil {
1184 return nil, fmt.Errorf("can't parse relocation at offset %v", off)
1185 }
1186
1187 symNo := int(elf.R_SYM64(rel.Info) - 1)
1188 if symNo >= len(symbols) {
1189 return nil, fmt.Errorf("offset %d: symbol %d doesn't exist", off, symNo)
1190 }
1191
1192 symbol := symbols[symNo]
1193 rels[rel.Off] = symbol
1194 }
1195
1196 return rels, nil
1197 }
1198
View as plain text