Skip to content

Commit

Permalink
elf_reader: only read data from PROGBITS sections, ignore NOBITS
Browse files Browse the repository at this point in the history
'Virtual' NOBITS sections like .bss always share an offset with another
ELF section, but reading from them is expected to yield only NUL bytes.

Prior to Go 1.18, opening a NOBITS section would yield a reader into
the overlapping 'real' section, dutifully returning its non-NUL bytes
and potentially reading past the end of the underlying file reader if
the size of the NOBITS section was large enough. This was addressed in
CL#375216.

As both an optimization (in case of large .bss sections) and a workaround
for this bug in Go versions 1.17 and earlier, only read data from PROGBITS
sections, which all known LLVM versions use correctly. Return an error if
a data section is not PROGBITS or NOBITS.

Signed-off-by: Timo Beckers <timo@isovalent.com>
  • Loading branch information
ti-mo authored and lmb committed Jul 20, 2022
1 parent 1db0160 commit 69c5729
Showing 1 changed file with 23 additions and 16 deletions.
39 changes: 23 additions & 16 deletions elf_reader.go
Expand Up @@ -1027,22 +1027,33 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
continue
}

data, err := sec.Data()
if err != nil {
return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
}

if uint64(len(data)) > math.MaxUint32 {
return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
}

mapSpec := &MapSpec{
Name: SanitizeName(sec.Name, -1),
Type: Array,
KeySize: 4,
ValueSize: uint32(len(data)),
ValueSize: uint32(sec.Size),
MaxEntries: 1,
Contents: []MapKV{{uint32(0), data}},
}

switch sec.Type {
// Only open the section if we know there's actual data to be read.
case elf.SHT_PROGBITS:
data, err := sec.Data()
if err != nil {
return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
}

if uint64(len(data)) > math.MaxUint32 {
return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
}
mapSpec.Contents = []MapKV{{uint32(0), data}}

case elf.SHT_NOBITS:
// NOBITS sections like .bss contain only zeroes, and since data sections
// are Arrays, the kernel already preallocates them. Skip reading zeroes
// from the ELF.
default:
return fmt.Errorf("data section %s: unknown section type %s", sec.Name, sec.Type)
}

// It is possible for a data section to exist without a corresponding BTF Datasec
Expand All @@ -1057,13 +1068,9 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
}
}

switch n := sec.Name; {
case strings.HasPrefix(n, ".rodata"):
if strings.HasPrefix(sec.Name, ".rodata") {
mapSpec.Flags = unix.BPF_F_RDONLY_PROG
mapSpec.Freeze = true
case n == ".bss":
// The kernel already zero-initializes the map
mapSpec.Contents = nil
}

maps[sec.Name] = mapSpec
Expand Down

0 comments on commit 69c5729

Please sign in to comment.