Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07907127 authored by Colin Cross's avatar Colin Cross Committed by Gerrit Code Review
Browse files

Merge "symbols_map: don't error on bad elf files"

parents 54f45e5c 6285c65e
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -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 {
+68 −0
Original line number Diff line number Diff line
@@ -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()
}