]> Cypherpunks.ru repositories - gostls13.git/commitdiff
debug/macho: use saferio to allocate Load and Symbol slices
authorDan Kortschak <dan@kortschak.io>
Sat, 27 Aug 2022 03:12:26 +0000 (12:42 +0930)
committerGopher Robot <gobot@golang.org>
Mon, 29 Aug 2022 20:08:15 +0000 (20:08 +0000)
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>

src/debug/macho/file.go

index e6b170a7cdb78f8483315dcc94ea1da49608fa96..e35b4df5089ffc586e1659224280ba719f4336fc 100644 (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)