aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorJes Cok <xigua67damn@gmail.com>2025-09-25 04:41:12 +0000
committerGopher Robot <gobot@golang.org>2025-09-28 21:38:57 -0700
commit5500cbf0e420a6d643835ec05f35abb170e3e443 (patch)
tree5198d0d4702d169655e479a187b688850050ab05 /src/debug
parent34e67623a81e9e93c3d7d0f0cb257d7d722939f2 (diff)
downloadgo-5500cbf0e420a6d643835ec05f35abb170e3e443.tar.xz
debug/elf: prevent offset overflow
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>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/elf/file.go160
1 files changed, 57 insertions, 103 deletions
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 50452b5bef..1d56a06c3f 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -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")
+ }
+}