Intro
I ran into an issue the other day with an executable not finding a library it depended on. I found where the library was and attempted to set LD_LIBRARY_PATH
to get it on path for the executable. This had no effect. A little more digging led me to RPATH
which I hadn’t heard of til this point. It turn’s out that RPATH takes precedence and can’t be overridden by LD_LIBRARY_PATH
. Here’s how it factors into things and some tips that helped me in the process.
Library Resolution
Here’s loosely how it works, library resolution occurs in this order of precedence:
RPATH
: variable encoded directly in the binary/library at compile time, or modified after- note —
RPATH
is deprecated because it’s hardcoded in the executable and can’t be overridden by the user short of modifying the executable itself
- note —
LD_LIBRARY_PATH
: environment variableRUNPATH
: variable encoded direcctly in the binary/library at compile time, or modified after- note —
RUNPATH
is now the preferred alternative to RPATH. It can be overridden by a user viaLD_LIBRARY_PATH
- note —
- Cache File /etc/ld.so.cache
- In the default path /lib , /lib64 and then /usr/lib , /usr/lib64.
SETUID
When you use setuid to modify the user and/or group that an executable is run as (often this is done to give priviledged access via root), certain environment variables also don’t carry across this threshold due to security concerns. They are as follows:
LD_LIBRARY_PATH
LD_PROFILE
LD_PROFILE_OUTPUT
LD_AUDIT
LD_DEBUG
LD_DEBUG_OUTPUT
Tips + Tricks
- Print out the libraries a binary depends on:
LD_DEBUG=libs ldd <EXE/LIB>
LD_DEBUG=libs
adds the search paths that ldd is using to resolve the libraries.
- Print out the tree of dependencies:
lddtree <EXE/LIB>
- Library resolution can be a recursive search, this helps understand it in a tree format
- Overriding RPATH/RUNPATH:
patchelf --set-rpath 'PATH1:PATH2' <EXE/LIB>
- Reading RPATH/RUNPATH from a binary/library:
objdump -x <EXE/LIB> | grep "R*PATH"