NixOS / patchelf

A small utility to modify the dynamic linker and RPATH of ELF executables
GNU General Public License v3.0
3.57k stars 487 forks source link

Segfault while section headers follows program headers #457

Closed fish2bird closed 1 year ago

fish2bird commented 1 year ago

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

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

Expected behavior

patchelf --version output

patchelf 0.17.2

Additional context

for original file, Section Headers next to program headers:

offsetof(PHdrs) + sizeof(PHdrs[0]) * PHdrs.size() == offsetof(SHdrs)

Although first patch runs okay, but PHdrs(program headers) do overlap with SHdrs(Section Headers).

because new header added to PHdrs

offsetof(PHdrs) + sizeof(PHdrs[0]) * PHdrs.size() > offsetof(SHdrs)

details here:

[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     

here is full record

brenoguim commented 1 year ago

Fixed with #460