NixOS / patchelf

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

`patchelf --set-interpreter` and `patchelf --set-rpath` depend on the order (at least on i686-linux) #524

Open kvtb opened 1 year ago

kvtb commented 1 year ago

Describe the bug

patchelf --set-interpreter following patchelf --set-rpath may produce broken executables

patchelf --set-rpath following patchelf --set-interpreter works well for the same files

Context The latest released LDC for i686-linux is quite old, much older than for 64-bit platform. Upstream's position is understandable: x86_64-compiler is able to produce i686 executables. But as NixOS has no x86_64->i686 cross compilation we need a i686-linux compiler. Starting with so old one using it for bootstrapping recent versions: binary released 1.2.0 is able to bootstrap at most 1.29.0 (relatively modern) which is able to bootstrap the latest 1.34.0

The executable of the latest LDC for i686-linux is https://github.com/ldc-developers/ldc/releases/download/v1.2.0/ldc2-1.2.0-linux-x86.tar.xz

Steps To Reproduce

Put 1.2.0 here https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/ldc/bootstrap.nix (there is no newer binary anyway) and build pkgsi686Linux.ldc autoPatchelfHook produces broken executables (which crash immediately upon start)

It was discovered that removing autoPatchelfHook and replacing it with

    for f in $(find $out/bin -type f -executable); do
      patchelf --set-rpath       $out/bin:${lib.makeLibraryPath [ stdenv.cc.cc stdenv.cc.libc ]} "$f"
      patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker)                       "$f"
    done

does produce valid executables but

    for f in $(find $out/bin -type f -executable); do
      patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker)                       "$f"
      patchelf --set-rpath       $out/bin:${lib.makeLibraryPath [ stdenv.cc.cc stdenv.cc.libc ]} "$f"
    done

produces invalid ones

As a side note I could say that putting both --set-interpreter and --set-rpath into a single patchelf run always lead to broken executables, regardless on their order.

Expected behavior

expected that swapping patchelf --set-interpreter and patchelf --set-rpath would produce the same.

if there is a point for them to behave differently depending on the order, autoPatchelfHook should be aware and use the only valid order, i.e. always use patchelf --set-rpath before patchelf --set-interpreter and never combine them into a single run

patchelf --version output

0.18.0

DavidC-75 commented 9 months ago

I was about to file a new issue and then found this one.... which is exactly what I've observed too (in a slightly different context). Let me describe.

With their usual wisdom and carelessness, Microsoft have decided for their latest VS Code remote development package to require glibc 2.28, and that requirement arrives a few months before the end of life for distributions such as CentOs 7, RHEL 7 or SLES 12 that are based on older glibc.

The latest VS Code server can be downloaded from here (05047486b6df5eb8d44b2ecd70ea3bdf775fd937 is the current commit_id for VS Code 1.86, visible in help/about)

To avoid the limitations from my aging linux distribution, I also downloaded glibc 2.34 and built and installed it on my local machine.

At last, I decided to use this trick to try and start the VS Code server using glibc 2.34...

After a little bit of time and a lot of luck, I found that only following would produce a result that works:

patchelf --set-rpath       /path/to/glibc-2.34/lib64                      ~/.vscode-server/bin/05047486b6df5eb8d44b2ecd70ea3bdf775fd937/node
patchelf --set-interpreter /path/to/glibc-2.34/lib64/ld-linux-x86-64.so.2 ~/.vscode-server/bin/05047486b6df5eb8d44b2ecd70ea3bdf775fd937/node

However, as reported in the OP, the same steps in the reverse order, or combined in a single invokation of patchelf (whatever the order is), leads to an invalid node binary (core dumped).

chenhaowen01 commented 9 months ago

I was about to file a new issue and then found this one.... which is exactly what I've observed too (in a slightly different context). Let me describe.

With their usual wisdom and carelessness, Microsoft have decided for their latest VS Code remote development package to require glibc 2.28, and that requirement arrives a few months before the end of life for distributions such as CentOs 7, RHEL 7 or SLES 12 that are based on older glibc.

The latest VS Code server can be downloaded from here ( is the current commit_id for VS Code 1.86, visible in help/about)05047486b6df5eb8d44b2ecd70ea3bdf775fd937

To avoid the limitations from my aging linux distribution, I also downloaded glibc 2.34 and built and installed it on my local machine.

At last, I decided to use this trick to try and start the VS Code server using glibc 2.34...

After a little bit of time and a lot of luck, I found that only following would produce a result that works:

patchelf --set-rpath       /path/to/glibc-2.34/lib64/lib64                      ~/.vscode-server/bin/05047486b6df5eb8d44b2ecd70ea3bdf775fd937/node
patchelf --set-interpreter /path/to/glibc-2.34/lib64/lib64/ld-linux-x86-64.so.2 ~/.vscode-server/bin/05047486b6df5eb8d44b2ecd70ea3bdf775fd937/node

However, as reported in the OP, the same steps in the reverse order, or combined in a single invokation of (whatever the order is), leads to in invalid binary (core dumped).patchelf``node

To add some information, according to issue 531, there is no problem with version 0.15.0. I tried using version 0.15 and it does work.

k4lizen commented 7 months ago

Re: https://github.com/io12/pwninit/issues/297 and https://github.com/pwndbg/pwndbg/issues/924#issuecomment-1999970799