]> Cypherpunks repositories - gostls13.git/commitdiff
debug/elf: prevent offset overflow
authorJes Cok <xigua67damn@gmail.com>
Thu, 25 Sep 2025 04:41:12 +0000 (04:41 +0000)
committerGopher Robot <gobot@golang.org>
Mon, 29 Sep 2025 04:38:57 +0000 (21:38 -0700)
When applying relocations, a malformed ELF file can provide an offset
that, when added to the relocation size, overflows. This wrapped-around
value could then incorrectly pass the bounds check, leading to a panic
when the slice is accessed with the original large offset.

This change eliminates the manual bounds and overflow checks
and writes a relocation to slice by calling putUint.

The putUint helper function centralizes the logic for validating slice
access, correctly handling both out-of-bounds and integer overflow conditions.
This simplifies the relocation code and improves robustness when parsing
malformed ELF files.

Fixes #75516

Change-Id: I00d806bf5501a9bf70200585ba4fd0475d7b2ddc
GitHub-Last-Rev: 49144311d31fecc63cb81b6c31bf9a206acb0596
GitHub-Pull-Request: golang/go#75522
Reviewed-on: https://go-review.googlesource.com/c/go/+/705075
Reviewed-by: Florian Lehner <lehner.florian86@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Commit-Queue: Ian Lance Taylor <iant@golang.org>

src/debug/elf/file.go

index 50452b5bef45f4ef019321af18498f6b3cec7dc7..1d56a06c3fb221433e4fd25292da64a338646174 100644 (file)
@@ -25,6 +25,7 @@ import (
        "internal/saferio"
        "internal/zstd"
        "io"
+       "math"
        "os"
        "strings"
        "unsafe"
@@ -830,17 +831,9 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
 
                switch t {
                case R_X86_64_64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_X86_64_32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -872,12 +865,7 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error {
                sym := &symbols[symNo-1]
 
                if t == R_386_32 {
-                       if rel.Off+4 >= uint32(len(dst)) {
-                               continue
-                       }
-                       val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
-                       val += uint32(sym.Value)
-                       f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+                       putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
                }
        }
 
@@ -910,12 +898,7 @@ func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
 
                switch t {
                case R_ARM_ABS32:
-                       if rel.Off+4 >= uint32(len(dst)) {
-                               continue
-                       }
-                       val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
-                       val += uint32(sym.Value)
-                       f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+                       putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
                }
        }
 
@@ -955,17 +938,9 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
 
                switch t {
                case R_AARCH64_ABS64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_AARCH64_ABS32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1001,11 +976,7 @@ func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
 
                switch t {
                case R_PPC_ADDR32:
-                       if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, uint64(rela.Off), 4, sym.Value, 0, false)
                }
        }
 
@@ -1041,17 +1012,9 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
 
                switch t {
                case R_PPC64_ADDR64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_PPC64_ADDR32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1084,12 +1047,7 @@ func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
 
                switch t {
                case R_MIPS_32:
-                       if rel.Off+4 >= uint32(len(dst)) {
-                               continue
-                       }
-                       val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
-                       val += uint32(sym.Value)
-                       f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+                       putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
                }
        }
 
@@ -1132,17 +1090,9 @@ func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
 
                switch t {
                case R_MIPS_64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_MIPS_32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1180,17 +1130,9 @@ func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {
 
                switch t {
                case R_LARCH_64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_LARCH_32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1226,17 +1168,9 @@ func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
 
                switch t {
                case R_RISCV_64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_RISCV_32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1272,17 +1206,9 @@ func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
 
                switch t {
                case R_390_64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
                case R_390_32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1318,17 +1244,10 @@ func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
 
                switch t {
                case R_SPARC_64, R_SPARC_UA64:
-                       if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val64 := sym.Value + uint64(rela.Addend)
-                       f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
+                       putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
+
                case R_SPARC_32, R_SPARC_UA32:
-                       if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-                               continue
-                       }
-                       val32 := uint32(sym.Value) + uint32(rela.Addend)
-                       f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
+                       putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
                }
        }
 
@@ -1903,3 +1822,38 @@ type nobitsSectionReader struct{}
 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
        return 0, errors.New("unexpected read from SHT_NOBITS section")
 }
+
+// putUint writes a relocation to slice
+// at offset start of length length (4 or 8 bytes),
+// adding sym+addend to the existing value if readUint is true,
+// or just writing sym+addend if readUint is false.
+// If the write would extend beyond the end of slice, putUint does nothing.
+// If the addend is negative, putUint does nothing.
+// If the addition would overflow, putUint does nothing.
+func putUint(byteOrder binary.ByteOrder, slice []byte, start, length, sym uint64, addend int64, readUint bool) {
+       if start+length > uint64(len(slice)) || math.MaxUint64-start < length {
+               return
+       }
+       if addend < 0 {
+               return
+       }
+
+       s := slice[start : start+length]
+
+       switch length {
+       case 4:
+               ae := uint32(addend)
+               if readUint {
+                       ae += byteOrder.Uint32(s)
+               }
+               byteOrder.PutUint32(s, uint32(sym)+ae)
+       case 8:
+               ae := uint64(addend)
+               if readUint {
+                       ae += byteOrder.Uint64(s)
+               }
+               byteOrder.PutUint64(s, sym+ae)
+       default:
+               panic("can't happen")
+       }
+}