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

patchelf --set-interpreter fails with cannot find section #66

Closed
pmahoney opened this issue Sep 16, 2015 · 24 comments
Closed

patchelf --set-interpreter fails with cannot find section #66

pmahoney opened this issue Sep 16, 2015 · 24 comments

Comments

@pmahoney
Copy link

I have a binary compiled with the Go 1.4 compiler from nixpkgs, and I'd like to run it outside of a nix environment, so I'm trying to patch the interpreter.

patchelf 0.8 gives the following error:

$ patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2  prog
patchelf: patchelf.cc:693: void ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym>::rewriteSectionsExecutable() [with Elf_Ehdr = Elf64_Ehdr; Elf_Phdr = Elf64_Phdr; Elf_Shdr = Elf64_Shdr; Elf_Addr = long unsigned int; Elf_Off = long unsigned int; Elf_Dyn = Elf64_Dyn; Elf_Sym = Elf64_Sym]: Assertion `(off_t) rdi(hdr->e_shoff) >= startOffset' failed.
Aborted

Which I think was fixed in pull 39.

I built a patchelf from master @ 63296c4, and I now get a different error:

 ./result/bin/patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --debug prog
patching ELF file `prog'
Kernel page size is 4096 bytes
replacing section `.interp' with size 28
this is an executable
using replaced section `.interp'
last replaced is 2
looking at section `'
replacing section `' which is in the way
looking at section `.interp'
first reserved offset/addr is 0xc00/0x400c00
first page is 0x400000
needed space is 600
clearing first 2504 bytes
cannot find section 

headers:

$ readelf -e prog
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:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x43dee0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          568 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         33
  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         0000000000400c00  00000c00
       000000000029d3fb  0000000000000000  AX       0     0     16
  [ 2] .plt              PROGBITS         000000000069e000  0029e000
       0000000000000170  0000000000000010  AX       0     0     4
  [ 3] .rodata           PROGBITS         000000000069f000  0029f000
       00000000001cd6c0  0000000000000000   A       0     0     32
  [ 4] .typelink         PROGBITS         000000000086c6c0  0046c6c0
       0000000000001308  0000000000000000   A       0     0     8
  [ 5] .gosymtab         PROGBITS         000000000086d9c8  0046d9c8
       0000000000000000  0000000000000000   A       0     0     1
  [ 6] .gopclntab        PROGBITS         000000000086d9e0  0046d9e0
       00000000000f879d  0000000000000000   A       0     0     32
  [ 7] .rela             RELA             0000000000966180  00566180
       0000000000000018  0000000000000018   A      14     0     8
  [ 8] .gnu.version      VERSYM           00000000009661a0  005661a0
       0000000000000038  0000000000000002   A      14     0     2
  [ 9] .gnu.version_r    VERNEED          00000000009661e0  005661e0
       0000000000000040  0000000000000000   A      12     2     8
  [10] .hash             HASH             0000000000966220  00566220
       0000000000000090  0000000000000004   A      14     0     8
  [11] .shstrtab         STRTAB           0000000000000000  005662c0
       0000000000000185  0000000000000000           0     0     1
  [12] .dynstr           STRTAB           0000000000966460  00566460
       0000000000000189  0000000000000000   A       0     0     1
  [13] .rela.plt         RELA             0000000000966600  00566600
       0000000000000210  0000000000000018   A      14     2     8
  [14] .dynsym           DYNSYM           0000000000966820  00566820
       00000000000002a0  0000000000000018   A      12     0     8
  [15] .got              PROGBITS         0000000000967000  00567000
       0000000000000008  0000000000000008  WA       0     0     8
  [16] .got.plt          PROGBITS         0000000000967020  00567020
       00000000000000c8  0000000000000008  WA       0     0     8
  [17] .dynamic          DYNAMIC          0000000000967100  00567100
       0000000000000130  0000000000000010  WA      12     0     8
  [18] .noptrdata        PROGBITS         0000000000967240  00567240
       0000000000015eac  0000000000000000  WA       0     0     32
  [19] .data             PROGBITS         000000000097d100  0057d100
       0000000000006f90  0000000000000000  WA       0     0     32
  [20] .bss              NOBITS           00000000009840a0  005840a0
       0000000000009520  0000000000000000  WA       0     0     32
  [21] .noptrbss         NOBITS           000000000098d5c0  0058d5c0
       0000000000013448  0000000000000000  WA       0     0     32
  [22] .interp           PROGBITS         0000000000400bb0  00000bb0
       0000000000000050  0000000000000000   A       0     0     1
  [23] .symtab           SYMTAB           0000000000000000  00585000
       00000000000340f8  0000000000000018          24   195     8
  [24] .strtab           STRTAB           0000000000000000  005b90f8
       0000000000044f9a  0000000000000000           0     0     1
  [25] .tbss             NOBITS           0000000000000000  00000000
       0000000000000010  0000000000000000 WAT       0     0     8
  [26] .debug_abbrev     PROGBITS         0000000000000000  005fe092
       00000000000000fd  0000000000000000           0     0     1
  [27] .debug_line       PROGBITS         0000000000000000  005fe18f
       00000000000386b7  0000000000000000           0     0     1
  [28] .debug_frame      PROGBITS         0000000000000000  00636846
       00000000000409a4  0000000000000000           0     0     1
  [29] .debug_info       PROGBITS         0000000000000000  006771ea
       000000000010c120  0000000000000000           0     0     1
  [30] .debug_pubnames   PROGBITS         0000000000000000  0078330a
       000000000004cf2d  0000000000000000           0     0     1
  [31] .debug_pubtypes   PROGBITS         0000000000000000  007d0237
       000000000001d88b  0000000000000000           0     0     1
  [32] .debug_aranges    PROGBITS         0000000000000000  007edac2
       0000000000000030  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R      1000
  INTERP         0x0000000000000bb0 0x0000000000400bb0 0x0000000000400bb0
                 0x0000000000000050 0x0000000000000050  R      1
      [Requesting program interpreter: /nix/store/q0m70q5wg21hxrixkp1xk4x95sfs2fln-glibc-2.21/lib/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x000000000029e130 0x000000000029e130  R E    1000
  LOAD           0x000000000029f000 0x000000000069f000 0x000000000069f000
                 0x00000000002c7ac0 0x00000000002c7ac0  R      1000
  LOAD           0x0000000000567000 0x0000000000967000 0x0000000000967000
                 0x000000000001d0a0 0x0000000000039a08  RW     1000
  DYNAMIC        0x0000000000567100 0x0000000000967100 0x0000000000967100
                 0x0000000000000130 0x0000000000000130  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000010  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     .text .plt .interp
   03     .rodata .typelink .gosymtab .gopclntab .rela .gnu.version .gnu.version_r .hash .shstrtab .dynstr .rela.plt .dynsym
   04     .got .got.plt .dynamic .noptrdata .data .bss .noptrbss
   05     .dynamic
   06     .tbss
   07
   08
@offlinehacker
Copy link

I have same error, also go binary.

@pmahoney
Copy link
Author

For anyone encountering this problem, if your go program can be compiled as a purely static library (doesn't need to link to libc or any other c library), this worked for me:

# build static binary
CGO_ENABLED=0 go build -v -a -tags netgo -installsuffix netgo <package>

see golang/go#9369 (comment)

But of course this won't help programs that do need to link to libc.

@chris-martin
Copy link

I'm having the same problem. The Go binary in question is Otto (64-bit).

@aaronlevin
Copy link

👍 I'm also hitting this issue with an internal library (distributed as a binary) that is very simple.

@aaronlevin
Copy link

I hit this issue again and tried patchelf-0.9, still no luck.

@puffnfresh
Copy link

Same situation as above.

@thearchitect
Copy link

Same patchelf error for binaries built with golang 1.6

@edolstra
Copy link
Member

edolstra commented May 3, 2016

The otto binary gives:

cannot find section .interp

which is a different problem than the original report, i.e.

cannot find section 

PR #95 may fix the latter, but it's not clear to me whether skipping sections with empty names (which is not necessarily the same as an empty section) is the right thing to do.

@sleexyz
Copy link

sleexyz commented Sep 8, 2016

Same error here:

binary in question is ngrok

pretty sure it is a go-packaged binary, but it is closed source so I can't rebuild it myself

> patchelf --set-interpreter /nix/store/y5js9j7zgrmz4j2dqcy0nvaqyk3izbv7-glibc-2.24/lib64/ld-linux-x86-64.so.2 --debug ngrok
patching ELF file `ngrok'
Kernel page size is 4096 bytes
replacing section `.interp' with size 82
this is an executable
using replaced section `.interp'
last replaced is 2
looking at section `'
replacing section `' which is in the way
looking at section `.interp'
first reserved offset/addr is 0xc00/0x400c00
first page is 0x400000
needed space is 656
clearing first 2504 bytes
cannot find section 
> readelf -e ngrok
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:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x486020
  Start of program headers:          64 (bytes into file)
  Start of section headers:          568 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         33
  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         0000000000400c00  00000c00
       000000000042facf  0000000000000000  AX       0     0     16
  [ 2] .plt              PROGBITS         00000000008306e0  004306e0
       0000000000000170  0000000000000010  AX       0     0     4
  [ 3] .rodata           PROGBITS         0000000000831000  00431000
       0000000000388af0  0000000000000000   A       0     0     32
  [ 4] .typelink         PROGBITS         0000000000bb9af0  007b9af0
       0000000000001c30  0000000000000000   A       0     0     8
  [ 5] .gosymtab         PROGBITS         0000000000bbb720  007bb720
       0000000000000000  0000000000000000   A       0     0     1
  [ 6] .gopclntab        PROGBITS         0000000000bbb720  007bb720
       00000000001a24e4  0000000000000000   A       0     0     32
  [ 7] .rela             RELA             0000000000d5dc10  0095dc10
       0000000000000018  0000000000000018   A      14     0     8
  [ 8] .gnu.version      VERSYM           0000000000d5dc40  0095dc40
       0000000000000038  0000000000000002   A      14     0     2
  [ 9] .gnu.version_r    VERNEED          0000000000d5dc80  0095dc80
       0000000000000040  0000000000000000   A      12     2     8
  [10] .hash             HASH             0000000000d5dcc0  0095dcc0
       0000000000000090  0000000000000004   A      14     0     8
  [11] .shstrtab         STRTAB           0000000000000000  0095dd60
       0000000000000185  0000000000000000           0     0     1
  [12] .dynstr           STRTAB           0000000000d5df00  0095df00
       0000000000000189  0000000000000000   A       0     0     1
  [13] .rela.plt         RELA             0000000000d5e0a0  0095e0a0
       0000000000000210  0000000000000018   A      14     2     8
  [14] .dynsym           DYNSYM           0000000000d5e2c0  0095e2c0
       00000000000002a0  0000000000000018   A      12     0     8
  [15] .got              PROGBITS         0000000000d5f000  0095f000
       0000000000000008  0000000000000008  WA       0     0     8
  [16] .got.plt          PROGBITS         0000000000d5f020  0095f020
       00000000000000c8  0000000000000008  WA       0     0     8
  [17] .dynamic          DYNAMIC          0000000000d5f100  0095f100
       0000000000000130  0000000000000010  WA      12     0     8
  [18] .noptrdata        PROGBITS         0000000000d5f240  0095f240
       000000000001878c  0000000000000000  WA       0     0     32
  [19] .data             PROGBITS         0000000000d779e0  009779e0
       000000000000c1d0  0000000000000000  WA       0     0     32
  [20] .bss              NOBITS           0000000000d83bc0  00983bc0
       0000000000009ce0  0000000000000000  WA       0     0     32
  [21] .noptrbss         NOBITS           0000000000d8d8a0  0098d8a0
       00000000000149c8  0000000000000000  WA       0     0     32
  [22] .interp           PROGBITS         0000000000400be4  00000be4
       000000000000001c  0000000000000000   A       0     0     1
  [23] .symtab           SYMTAB           0000000000000000  00984000
       0000000000055608  0000000000000018          24   197     8
  [24] .strtab           STRTAB           0000000000000000  009d9608
       000000000007888b  0000000000000000           0     0     1
  [25] .tbss             NOBITS           0000000000000000  00000000
       0000000000000010  0000000000000000 WAT       0     0     8
  [26] .debug_abbrev     PROGBITS         0000000000000000  00a51e93
       00000000000000fd  0000000000000000           0     0     1
  [27] .debug_line       PROGBITS         0000000000000000  00a51f90
       00000000000533e6  0000000000000000           0     0     1
  [28] .debug_frame      PROGBITS         0000000000000000  00aa5376
       000000000006cc14  0000000000000000           0     0     1
  [29] .debug_info       PROGBITS         0000000000000000  00b11f8a
       00000000001c8d26  0000000000000000           0     0     1
  [30] .debug_pubnames   PROGBITS         0000000000000000  00cdacb0
       0000000000086302  0000000000000000           0     0     1
  [31] .debug_pubtypes   PROGBITS         0000000000000000  00d60fb2
       0000000000035536  0000000000000000           0     0     1
  [32] .debug_aranges    PROGBITS         0000000000000000  00d964e8
       0000000000000030  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
                 0x00000000000001f8 0x00000000000001f8  R      1000
  INTERP         0x0000000000000be4 0x0000000000400be4 0x0000000000400be4
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000430810 0x0000000000430810  R E    1000
  LOAD           0x0000000000431000 0x0000000000831000 0x0000000000831000
                 0x000000000052d560 0x000000000052d560  R      1000
  LOAD           0x000000000095f000 0x0000000000d5f000 0x0000000000d5f000
                 0x0000000000024bc0 0x0000000000043268  RW     1000
  DYNAMIC        0x000000000095f100 0x0000000000d5f100 0x0000000000d5f100
                 0x0000000000000130 0x0000000000000130  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000010  R      8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     8
  PAX_FLAGS      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .text .plt .interp 
   03     .rodata .typelink .gosymtab .gopclntab .rela .gnu.version .gnu.version_r .hash .dynstr .rela.plt .dynsym 
   04     .got .got.plt .dynamic .noptrdata .data .bss .noptrbss 
   05     .dynamic 
   06     .tbss 
   07     
   08

DoomHammer added a commit to DoomHammer/patchelf that referenced this issue Oct 7, 2016
peterhoeg pushed a commit to peterhoeg/nixpkgs that referenced this issue Nov 4, 2016
The heroku tool has changed and now downloads a binary to do bulk of the
work.

This PR also downloads the binary to wrap it properly, but due to
NixOS/patchelf#66 we cannot ```patchelf``` the
binary and it doesn't work.

So for now we instead wrap it in a buildFHSUserEnv so at least things
are working again.

Once the patchelf issue has been solved, I'll update this again.
@vikstrous
Copy link

Same issue with the minio binary client. Building from scratch myself worked as expected.

@offlinehacker
Copy link

offlinehacker commented Dec 15, 2016 via email

@puffnfresh
Copy link

@purefn came up with this nice solution:

{ stdenv }:
 
stdenv.mkDerivation rec {
  name = "example";
 
  src = example.tar.gz;
 
  phases = [ "unpackPhase" "installPhase" ];
 
  installPhase = ''
    mkdir -p $out/bin
    cp example $out/bin/example.wrapped
    echo $(< $NIX_CC/nix-support/dynamic-linker) $out/bin/example.wrapped \"\$@\" > $out/bin/example
    chmod +x $out/bin/example
  '';
}

Which runs the linker with the binary instead of patching the binary to use the linker. Pretty cool 👍

@rlupton20
Copy link

The above trick works for standalone plugins, but I'm hitting this now trying to get a terraform plugin (which is again just a go binary) to work. Running from the terminal is fine, but it crashes out when terraform tries to use it (which is perhaps not terribly surprising).

@rlupton20
Copy link

I just did a horrible thing but got it to work. One day I'll craft a proper solution, but for the moment I

  • downloaded the binary to my home directory
  • symlinked the dynamic linker with an absolute file name the same length as the one in the elf header
  • edited the elf header in vim to use the symlink as interpreter

Seems to work, good enough for the moment, and perhaps another useful trick for anyone rolling by here who needs to get out of a tight spot!

@ezquat
Copy link
Contributor

ezquat commented Jun 21, 2018

I encountered this problem also, with a Go biniary, and I think I have some form of "fix" for patchelf.

To recount the problem symptoms: with patchelf 0.8 you get an assertion failure, (off_t) rdi(hdr->e_shoff) >= startOffset'. With patchelf 0.9 you get cannot find section , which is referring to the section with the empty name, which is some kind of dummy placeholder in ELF files, at section index 0.

Here's my understanding of the bug: Most of the code in patchelf ignores the first entry in the section header table, but there is a call to C++ sort() which can move the entry at index 0, in the case where some other entry also has offset 0 (which is the case for Go binaries, a .tbss section has offset 0). It is easy to skip entry 0 in the sort. Then another problem kicks in, which is that patchelf tries to overwrite some bytes (with 'X's) at that offset 0, even though the .tbss section is marked as NOBITS and thus has no content.

I'm not totally confident in this area, but I'd like to offer my fix.

ezquat added a commit to ezquat/patchelf that referenced this issue Jun 21, 2018
ezquat added a commit to ezquat/patchelf that referenced this issue Jun 21, 2018
@ezquat
Copy link
Contributor

ezquat commented Jun 21, 2018

See PR #149.

@kuznero
Copy link
Member

kuznero commented Mar 5, 2019

Same with argo-cd go binary ;(

edolstra added a commit that referenced this issue Mar 6, 2019
Fix issue #66: ignore 0th section header when sorting, don't overwrite NOBITS
@iMichka
Copy link

iMichka commented Mar 6, 2019

#149 was merged. This issue can be closed.

@steshaw
Copy link
Member

steshaw commented Aug 5, 2019

I ran into this problem today and for anyone who comes by here, I had to install nixpkgs.patchelfUnstable to get it working.

@offlinehacker
Copy link

@steshaw you had issues with 0.10 version?

@steshaw
Copy link
Member

steshaw commented Aug 7, 2019

@offlinehacker I checked the versions: nixpkgs.patchelf is 0.9 and I had to install the unstable version which reports 0.10-pre-20190328. This worked fine for me.

@offlinehacker
Copy link

Yeah 0.10 is still not merged in nixpkgs

@robinp
Copy link

robinp commented Oct 3, 2019

Quick hack if it helps: you can invoke the dynamic interpreter with the program as the argument, to get it running at least... So instead patchelf --set-interpreter foo bar, you can do foo bar.

@maxmcd
Copy link

maxmcd commented Oct 25, 2020

I'm still getting this issue when trying to patch the latest version of Go: https://golang.org/dl/go1.15.3.linux-amd64.tar.gz

patching ELF file `/go/bin/go'
Kernel page size is 4096 bytes
replacing section `.interp' with size 108
this is an executable
using replaced section `.interp'
last replaced is 3
looking at section `'
replacing section `' which is in the way
looking at section `.note.go.buildid'
replacing section `.note.go.buildid' which is in the way
looking at section `.interp'
first reserved offset/addr is 0x1000/0x401000
first page is 0x400000
needed space is 840
clearing first 3472 bytes
cannot find section

Using patchelf version 0.12

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

No branches or pull requests