Skip to content

Commit 4914431

Browse files
committed
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 golang#75516 Change-Id: I3a1662398a981977d6cbacfa47c40707ddd87b37
1 parent f15cd63 commit 4914431

File tree

1 file changed

+57
-103
lines changed

1 file changed

+57
-103
lines changed

src/debug/elf/file.go

Lines changed: 57 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"internal/saferio"
2626
"internal/zstd"
2727
"io"
28+
"math"
2829
"os"
2930
"strings"
3031
"unsafe"
@@ -830,17 +831,9 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
830831

831832
switch t {
832833
case R_X86_64_64:
833-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
834-
continue
835-
}
836-
val64 := sym.Value + uint64(rela.Addend)
837-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
834+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
838835
case R_X86_64_32:
839-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
840-
continue
841-
}
842-
val32 := uint32(sym.Value) + uint32(rela.Addend)
843-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
836+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
844837
}
845838
}
846839

@@ -872,12 +865,7 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error {
872865
sym := &symbols[symNo-1]
873866

874867
if t == R_386_32 {
875-
if rel.Off+4 >= uint32(len(dst)) {
876-
continue
877-
}
878-
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
879-
val += uint32(sym.Value)
880-
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
868+
putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
881869
}
882870
}
883871

@@ -910,12 +898,7 @@ func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
910898

911899
switch t {
912900
case R_ARM_ABS32:
913-
if rel.Off+4 >= uint32(len(dst)) {
914-
continue
915-
}
916-
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
917-
val += uint32(sym.Value)
918-
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
901+
putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
919902
}
920903
}
921904

@@ -955,17 +938,9 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
955938

956939
switch t {
957940
case R_AARCH64_ABS64:
958-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
959-
continue
960-
}
961-
val64 := sym.Value + uint64(rela.Addend)
962-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
941+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
963942
case R_AARCH64_ABS32:
964-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
965-
continue
966-
}
967-
val32 := uint32(sym.Value) + uint32(rela.Addend)
968-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
943+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
969944
}
970945
}
971946

@@ -1001,11 +976,7 @@ func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
1001976

1002977
switch t {
1003978
case R_PPC_ADDR32:
1004-
if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
1005-
continue
1006-
}
1007-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1008-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
979+
putUint(f.ByteOrder, dst, uint64(rela.Off), 4, sym.Value, 0, false)
1009980
}
1010981
}
1011982

@@ -1041,17 +1012,9 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
10411012

10421013
switch t {
10431014
case R_PPC64_ADDR64:
1044-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1045-
continue
1046-
}
1047-
val64 := sym.Value + uint64(rela.Addend)
1048-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1015+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
10491016
case R_PPC64_ADDR32:
1050-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1051-
continue
1052-
}
1053-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1054-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1017+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
10551018
}
10561019
}
10571020

@@ -1084,12 +1047,7 @@ func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
10841047

10851048
switch t {
10861049
case R_MIPS_32:
1087-
if rel.Off+4 >= uint32(len(dst)) {
1088-
continue
1089-
}
1090-
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
1091-
val += uint32(sym.Value)
1092-
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
1050+
putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)
10931051
}
10941052
}
10951053

@@ -1132,17 +1090,9 @@ func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
11321090

11331091
switch t {
11341092
case R_MIPS_64:
1135-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1136-
continue
1137-
}
1138-
val64 := sym.Value + uint64(rela.Addend)
1139-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1093+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
11401094
case R_MIPS_32:
1141-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1142-
continue
1143-
}
1144-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1145-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1095+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
11461096
}
11471097
}
11481098

@@ -1180,17 +1130,9 @@ func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {
11801130

11811131
switch t {
11821132
case R_LARCH_64:
1183-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1184-
continue
1185-
}
1186-
val64 := sym.Value + uint64(rela.Addend)
1187-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1133+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
11881134
case R_LARCH_32:
1189-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1190-
continue
1191-
}
1192-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1193-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1135+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
11941136
}
11951137
}
11961138

@@ -1226,17 +1168,9 @@ func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
12261168

12271169
switch t {
12281170
case R_RISCV_64:
1229-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1230-
continue
1231-
}
1232-
val64 := sym.Value + uint64(rela.Addend)
1233-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1171+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
12341172
case R_RISCV_32:
1235-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1236-
continue
1237-
}
1238-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1239-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1173+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
12401174
}
12411175
}
12421176

@@ -1272,17 +1206,9 @@ func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
12721206

12731207
switch t {
12741208
case R_390_64:
1275-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1276-
continue
1277-
}
1278-
val64 := sym.Value + uint64(rela.Addend)
1279-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1209+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
12801210
case R_390_32:
1281-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1282-
continue
1283-
}
1284-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1285-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1211+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
12861212
}
12871213
}
12881214

@@ -1318,17 +1244,10 @@ func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
13181244

13191245
switch t {
13201246
case R_SPARC_64, R_SPARC_UA64:
1321-
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1322-
continue
1323-
}
1324-
val64 := sym.Value + uint64(rela.Addend)
1325-
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1247+
putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)
1248+
13261249
case R_SPARC_32, R_SPARC_UA32:
1327-
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1328-
continue
1329-
}
1330-
val32 := uint32(sym.Value) + uint32(rela.Addend)
1331-
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1250+
putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)
13321251
}
13331252
}
13341253

@@ -1903,3 +1822,38 @@ type nobitsSectionReader struct{}
19031822
func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
19041823
return 0, errors.New("unexpected read from SHT_NOBITS section")
19051824
}
1825+
1826+
// putUint writes a relocation to slice
1827+
// at offset start of length length (4 or 8 bytes),
1828+
// adding sym+addend to the existing value if readUint is true,
1829+
// or just writing sym+addend if readUint is false.
1830+
// If the write would extend beyond the end of slice, putUint does nothing.
1831+
// If the addend is negative, putUint does nothing.
1832+
// If the addition would overflow, putUint does nothing.
1833+
func putUint(byteOrder binary.ByteOrder, slice []byte, start, length, sym uint64, addend int64, readUint bool) {
1834+
if start+length > uint64(len(slice)) || math.MaxUint64-start < length {
1835+
return
1836+
}
1837+
if addend < 0 {
1838+
return
1839+
}
1840+
1841+
s := slice[start : start+length]
1842+
1843+
switch length {
1844+
case 4:
1845+
ae := uint32(addend)
1846+
if readUint {
1847+
ae += byteOrder.Uint32(s)
1848+
}
1849+
byteOrder.PutUint32(s, uint32(sym)+ae)
1850+
case 8:
1851+
ae := uint64(addend)
1852+
if readUint {
1853+
ae += byteOrder.Uint64(s)
1854+
}
1855+
byteOrder.PutUint64(s, sym+ae)
1856+
default:
1857+
panic("can't happen")
1858+
}
1859+
}

0 commit comments

Comments
 (0)