Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault while section headers follows program headers #457

Closed
fish2bird opened this issue Feb 1, 2023 · 1 comment
Closed

Segfault while section headers follows program headers #457

fish2bird opened this issue Feb 1, 2023 · 1 comment
Labels

Comments

@fish2bird
Copy link

fish2bird commented Feb 1, 2023

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 should honor space reserved for Program headers, and move if not enough while grow.
  • patchelf should avoid adding new PHdr if modify in-place possible

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

@fish2bird fish2bird added the bug label Feb 1, 2023
brenoguim added a commit to brenoguim/patchelf that referenced this issue Feb 19, 2023
…S#457

This patch checks if the section header table is placed right after the
program header table such that it would overlap when we add a new entry
in the program header table.
If that is the case, move the section header table to the end of the file.

Moreover, there is no need to add a new PT_LOAD segment everytime.
Check if the last segment is already a PT_LOAD with the same characteristics
and adjacent. Extend it in this case.
brenoguim added a commit to brenoguim/patchelf that referenced this issue Feb 19, 2023
…S#457

This patch checks if the section header table is placed right after the
program header table such that it would overlap when we add a new entry
in the program header table.
If that is the case, move the section header table to the end of the file.

Moreover, there is no need to add a new PT_LOAD segment everytime.
Check if the last segment is already a PT_LOAD with the same characteristics
and adjacent. Extend it in this case.
brenoguim added a commit to brenoguim/patchelf that referenced this issue Feb 19, 2023
…S#457

This patch checks if the section header table is placed right after the
program header table such that it would overlap when we add a new entry
in the program header table.
If that is the case, move the section header table to the end of the file.

Moreover, there is no need to add a new PT_LOAD segment everytime.
Check if the last segment is already a PT_LOAD with the same characteristics
and adjacent. Extend it in this case.
bors bot added a commit that referenced this issue Feb 24, 2023
460: Avoid overlapping program header table with section header table #457 r=Mic92 a=brenoguim



Co-authored-by: Breno Rodrigues Guimaraes <[email protected]>
Co-authored-by: Breno Rodrigues Guimarães <[email protected]>
Co-authored-by: Jörg Thalheim <[email protected]>
@brenoguim
Copy link
Collaborator

Fixed with #460

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants