diff --git a/btf/ext_info.go b/btf/ext_info.go index 7cd1dc51c..2e2aa629f 100644 --- a/btf/ext_info.go +++ b/btf/ext_info.go @@ -642,9 +642,15 @@ func parseLineInfoRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, r return nil, fmt.Errorf("expected LineInfo record size %d, but BTF blob contains %d", exp, got) } - out := make([]bpfLineInfo, recordNum) - if err := binary.Read(r, bo, out); err != nil { - return nil, fmt.Errorf("can't read line info: %v", err) + out := make([]bpfLineInfo, 0) + chunk := make([]bpfLineInfo, min(1024, recordNum)) + for remaining := recordNum; remaining > 0; { + n := min(uint32(1024), remaining) + if err := binary.Read(r, bo, chunk[:n]); err != nil { + return nil, fmt.Errorf("can't read line info: %v", err) + } + out = append(out, chunk[:n]...) + remaining -= n } if offsetInBytes { diff --git a/btf/ext_info_test.go b/btf/ext_info_test.go index e791b9bb2..6c0783dc0 100644 --- a/btf/ext_info_test.go +++ b/btf/ext_info_test.go @@ -48,8 +48,8 @@ func TestParseLineInfoRecordsAllocations(t *testing.T) { parseLineInfoRecords(bytes.NewReader(buf), internal.NativeEndian, size, count, true) }) - // 7 is the number of allocations on go 1.22 + // 9 is the number of allocations on go 1.26 // what we want to test is that we are not allocating // once per record - qt.Assert(t, qt.IsTrue(allocs <= 7)) + qt.Assert(t, qt.IsTrue(allocs <= 9)) } diff --git a/elf_reader.go b/elf_reader.go index f8f7824e9..e2f264912 100644 --- a/elf_reader.go +++ b/elf_reader.go @@ -382,6 +382,10 @@ func (ec *elfCode) loadProgramSections() (map[string]*ProgramSpec, error) { return nil, fmt.Errorf("section %v: missing symbols", sec.Name) } + if sec.ReaderAt == nil { + return nil, fmt.Errorf("compressed program section is not supported") + } + funcs, err := ec.loadFunctions(sec) if err != nil { return nil, fmt.Errorf("section %v: %w", sec.Name, err) @@ -452,6 +456,13 @@ func (ec *elfCode) loadFunctions(sec *elfSection) (map[string]asm.Instructions, return nil, fmt.Errorf("duplicate symbol %s in section %s", sym.Name, sec.Name) } + if sym.Value > math.MaxUint32 || sym.Size > math.MaxUint32 { + return nil, fmt.Errorf("symbol %s: offset or size exceeds 32 bits in section %s", sym.Name, sec.Name) + } + if sym.Value+sym.Size > sec.Size { + return nil, fmt.Errorf("symbol %s: size goes out of bounds of section %s", sym.Name, sec.Name) + } + // Decode the symbol's instruction stream, limited to its size. sr := internal.NewBufferedSectionReader(sec, int64(sym.Value), int64(sym.Size)) insns := make(asm.Instructions, 0, sym.Size/asm.InstructionSize) @@ -803,6 +814,10 @@ func (ec *elfCode) loadMaps() error { return fmt.Errorf("section %v: no symbols", sec.Name) } + if sec.ReaderAt == nil { + return fmt.Errorf("compressed map section is not supported") + } + vars, err := ec.sectionVars(ec.btf, sec.Name) if err != nil { return fmt.Errorf("section %v: loading map variable BTF: %w", sec.Name, err) @@ -814,6 +829,13 @@ func (ec *elfCode) loadMaps() error { return fmt.Errorf("duplicate symbol %s in section %s", name, sec.Name) } + if sym.Value > math.MaxUint32 || sym.Size > math.MaxUint32 { + return fmt.Errorf("symbol %s: offset or size exceeds 32 bits in section %s", sym.Name, sec.Name) + } + if sym.Value+sym.Size > sec.Size { + return fmt.Errorf("symbol %s: size goes out of bounds of section %s", name, sec.Name) + } + sr := internal.NewBufferedSectionReader(sec, int64(sym.Value), int64(sym.Size)) spec := MapSpec{ @@ -889,6 +911,10 @@ func (ec *elfCode) loadBTFMaps() error { return fmt.Errorf("missing BTF") } + if sec.ReaderAt == nil { + return fmt.Errorf("compressed BTF map section is not supported") + } + vars, err := ec.sectionVars(ec.btf, sec.Name) if err != nil { return fmt.Errorf("section %v: loading map variable BTF: %w", sec.Name, err) @@ -912,6 +938,13 @@ func (ec *elfCode) loadBTFMaps() error { return fmt.Errorf("section %v: missing symbol for map %s", sec.Name, name) } + if sym.Value > math.MaxUint32 || sym.Size > math.MaxUint32 { + return fmt.Errorf("symbol %s: offset or size exceeds 32 bits in section %s", sym.Name, sec.Name) + } + if sym.Value+sym.Size > sec.Size { + return fmt.Errorf("section %v: symbol %s: size goes out of bounds of section", sec.Name, name) + } + sr := internal.NewBufferedSectionReader(sec, int64(sym.Value), int64(sym.Size)) // The BTF metadata for each Var contains the full length of the map @@ -1245,6 +1278,10 @@ func resolveBTFValuesContents(es *elfSection, sym elf.Symbol, member btf.Member) return nil, fmt.Errorf("member offset %d exceeds symbol size %d", member.Offset.Bytes(), sym.Size) } + if es.Addralign == 0 { + return nil, fmt.Errorf("section has no address alignment, can't resolve .values contents") + } + for i, sym := range valuesRelocations(es, sym, member) { // Emit a value stub based on the type of relocation to be replaced by a // real fd later in the pipeline before populating the Map. @@ -1354,6 +1391,10 @@ func (ec *elfCode) loadDataSections() error { return fmt.Errorf("data section %s: variable %s offset %d exceeds maximum", sec.Name, sym.Name, off) } + if sym.Size > math.MaxUint32 { + return fmt.Errorf("data section %s: variable %s size %d exceeds maximum", sec.Name, sym.Name, sym.Size) + } + ec.vars[sym.Name] = &VariableSpec{ SectionName: sec.Name, Name: sym.Name, @@ -1487,6 +1528,10 @@ func (ec *elfCode) associateStructOpsRelocs(progs map[string]*ProgramSpec) error return fmt.Errorf("failed to read section data: %w", err) } + if ec.btf == nil { + return fmt.Errorf("struct_ops section %s: missing BTF", sec.Name) + } + // Resolve the BTF datasec describing variables in this section. var ds *btf.Datasec if err := ec.btf.TypeByName(sec.Name, &ds); err != nil {