aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorDan Kortschak <dan@kortschak.io>2022-08-27 12:42:26 +0930
committerGopher Robot <gobot@golang.org>2022-08-29 20:08:15 +0000
commit36d1f236610a436bcbceca11e040a65593f1f253 (patch)
tree2d53673fe5c5b3e68ebe903c112cda921d8d9ce7 /src/debug
parentf3a1f9220a8a5265842f5cb877c4dc6d08f75c68 (diff)
downloadgo-36d1f236610a436bcbceca11e040a65593f1f253.tar.xz
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>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/macho/file.go57
1 files changed, 36 insertions, 21 deletions
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index e6b170a7cd..e35b4df508 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -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)