Open ekacoei opened 2 years ago
See also https://github.com/haampie/libtree/issues/46, libtree
skips some glibc libraries because output tends to be very verbose otherwise. With libtree -v
you get the other libs too.
Okay, Java is very odd, I can't explain it yet. Using the C rewrite:
$ ./libtree /usr/bin/java
lib.so
└── libjli.so not found
┊ Paths considered in this order:
┊ 1. rpath is skipped because runpath was set
┊ 2. LD_LIBRARY_PATH was not set
┊ 3. runpath:
┊ /usr/bin//../lib/amd64/jli
┊ /usr/bin//../lib/amd64
┊ 4. ld.so.conf:
...
So, you're reading this right, java has a soname lib.so
:sweat_smile:, and a needed library libjli.so, and also runpaths, but the library can't be found from there. Also ldd chokes:
$ ldd /usr/bin/java
linux-vdso.so.1 (0x00007ffef8fac000)
libjli.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa54d940000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa54db55000)
It also has a default interpreter:
$ readelf -l /usr/bin/java | grep interpret
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
If I pass it to the interpreter:
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/java
/usr/bin/java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory
So, apparently that's not how java executes.
Okay, it turns out that ldd
output is completely unreliable for symlinks.
Note that this works:
$ ./libtree -v $(realpath /usr/bin/java)
lib.so
├── libjli.so [runpath]
│ ├── libz.so.1 [ld.so.conf]
│ │ └── libc.so.6 [ld.so.conf]
│ ├── libpthread.so.0 [ld.so.conf]
│ ├── libc.so.6 [ld.so.conf]
│ └── libdl.so.2 [ld.so.conf]
└── libc.so.6 [ld.so.conf]
$ ldd $(realpath /usr/bin/java)
linux-vdso.so.1 (0x00007ffd4b90b000)
libjli.so => /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/../lib/amd64/jli/libjli.so (0x00007f3db0e03000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3db0bf5000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f3db0bd9000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3db0bd3000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3db0bb0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3db0e1c000)
If you execute /usr/bin/java
the executable path is resolved before ld.so is invoked (from strace output), and then $ORIGIN runpaths are relative to the real path. If you invoke ld.so by hand and pass the symlink, $ORIGIN is relative to the symlink and it fails.
It seems better (but note the man ldd security warning) to do
$ LD_TRACE_LOADED_OBJECTS=1 /usr/bin/java
linux-vdso.so.1 (0x00007fffb7764000)
libjli.so => /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/../lib/amd64/jli/libjli.so (0x00007f1353f70000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1353d62000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1353d46000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1353d40000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1353d1d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1353f84000)
Not sure how to handle this best in libtree... warn if the user passes a symlink? Resolve the symlink?
Thank you for your detailed writedown, that provided me a lot of insigths. Concerning whether you shall resolve symlinks - as far as I know it is very common that libraries symlink one another to cover version compatibility
$ ls -l /usr/lib/libgimp-2.0.so.0
lrwxrwxrwx 1 root root 23 Dec 24 2018 /usr/lib/libgimp-2.0.so.0 -> libgimp-2.0.so.0.1000.8
but I could not find libgimp being loaded
$ ./libtree $(realpath $(which gimp))
gimp-2.10
├── libgimpwidgets-2.0.so.0 [default paths]
│ ├── libgimpbase-2.0.so.0 [default paths]
│ │ └── libgexiv2.so.2 [ld.so.conf]
│ │ └── libexiv2.so.14 [ld.so.conf]
│ ├── libgimpcolor-2.0.so.0 [default paths]
│ │ ├── libgimpbase-2.0.so.0 (collapsed) [default paths]
│ │ ├── libgegl-0.4.so.0 [ld.so.conf]
│ │ │ ├── libgmodule-2.0.so.0 [ld.so.conf]
│ │ │ └── libbabl-0.1.so.0 [ld.so.conf]
│ │ │ └── liblcms2.so.2 [ld.so.conf]
│ │ ├── libbabl-0.1.so.0 (collapsed) [ld.so.conf]
│ │ ├── libcairo.so.2 [ld.so.conf]
│ │ │ ├── libpixman-1.so.0 [ld.so.conf]
│ │ │ ├── libpng16.so.16 [ld.so.conf]
│ │ │ ├── libxcb-shm.so.0 [ld.so.conf]
│ │ │ ├── libxcb-render.so.0 [ld.so.conf]
│ │ │ ├── libXrender.so.1 [ld.so.conf]
│ │ │ └── libXext.so.6 [ld.so.conf]
│ │ └── liblcms2.so.2 (collapsed) [ld.so.conf]
│ ├── libgimpconfig-2.0.so.0 [default paths]
│ │ ├── libgimpbase-2.0.so.0 (collapsed) [default paths]
│ │ ├── libgimpcolor-2.0.so.0 (collapsed) [default paths]
│ │ └── libgimpmath-2.0.so.0 [default paths]
│ ├── libgegl-0.4.so.0 (collapsed) [ld.so.conf]
│ ├── libbabl-0.1.so.0 (collapsed) [ld.so.conf]
│ ├── libgtk-x11-2.0.so.0 [ld.so.conf]
│ │ ├── libgdk-x11-2.0.so.0 [ld.so.conf]
│ │ │ ├── libXrender.so.1 (collapsed) [ld.so.conf]
│ │ │ ├── libXinerama.so.1 [ld.so.conf]
│ │ │ │ └── libXext.so.6 (collapsed) [ld.so.conf]
│ │ │ ├── libXi.so.6 [ld.so.conf]
│ │ │ │ └── libXext.so.6 (collapsed) [ld.so.conf]
│ │ │ ├── libXrandr.so.2 [ld.so.conf]
│ │ │ │ ├── libXext.so.6 (collapsed) [ld.so.conf]
│ │ │ │ └── libXrender.so.1 (collapsed) [ld.so.conf]
│ │ │ ├── libXcursor.so.1 [ld.so.conf]
│ │ │ │ ├── libXrender.so.1 (collapsed) [ld.so.conf]
│ │ │ │ └── libXfixes.so.3 [ld.so.conf]
│ │ │ ├── libXcomposite.so.1 [ld.so.conf]
│ │ │ ├── libXdamage.so.1 [ld.so.conf]
│ │ │ │ └── libXfixes.so.3 (collapsed) [ld.so.conf]
│ │ │ ├── libXfixes.so.3 (collapsed) [ld.so.conf]
│ │ │ ├── libcairo.so.2 (collapsed) [ld.so.conf]
│ │ │ └── libXext.so.6 (collapsed) [ld.so.conf]
│ │ ├── libgmodule-2.0.so.0 (collapsed) [ld.so.conf]
│ │ ├── libXcomposite.so.1 (collapsed) [ld.so.conf]
│ │ ├── libXdamage.so.1 (collapsed) [ld.so.conf]
│ │ ├── libXfixes.so.3 (collapsed) [ld.so.conf]
│ │ ├── libatk-1.0.so.0 [ld.so.conf]
│ │ └── libcairo.so.2 (collapsed) [ld.so.conf]
│ ├── libgdk-x11-2.0.so.0 (collapsed) [ld.so.conf]
│ ├── libcairo.so.2 (collapsed) [ld.so.conf]
│ └── liblcms2.so.2 (collapsed) [ld.so.conf]
├── libgtk-x11-2.0.so.0 (collapsed) [ld.so.conf]
├── libgdk-x11-2.0.so.0 (collapsed) [ld.so.conf]
├── libgimpconfig-2.0.so.0 (collapsed) [default paths]
├── libgimpmath-2.0.so.0 (collapsed) [default paths]
├── libgimpthumb-2.0.so.0 [default paths]
│ └── libgimpbase-2.0.so.0 (collapsed) [default paths]
├── libgimpcolor-2.0.so.0 (collapsed) [default paths]
├── libgimpmodule-2.0.so.0 [default paths]
│ ├── libgimpbase-2.0.so.0 (collapsed) [default paths]
│ ├── libgimpconfig-2.0.so.0 (collapsed) [default paths]
│ └── libgmodule-2.0.so.0 (collapsed) [ld.so.conf]
├── libgimpbase-2.0.so.0 (collapsed) [default paths]
├── libcairo.so.2 (collapsed) [ld.so.conf]
├── libgegl-0.4.so.0 (collapsed) [ld.so.conf]
├── libgegl-npd-0.4.so [ld.so.conf]
│ ├── libgegl-0.4.so.0 (collapsed) [ld.so.conf]
│ └── libbabl-0.1.so.0 (collapsed) [ld.so.conf]
├── libbabl-0.1.so.0 (collapsed) [ld.so.conf]
├── liblcms2.so.2 (collapsed) [ld.so.conf]
├── libgexiv2.so.2 (collapsed) [ld.so.conf]
└── libmypaint-1.3.so.0 [ld.so.conf]
└── libjson-c.so.3 [ld.so.conf]
So I am lost at the moment if libtree has to handle symlinks on real world examples, including libraries as symlinks.
It only applies to executables, not to libraries, because ld.so gets the resolved executable path (I think).
$ORIGIN
is relative to the path in which the library was found, even if it is a symlink. For example if you have exe
depends on libb.so
depends on liba.so
and the libs are in the same dir with $ORIGIN
rpath, but you symlink libb.so
from another dir, and set exe
's rpath to that other dir, liba.so
is not found.
$ mkdir -p a b
$ echo 'int f(){return 3;}' | gcc -shared -o a/liba.so -Wl,-soname,liba.so -nostdlib -x c -
$ echo 'extern int f(); int g(){return f();}' | gcc -shared -o a/libb.so -Wl,-soname,libb.so '-Wl,-rpath,$ORIGIN' -nostdlib -x c - -La -la
$ ln -s ../a/libb.so b/libb.so
$ echo 'extern int g(); int main(){return g();}' | gcc -o exe '-Wl,-rpath,$ORIGIN/b' -x c - -La -lb
$ ./exe
./exe: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory
$ echo 'extern int g(); int main(){return g();}' | gcc -o exe '-Wl,-rpath,$ORIGIN/a' -x c - -La -lb
$ ./exe
[works]
Another thing to note is that the linker likes to copy the soname into DT_NEEDED instead of the filename you provide in -l<libname>
. So if linking works & rpaths are set correctly, it may still fail at runtime if there is no file/symlink matching the soname.
What is the expected output if a dependency cannot be found? I cannot resolve my Java dependencies: