patchelf may bring segfault on GoLang ELF, whose section headers follows program headers and no gap between SHdr and PHdr.
cat > hello-world.go <<EOF
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
EOF
go build -buildmode=pie hello-world.go
patchelf --debug --no-sort --output ./patched1 --set-interpreter /lib64/ld-linux-x86-64.so.2 ./hello-world
patchelf --debug --no-sort --output ./patched2 --set-interpreter /lib64/ld-linux-x86-64.so.2 ./patched1
./patched2
offsetof(PHdrs) + sizeof(PHdrs[0]) * PHdrs.size() == offsetof(SHdrs)
Although first patch runs okay, but PHdrs(program headers) do overlap with SHdrs(Section Headers).
offsetof(PHdrs) + sizeof(PHdrs[0]) * PHdrs.size() > offsetof(SHdrs)
[root tmp]#go version
go version go1.15.7 linux/amd64
[root tmp]#readelf -e ./hello-world
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4650a0
Start of program headers: 64 (bytes into file)
Start of section headers: 736 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 12
Size of section headers: 64 (bytes)
Number of section headers: 39
Section header string table index: 11
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000401000 00001000
0000000000098b4b 0000000000000000 AX 0 0 32
[ 2] .plt PROGBITS 0000000000499b50 00099b50
0000000000000010 0000000000000010 AX 0 0 16
...
(omited for read)
...
[35] .interp PROGBITS 0000000000400fe4 00000fe4
000000000000001c 0000000000000000 A 0 0 1
[36] .note.go.buildid NOTE 0000000000400f80 00000f80
0000000000000064 0000000000000000 A 0 0 4
[37] .symtab SYMTAB 0000000000000000 00224000
0000000000011310 0000000000000018 38 422 8
[38] .strtab STRTAB 0000000000000000 00235310
0000000000010994 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000002a0 0x00000000000002a0 R 1000
INTERP 0x0000000000000fe4 0x0000000000400fe4 0x0000000000400fe4
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
(omited for read)
...
TLS 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000008 R 8
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
LOOS+5041580 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.go.buildid
03 .text .plt .interp .note.go.buildid
04 .rodata .gnu.version_r .rela .rela.plt .dynstr .gnu.version .hash .dynsym
05 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
06 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
07 .go.buildinfo .got.plt .dynamic .got .noptrdata .data .bss .noptrbss
08 .dynamic
09 .tbss
10
11
[root tmp]#./hello-world
hello world
[root tmp]#readelf -e ./patched1
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4650a0
Start of program headers: 64 (bytes into file)
Start of section headers: 736 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 39
Section header string table index: 11
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text DYNAMIC 00000000005dd000 005dd000
0000000000000020 0000000000000000 xxxo 32 0 4096
[ 1] .text PROGBITS 0000000000401000 00001000
0000000000098b4b 0000000000000000 AX 0 0 32
[ 2] .plt PROGBITS 0000000000499b50 00099b50
0000000000000010 0000000000000010 AX 0 0 16
...
(omited for read)
...
[35] .interp PROGBITS 00000000005dd000 00246000
000000000000001c 0000000000000000 A 0 0 8
[36] .note.go.buildid NOTE 0000000000400f80 00000f80
0000000000000064 0000000000000000 A 0 0 4
[37] .symtab SYMTAB 0000000000000000 00224000
0000000000011310 0000000000000018 38 422 8
[38] .strtab STRTAB 0000000000000000 00235310
0000000000010994 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000002d8 0x00000000000002d8 R 1000
INTERP 0x0000000000246000 0x00000000005dd000 0x00000000005dd000
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
(omited for read)
...
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
LOOS+5041580 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 8
LOAD 0x0000000000246000 0x00000000005dd000 0x00000000005dd000
0x0000000000000020 0x0000000000000020 RW 1000
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.go.buildid
03 .text .plt .note.go.buildid
04 .rodata .gnu.version_r .rela .rela.plt .dynstr .gnu.version .hash .dynsym
05 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
06 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
07 .go.buildinfo .got.plt .dynamic .got .noptrdata .data .bss .noptrbss
08 .dynamic
09 .tbss
10
11
12 .interp
[root tmp]#readelf -e ./patched2
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4650a0
Start of program headers: 64 (bytes into file)
Start of section headers: 736 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 14
Size of section headers: 64 (bytes)
Number of section headers: 39
Section header string table index: 11
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text DYNAMIC 00000000005dd000 005dd000
0000000000000020 0000000600000001 xxxo 32 0 4096
[ 1] .text PROGBITS 0000000000401000 00001000
0000000000098b4b 0000000000000000 AX 0 0 32
[ 2] .plt PROGBITS 0000000000499b50 00099b50
0000000000000010 0000000000000010 AX 0 0 16
...
(omited for read)
...
[35] .interp PROGBITS 00000000005de000 00247000
000000000000001c 0000000000000000 A 0 0 8
[36] .note.go.buildid NOTE 0000000000400f80 00000f80
0000000000000064 0000000000000000 A 0 0 4
[37] .symtab SYMTAB 0000000000000000 00224000
0000000000011310 0000000000000018 38 422 8
[38] .strtab STRTAB 0000000000000000 00235310
0000000000010994 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x0000000000000310 0x0000000000000310 R 1000
INTERP 0x0000000000247000 0x00000000005de000 0x00000000005de000
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
(omited for read)
...
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
LOOS+5041580 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 8
LOAD 0x0000000000246000 0x00000000005dd000 0x00000000005dd000
0x0000000000000020 0x0000000000000020 RW 1000
LOAD 0x0000000100000001 0x0000000000000006 0x0000000000401000
0x0000000000001000 0x0000000000098b4b RW 0
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.go.buildid
03 .text .plt .note.go.buildid
04 .rodata .gnu.version_r .rela .rela.plt .dynstr .gnu.version .hash .dynsym
05 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
06 .data.rel.ro .data.rel.ro.typelink .data.rel.ro.itablink .data.rel.ro.gosymtab .data.rel.ro.gopclntab
07 .go.buildinfo .got.plt .dynamic .got .noptrdata .data .bss .noptrbss
08 .dynamic
09 .tbss
10
11
12
13
Describe the bug
patchelf may bring segfault on GoLang ELF, whose section headers follows program headers and no gap between SHdr and PHdr.
Steps To Reproduce
Expected behavior
patchelf --versionoutputpatchelf 0.17.2
Additional context
for original file, Section Headers next to program headers:
Although first patch runs okay, but PHdrs(program headers) do overlap with SHdrs(Section Headers).
because new header added to PHdrs
details here:
here is full record