symbols_map: don't error on bad elf files
There are cc_binary_prebuilt modules in the tree that are shell scripts, and attempting to extract an elf ID from them results in an error. Ignore too short files and files missing the elf magic header the same way we do for elf files without an elf ID. Bug: 218888599 Test: Test_elfIdentifierFromReaderAt_BadElfFile Change-Id: If7117925ca2371a8ee61ba3616372f6e9b0fab0e
This commit is contained in:
@@ -18,8 +18,10 @@ import (
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
const gnuBuildID = "GNU\x00"
|
||||
@@ -27,12 +29,33 @@ const gnuBuildID = "GNU\x00"
|
||||
// elfIdentifier extracts the elf build ID from an elf file. If allowMissing is true it returns
|
||||
// an empty identifier if the file exists but the build ID note does not.
|
||||
func elfIdentifier(filename string, allowMissing bool) (string, error) {
|
||||
f, err := elf.Open(filename)
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to open %s: %w", filename, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return elfIdentifierFromReaderAt(f, filename, allowMissing)
|
||||
}
|
||||
|
||||
// elfIdentifier extracts the elf build ID from a ReaderAt. If allowMissing is true it returns
|
||||
// an empty identifier if the file exists but the build ID note does not.
|
||||
func elfIdentifierFromReaderAt(r io.ReaderAt, filename string, allowMissing bool) (string, error) {
|
||||
f, err := elf.NewFile(r)
|
||||
if err != nil {
|
||||
if allowMissing {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return "", nil
|
||||
}
|
||||
if _, ok := err.(*elf.FormatError); ok {
|
||||
// The file was not an elf file.
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to parse elf file %s: %w", filename, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buildIDNote := f.Section(".note.gnu.build-id")
|
||||
if buildIDNote == nil {
|
||||
if allowMissing {
|
||||
|
@@ -16,11 +16,46 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_elfIdentifierFromReaderAt_BadElfFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
contents string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
contents: "",
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
contents: "#!/bin/bash\necho foobar",
|
||||
},
|
||||
{
|
||||
name: "empty elf",
|
||||
contents: emptyElfFile(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
buf := bytes.NewReader([]byte(tt.contents))
|
||||
_, err := elfIdentifierFromReaderAt(buf, "<>", false)
|
||||
if err == nil {
|
||||
t.Errorf("expected error reading bad elf file without allowMissing")
|
||||
}
|
||||
_, err = elfIdentifierFromReaderAt(buf, "<>", true)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error reading bad elf file with allowMissing, got %q", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_readNote(t *testing.T) {
|
||||
note := []byte{
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
@@ -43,3 +78,36 @@ func Test_readNote(t *testing.T) {
|
||||
t.Errorf("incorrect return, want %#v got %#v", expectedDescs, descs)
|
||||
}
|
||||
}
|
||||
|
||||
// emptyElfFile returns an elf file header with no program headers or sections.
|
||||
func emptyElfFile() string {
|
||||
ident := [elf.EI_NIDENT]byte{}
|
||||
identBuf := bytes.NewBuffer(ident[0:0:elf.EI_NIDENT])
|
||||
binary.Write(identBuf, binary.LittleEndian, []byte("\x7fELF"))
|
||||
binary.Write(identBuf, binary.LittleEndian, elf.ELFCLASS64)
|
||||
binary.Write(identBuf, binary.LittleEndian, elf.ELFDATA2LSB)
|
||||
binary.Write(identBuf, binary.LittleEndian, elf.EV_CURRENT)
|
||||
binary.Write(identBuf, binary.LittleEndian, elf.ELFOSABI_LINUX)
|
||||
binary.Write(identBuf, binary.LittleEndian, make([]byte, 8))
|
||||
|
||||
header := elf.Header64{
|
||||
Ident: ident,
|
||||
Type: uint16(elf.ET_EXEC),
|
||||
Machine: uint16(elf.EM_X86_64),
|
||||
Version: uint32(elf.EV_CURRENT),
|
||||
Entry: 0,
|
||||
Phoff: uint64(binary.Size(elf.Header64{})),
|
||||
Shoff: uint64(binary.Size(elf.Header64{})),
|
||||
Flags: 0,
|
||||
Ehsize: uint16(binary.Size(elf.Header64{})),
|
||||
Phentsize: 0x38,
|
||||
Phnum: 0,
|
||||
Shentsize: 0x40,
|
||||
Shnum: 0,
|
||||
Shstrndx: 0,
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.LittleEndian, header)
|
||||
return buf.String()
|
||||
}
|
||||
|
Reference in New Issue
Block a user