1
0
mirror of https://github.com/golang/go synced 2024-11-22 03:34:40 -07:00

debug/buildinfo: stop searchMagic search at EOF

An invalid executable may claim to have a data section bigger than the
executable, causing readData in searchMagic to hit EOF. Since readData
suppresses all EOF errors, searchData would keep attempting to search
through a potentially huge "section" despite readData continuously
failing.

Fix by suppressing EOF only on partial read. If nothing is read, allow
EOF. Note that most of the admittedly tedious EOF handling in this
package is around ensuring we return errNotGoExe in most cases.

This was discovered by the new fuzz test. This fuzz test was inspired
by #69066, though it has not found that specific bug.

Change-Id: Icf413e996cecc583c084c9e44249b9294c3d8f10
Reviewed-on: https://go-review.googlesource.com/c/go/+/608637
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Michael Pratt 2024-08-27 11:13:46 -04:00
parent aa2e8b9ce2
commit 61e00ae134
3 changed files with 41 additions and 10 deletions

View File

@ -179,9 +179,14 @@ func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) {
// Read in the full header first.
header, err := readData(x, addr, buildInfoHeaderSize)
if err != nil {
if err == io.EOF {
return "", "", errNotGoExe
} else if err != nil {
return "", "", err
}
if len(header) < buildInfoHeaderSize {
return "", "", errNotGoExe
}
const (
ptrSizeOffset = 14
@ -283,7 +288,9 @@ func decodeString(x exe, addr uint64) (string, uint64, error) {
// addr. So we don't need to check that size doesn't overflow the
// section.
b, err := readData(x, addr, binary.MaxVarintLen64)
if err != nil {
if err == io.EOF {
return "", 0, errNotGoExe
} else if err != nil {
return "", 0, err
}
@ -294,11 +301,12 @@ func decodeString(x exe, addr uint64) (string, uint64, error) {
addr += uint64(n)
b, err = readData(x, addr, length)
if err != nil {
if err == io.ErrUnexpectedEOF {
// Length too large to allocate. Clearly bogus value.
return "", 0, errNotGoExe
}
if err == io.EOF {
return "", 0, errNotGoExe
} else if err == io.ErrUnexpectedEOF {
// Length too large to allocate. Clearly bogus value.
return "", 0, errNotGoExe
} else if err != nil {
return "", 0, err
}
if uint64(len(b)) < length {
@ -364,7 +372,10 @@ func searchMagic(x exe, start, size uint64) (uint64, error) {
}
n, err := readDataInto(x, start, buf)
if err != nil {
if err == io.EOF {
// EOF before finding the magic; must not be a Go executable.
return 0, errNotGoExe
} else if err != nil {
return 0, err
}
@ -407,7 +418,7 @@ func readData(x exe, addr, size uint64) ([]byte, error) {
}
b, err := saferio.ReadDataAt(r, size, 0)
if err == io.EOF {
if len(b) > 0 && err == io.EOF {
err = nil
}
return b, err
@ -420,7 +431,7 @@ func readDataInto(x exe, addr uint64, b []byte) (int, error) {
}
n, err := r.ReadAt(b, 0)
if err == io.EOF {
if n > 0 && err == io.EOF {
err = nil
}
return n, err

View File

@ -408,3 +408,21 @@ func TestIssue54968(t *testing.T) {
})
}
}
func FuzzRead(f *testing.F) {
go117, err := os.ReadFile("testdata/go117")
if err != nil {
f.Errorf("Error reading go117: %v", err)
}
f.Add(go117)
notgo, err := os.ReadFile("testdata/notgo")
if err != nil {
f.Errorf("Error reading notgo: %v", err)
}
f.Add(notgo)
f.Fuzz(func(t *testing.T, in []byte) {
buildinfo.Read(bytes.NewReader(in))
})
}

File diff suppressed because one or more lines are too long