1
0
mirror of https://github.com/golang/go synced 2024-09-29 07:24:32 -06:00

debug/macho: use saferio to allocate Load and Symbol slices

Avoid allocating large amounts of memory for corrupt input.

No test case because the problem can only happen for invalid data.
Let the fuzzer find cases like this.

Change-Id: I2d1745200611f0af06ca58adcc3e2309ad6742d8
Reviewed-on: https://go-review.googlesource.com/c/go/+/425882
Run-TryBot: Dan Kortschak <dan@kortschak.io>
Auto-Submit: Dan Kortschak <dan@kortschak.io>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Dan Kortschak 2022-08-27 12:42:26 +09:30 committed by Gopher Robot
parent f3a1f9220a
commit 36d1f23661

View File

@ -253,9 +253,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
if _, err := r.ReadAt(dat, offset); err != nil {
return nil, err
}
f.Loads = make([]Load, f.Ncmd)
c := saferio.SliceCap([]Load{}, uint64(f.Ncmd))
if c < 0 {
return nil, &FormatError{offset, "too many load commands", nil}
}
f.Loads = make([]Load, 0, c)
bo := f.ByteOrder
for i := range f.Loads {
for i := uint32(0); i < f.Ncmd; i++ {
// Each load command begins with uint32 command and length.
if len(dat) < 8 {
return nil, &FormatError{offset, "command block too small", nil}
@ -270,7 +274,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
var s *Segment
switch cmd {
default:
f.Loads[i] = LoadBytes(cmddat)
f.Loads = append(f.Loads, LoadBytes(cmddat))
case LoadCmdRpath:
var hdr RpathCmd
@ -284,7 +288,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
l.Path = cstring(cmddat[hdr.Path:])
l.LoadBytes = LoadBytes(cmddat)
f.Loads[i] = l
f.Loads = append(f.Loads, l)
case LoadCmdDylib:
var hdr DylibCmd
@ -301,7 +305,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
l.CurrentVersion = hdr.CurrentVersion
l.CompatVersion = hdr.CompatVersion
l.LoadBytes = LoadBytes(cmddat)
f.Loads[i] = l
f.Loads = append(f.Loads, l)
case LoadCmdSymtab:
var hdr SymtabCmd
@ -319,15 +323,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
} else {
symsz = 12
}
symdat := make([]byte, int(hdr.Nsyms)*symsz)
if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
symdat, err := saferio.ReadDataAt(r, uint64(hdr.Nsyms)*uint64(symsz), int64(hdr.Symoff))
if err != nil {
return nil, err
}
st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
if err != nil {
return nil, err
}
f.Loads[i] = st
f.Loads = append(f.Loads, st)
f.Symtab = st
case LoadCmdDysymtab:
@ -357,7 +361,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
st.LoadBytes = LoadBytes(cmddat)
st.DysymtabCmd = hdr
st.IndirectSyms = x
f.Loads[i] = st
f.Loads = append(f.Loads, st)
f.Dysymtab = st
case LoadCmdSegment:
@ -379,7 +383,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
s.Prot = seg32.Prot
s.Nsect = seg32.Nsect
s.Flag = seg32.Flag
f.Loads[i] = s
f.Loads = append(f.Loads, s)
for i := 0; i < int(s.Nsect); i++ {
var sh32 Section32
if err := binary.Read(b, bo, &sh32); err != nil {
@ -419,7 +423,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
s.Prot = seg64.Prot
s.Nsect = seg64.Nsect
s.Flag = seg64.Flag
f.Loads[i] = s
f.Loads = append(f.Loads, s)
for i := 0; i < int(s.Nsect); i++ {
var sh64 Section64
if err := binary.Read(b, bo, &sh64); err != nil {
@ -441,6 +445,12 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
}
if s != nil {
if int64(s.Offset) < 0 {
return nil, &FormatError{offset, "invalid section offset", s.Offset}
}
if int64(s.Filesz) < 0 {
return nil, &FormatError{offset, "invalid section file size", s.Filesz}
}
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
s.ReaderAt = s.sr
}
@ -450,9 +460,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
c := saferio.SliceCap([]Symbol{}, uint64(hdr.Nsyms))
if c < 0 {
return nil, &FormatError{offset, "too many symbols", nil}
}
symtab := make([]Symbol, 0, c)
b := bytes.NewReader(symdat)
for i := range symtab {
for i := 0; i < int(hdr.Nsyms); i++ {
var n Nlist64
if f.Magic == Magic64 {
if err := binary.Read(b, bo, &n); err != nil {
@ -469,7 +483,6 @@ func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset
n.Desc = n32.Desc
n.Value = uint64(n32.Value)
}
sym := &symtab[i]
if n.Name >= uint32(len(strtab)) {
return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
}
@ -478,11 +491,13 @@ func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset
if strings.Contains(name, ".") && name[0] == '_' {
name = name[1:]
}
sym.Name = name
sym.Type = n.Type
sym.Sect = n.Sect
sym.Desc = n.Desc
sym.Value = n.Value
symtab = append(symtab, Symbol{
Name: name,
Type: n.Type,
Sect: n.Sect,
Desc: n.Desc,
Value: n.Value,
})
}
st := new(Symtab)
st.LoadBytes = LoadBytes(cmddat)
@ -501,8 +516,8 @@ func (f *File) pushSection(sh *Section, r io.ReaderAt) error {
sh.ReaderAt = sh.sr
if sh.Nreloc > 0 {
reldat := make([]byte, int(sh.Nreloc)*8)
if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil {
reldat, err := saferio.ReadDataAt(r, uint64(sh.Nreloc)*8, int64(sh.Reloff))
if err != nil {
return err
}
b := bytes.NewReader(reldat)