From 0393df6446f405dfe1afaf7eadc47e75324bcc49 Mon Sep 17 00:00:00 2001 From: Timo Beckers Date: Wed, 20 Jul 2022 14:50:25 +0200 Subject: [PATCH] elf_reader: only read data from PROGBITS sections, ignore NOBITS '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 --- elf_reader.go | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/elf_reader.go b/elf_reader.go index df278895c..4d8d4bed9 100644 --- a/elf_reader.go +++ b/elf_reader.go @@ -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 @@ -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