[PATCH 1/1] elf: Canonicalize $ORIGIN in an explicit ld.so invocation [BZ #25263]
Geoffrey Thomas
geofft@ldpreload.com
Fri Feb 28 19:02:00 GMT 2025
On Thu, Feb 27, 2025, at 3:26 PM, Adhemerval Zanella Netto wrote:
> Although this change solves the LD_TRACE_LOADED_OBJECTS=1 (ldd) issue, I
> think it still misses the underlying issue for the case user want to also
> run the binary with a direct loader invocation (as Florian has hinted on
> comment #4).
>
> For instance, with this testcase (similar to what electron is doing from
> the bug report):
>
> $ cat test/main.c
> int main (int argc, char *argv[]) { return 0; }
> $ cat test/lib1.c
> int foo (void) { return 42; }
> tst-bz25263 $ mkdir test && cd test
> test $ gcc -Wall -shared -Wl,-soname,lib1.so lib1.c -o lib1.so
> test $ gcc -no-pie -Wall main.c -o main -Wl,-rpath,\$ORIGIN -L`pwd`
> -Wl,-no-as-needed -l1
> test $ gcc -no-pie -Wall main.c -o main-hcp
> -Wl,-rpath,\$ORIGIN:$GLIBCBUILDDIR
> -Wl,-dynamic-linker,$GLIBCBUILDDIR/elf/ld.so -L`pwd` -Wl,-no-as-needed
> -l1
> main $ cd ..
> $ ln -s test/main main
> $ ln -s test/main-hcp main-hcp
>
> So 'main' is a binary without just one RUNPATH with $ORIGIN, while 'main-hcp'
> is binary that will use a built glibc (along with the RUNPATH).
>
> Checking the library path resolution for both cases:
>
> $ LD_DEBUG=libs ./main-hcp
> 3151277: find library=lib1.so [0]; searching
> 3151277: search
> path=$GLIBCBUILDDIR/tst-bz25263/test/glibc-hwcaps/x86-64-v3:/home/azanella/Projects/glibc/build/
> x86_64-linux-gnu-work/tst-bz25263/test/glibc-hwcaps/x86-64-v2:$GLIBCBUILDDIR/tst-bz25263/test:$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v3:$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v2:$GLIBCBUILDDIR
> (RUNPATH from file ./main-hcp)
> 3151277: trying
> file=$GLIBCBUILDDIR/tst-bz25263/test/glibc-hwcaps/x86-64-v3/lib1.so
> 3151277: trying
> file=$GLIBCBUILDDIR/tst-bz25263/test/glibc-hwcaps/x86-64-v2/lib1.so
> 3151277: trying file=$GLIBCBUILDDIR/tst-bz25263/test/lib1.so
>
> LD_DEBUG=libs $GLIBCBUILDDIR/elf/ld.so --library-path $GLIBCBUILDDIR
> ./main
> 3151286: find library=lib1.so [0]; searching
> 3151286: search
> path=$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v3:$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v2:$GLIBCBUILDDIR (--library-path)
> 3151286: trying file=$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v3/lib1.so
> 3151286: trying file=$GLIBCBUILDDIR/glibc-hwcaps/x86-64-v2/lib1.so
> 3151286: trying file=$GLIBCBUILDDIR/lib1.so
> 3151286: search
> path=$GLIBCBUILDDIR/tst-bz25263/./glibc-hwcaps/x86-64-v3:$GLIBCBUILDDIR/tst-bz25263/./glibc-hwcaps/x86-64-v2:$GLIBCBUILDDIR/tst-bz25263/. (RUNPATH
> from file ./main)
> 3151286: trying
> file=$GLIBCBUILDDIR/tst-bz25263/./glibc-hwcaps/x86-64-v3/lib1.so
> 3151286: trying
> file=$GLIBCBUILDDIR/tst-bz25263/./glibc-hwcaps/x86-64-v2/lib1.so
> 3151286: trying file=$GLIBCBUILDDIR/tst-bz25263/./lib1.so
> 3151286: search cache=/etc/ld.so.cache
> 3151286: search
> path=/lib64/glibc-hwcaps/x86-64-v3:/lib64/glibc-hwcaps/x86-64-v2:/lib64:/usr/lib64/glibc-hwcaps/x86-64-v3:/usr/lib64/glibc-hwcaps/x86-64-v2:/usr/lib64 (system
> search path)
> 3151286: trying file=/lib64/glibc-hwcaps/x86-64-v3/lib1.so
> 3151286: trying file=/lib64/glibc-hwcaps/x86-64-v2/lib1.so
> 3151286: trying file=/lib64/lib1.so
> 3151286: trying file=/usr/lib64/glibc-hwcaps/x86-64-v3/lib1.so
> 3151286: trying file=/usr/lib64/glibc-hwcaps/x86-64-v2/lib1.so
> 3151286: trying file=/usr/lib64/lib1.so
>
> You can see that if the binary is not issued directly by the loader
> (main-hcp),
> it will have the full realpath on the search path
> (GLIBCBUILDDIR/tst-bz25263/test);
> different that binary issued by the loader which is has the current
> directory
> (GLIBCBUILDDIR/tst-bz25263).
This is with my patch? Directly on top of glibc-2.41 (commit db71c940
from github.com/geofft/glibc), with a checkout at /glibc and so
GLIBCBUILDDIR=/glibc/build, I get
[root@nixos:/glibc/build/tst-bz25263]# ls -l
total 0
lrwxr-xr-x 1 root root 9 Feb 28 13:37 main -> test/main
lrwxr-xr-x 1 root root 13 Feb 28 13:37 main-hcp -> test/main-hcp
drwxr-xr-x 7 root root 224 Feb 28 13:37 test
[root@nixos:/glibc/build/tst-bz25263]# readelf -d main | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [lib1.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
[root@nixos:/glibc/build/tst-bz25263]# LD_DEBUG=libs /glibc/build/elf/ld.so --library-path /glibc/build ./main
49044: find library=lib1.so [0]; searching
49044: search path=/glibc/build (--library-path)
49044: trying file=/glibc/build/lib1.so
49044: search path=/glibc/build/tst-bz25263/test:/nix/store/6j2qcdi8axcl91v08blc3vjn39y117z3-shell/lib:/nix/store/q6kvdfhlp251n8rx183lg1n245kwg6m8-glibc-2.39-52/lib:/nix/store/fxh2cg0sfgygfya6qjr11gzj4sbjx0h9-gcc-13.2.0-lib/lib (RUNPATH from file ./main)
49044: trying file=/glibc/build/tst-bz25263/test/lib1.so
49044:
49044: find library=libc.so.6 [0]; searching
49044: search path=/glibc/build (--library-path)
49044: trying file=/glibc/build/libc.so.6
[...]
which, if I'm following correctly, is the fixed behavior.
As expected it does not work with a copy instead of a symlink:
[root@nixos:/glibc/build/tst-bz25263]# cp test/main maincopy
[root@nixos:/glibc/build/tst-bz25263]# LD_DEBUG=libs /glibc/build/elf/ld.so --library-path /glibc/build ./maincopy
49073: find library=lib1.so [0]; searching
49073: search path=/glibc/build (--library-path)
49073: trying file=/glibc/build/lib1.so
49073: search path=/glibc/build/tst-bz25263:/nix/store/6j2qcdi8axcl91v08blc3vjn39y117z3-shell/lib:/nix/store/q6kvdfhlp251n8rx183lg1n245kwg6m8-glibc-2.39-52/lib:/nix/store/fxh2cg0sfgygfya6qjr11gzj4sbjx0h9-gcc-13.2.0-lib/lib (RUNPATH from file ./maincopy)
49073: trying file=/glibc/build/tst-bz25263/lib1.so
49073: trying file=/nix/store/6j2qcdi8axcl91v08blc3vjn39y117z3-shell/lib/lib1.so
49073: trying file=/nix/store/q6kvdfhlp251n8rx183lg1n245kwg6m8-glibc-2.39-52/lib/lib1.so
49073: trying file=/nix/store/fxh2cg0sfgygfya6qjr11gzj4sbjx0h9-gcc-13.2.0-lib/lib/lib1.so
49073: search cache=/root/etc/ld.so.cache
49073: search path=/root/lib (system search path)
49073: trying file=/root/lib/lib1.so
49073:
./maincopy: error while loading shared libraries: lib1.so: cannot open shared object file: No such file or directory
What commit and OS and arch are you on? (It's possible I'm confusing
myself by using NixOS, maybe.)
--
Geoffrey Thomas
geofft@ldpreload.com
More information about the Libc-alpha
mailing list