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:
parent
f3a1f9220a
commit
36d1f23661
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user