Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions src/debug/elf/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ func (e *FormatError) Error() string {
return msg
}

// A [*FormatError] is a target error if the base message matches the target.Error string
func (e *FormatError) Is(target error) bool { return e.msg == target.Error() }

// Open opens the named file using [os.Open] and prepares it for use as an ELF binary.
func Open(name string) (*File, error) {
f, err := os.Open(name)
Expand Down Expand Up @@ -289,7 +292,11 @@ func NewFile(r io.ReaderAt) (*File, error) {
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read and decode ELF identifier
var ident [16]uint8
if _, err := r.ReadAt(ident[0:], 0); err != nil {
n, err := r.ReadAt(ident[0:], 0)
if err != nil {
if err == io.EOF {
err = &FormatError{int64(n), io.ErrUnexpectedEOF.Error(), ident[0:n]}
}
return nil, err
}
if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
Expand Down Expand Up @@ -335,7 +342,11 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS32:
var hdr Header32
data := make([]byte, unsafe.Sizeof(hdr))
if _, err := sr.ReadAt(data, 0); err != nil {
n, err := sr.ReadAt(data, 0)
if err != nil {
if err == io.EOF && n < int(unsafe.Sizeof(hdr)) {
err = &FormatError{int64(n), io.ErrUnexpectedEOF.Error(), data}
}
return nil, err
}
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
Expand All @@ -354,7 +365,11 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS64:
var hdr Header64
data := make([]byte, unsafe.Sizeof(hdr))
if _, err := sr.ReadAt(data, 0); err != nil {
n, err := sr.ReadAt(data, 0)
if err != nil {
if err == io.EOF && n < int(unsafe.Sizeof(hdr)) {
err = &FormatError{int64(n), io.ErrUnexpectedEOF.Error(), data}
}
return nil, err
}
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
Expand Down Expand Up @@ -404,6 +419,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
f.Progs = make([]*Prog, phnum)
phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff)
if err != nil {
if err == io.EOF {
err = &FormatError{phoff + int64(len(phdata)), io.ErrUnexpectedEOF.Error(), phdata}
}
return nil, err
}
for i := 0; i < phnum; i++ {
Expand Down Expand Up @@ -457,6 +475,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS32:
sh := new(Section32)
if err := binary.Read(sr, bo, sh); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = &FormatError{shoff, io.ErrUnexpectedEOF.Error(), nil}
}
return nil, err
}
shnum = int(sh.Size)
Expand All @@ -465,6 +486,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS64:
sh := new(Section64)
if err := binary.Read(sr, bo, sh); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = &FormatError{shoff, io.ErrUnexpectedEOF.Error(), nil}
}
return nil, err
}
shnum = int(sh.Size)
Expand Down Expand Up @@ -508,6 +532,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
names := make([]uint32, 0, c)
shdata, err := saferio.ReadDataAt(sr, uint64(shnum)*uint64(shentsize), shoff)
if err != nil {
if err == io.EOF {
err = &FormatError{shoff + int64(len(shdata)), io.ErrUnexpectedEOF.Error(), shdata}
}
return nil, err
}
for i := 0; i < shnum; i++ {
Expand Down Expand Up @@ -560,7 +587,11 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS32:
var ch Chdr32
chdata := make([]byte, unsafe.Sizeof(ch))
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
n, err := s.sr.ReadAt(chdata, 0)
if err != nil {
if err == io.EOF && n < int(unsafe.Sizeof(ch)) {
err = &FormatError{int64(n), io.ErrUnexpectedEOF.Error(), chdata}
}
return nil, err
}
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
Expand All @@ -570,7 +601,11 @@ func NewFile(r io.ReaderAt) (*File, error) {
case ELFCLASS64:
var ch Chdr64
chdata := make([]byte, unsafe.Sizeof(ch))
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
n, err := s.sr.ReadAt(chdata, 0)
if err != nil {
if err == io.EOF && n < int(unsafe.Sizeof(ch)) {
err = &FormatError{int64(n), io.ErrUnexpectedEOF.Error(), chdata}
}
return nil, err
}
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
Expand Down Expand Up @@ -599,6 +634,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
shstrtab, err := shstr.Data()
if err != nil {
if err == io.EOF {
err = &FormatError{shoff + int64(shstrndx*shentsize) + int64(len(shstrtab)), io.ErrUnexpectedEOF.Error(), shstrtab}
}
return nil, err
}
for i, s := range f.Sections {
Expand Down
15 changes: 15 additions & 0 deletions src/debug/elf/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,21 @@ func TestIssue59208(t *testing.T) {
}
}

// Issue #76338
func TestUnexpectedEOF(t *testing.T) {
const testdata = "testdata/empty"
wantedVal := io.ErrUnexpectedEOF
var wantedType *FormatError

_, err := Open(testdata)
if !errors.As(err, &wantedType) {
t.Errorf("did not receive a FormatError, instead: %#v", err)
}
if !errors.Is(err, wantedVal) {
t.Errorf("did not get an io.ErrUnexpectedEOF, instead: %#v", err)
}
}

func BenchmarkSymbols64(b *testing.B) {
const testdata = "testdata/gcc-amd64-linux-exec"
f, err := Open(testdata)
Expand Down
Empty file added src/debug/elf/testdata/empty
Empty file.