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)