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

Audit libraries to check for problematic RPATH/RUNPATH when building #173

Merged
merged 17 commits into from
Oct 4, 2021

Conversation

JonathonReinhart
Copy link
Owner

@JonathonReinhart JonathonReinhart commented Apr 18, 2021

This PR audits all libraries included (directly by staticx or indirectly as part of a PyInstaller archive) for use of DT_RPATH/DT_RUNPATH which is problematic as described in #169.

RPATH/RUNPATH are removed from the libraries when possible, which does not apply to libraries already part of a PyInstaller archive:

RPATH RUNPATH
In a library being added as a dependency 🧹 Removed 🧹 Removed
In a library already part of PyInstaller archive ⚠️ ... ❌ Forbidden

Those libraries are examined to determine is the RPATH/RUNPATH is problematic. RUNPATH is always forbidden, as detailed in #169. RPATH is allowed unless it is deemed "dangerous":

RPATH in a library already part of PyInstaller archive...
Absolute path ❌ Forbidden
Path relative to working dir ❌ Forbidden
Path relative to $ORIGIN (below) ✔️
Path relative to $ORIGIN (above) ❌ Forbidden

Problematic uses which cannot be corrected will point the user at #188.

Closes #172.
See #169.

staticx/api.py Outdated Show resolved Hide resolved
@JonathonReinhart
Copy link
Owner Author

Based on this conversation with myself, I went ahead and started treating RPATH and RUNPATH exactly the same.

Because this is more likely and wide-reaching that I initially thought, I also went ahead and added patchelf --remove-rpath in StaticxGenerator.add_library() to "fix" the problematic libraries. Note that we cannot (easily) do this for libraries already in the PyInstaller archive.


Now, an existing test (test/pyinstall-cffi/) is failing, as it should:

staticx.errors.UnsupportedRpathError: /tmp/staticx-pyi-znqc4zfi/_cffi_backend.cpython-39-x86_64-linux-gnu.so uses unsupported DT_RPATH ('$ORIGIN/cffi.libs').

Confirmed with readelf:

$ readelf -d ./venv/lib/python3.9/site-packages/_cffi_backend.cpython-39-x86_64-linux-gnu.so

Dynamic section at offset 0xd2000 contains 28 entries:
  Tag        Type                         Name/Value
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/cffi.libs]
 0x0000000000000001 (NEEDED)             Shared library: [libffi-c643fa1a.so.6.0.4]
 ...

$ ls -l venv/lib/python3.9/site-packages/cffi.libs/
total 48K
-rwxr-xr-x 1 jreinhart jreinhart 46K Oct  3 03:14 libffi-c643fa1a.so.6.0.4

This RPATH is harmless because it is relative (down) from $ORIGIN, so it won't break out of our extracted "jail". (It's also unnecessary, as noted in #61 (comment)).

So I think I'll also have to implement the second part of this self-suggestion which is to check for "dangerous" rpaths. Otherwise, staticx will fail on a bunch of stuff unnecessarily.

staticx cannot currently handle any libraries that have DT_RUNPATH set as
it interferes with our ability to fully control the library paths.

See #169
This will let us do other things prior to get_shobj_deps() which assume
the file is a shared library
RPATH is also problematic. While RUNPATH will immediately kill the
top-level RPATH with set, RPATH on a library can defeat our "jail" and
cause target-system libraries to be loaded.
Since staticx has already discovered dependencies of the library
(because ldd is effectively recursive), and (like Pyinstaller) will
flatten all dependencies when they're tar-ed up and extracted, there's
no reason we can't just drop the RPATH/RUNPATH entry.

This also renames audit_library to check_library_rpath. I don't want
this function to sound too generic, since we're catching exceptions and
carrying on. Otherwise, we might "fix" an initial problem but then miss
the remaining problems.
We now treat RPATH and RUNPATH (in added dependent libraries) the same by
fixing (removing) them.

It's the RPATH/RUNPATH in PyInstaller bundled libraries that is an
unfixable problem, so we'll have to add another test, sigh.
A primary example of this is _cffi_backend.cpython-39-x86_64-linux-gnu.so
which has RPATH = "$ORIGIN/cffi.libs" which doesn't matter because
PyInstaller flattens the dependencies anyway. But we allow it because it
is relative to $ORIGIN.
@JonathonReinhart JonathonReinhart changed the title Audit libraries to check for problematic RUNPATH when building Audit libraries to check for problematic RPATH/RUNPATH when building Oct 4, 2021
@JonathonReinhart JonathonReinhart merged commit 2ba0f8a into master Oct 4, 2021
@JonathonReinhart JonathonReinhart deleted the 172-audit-libs-for-RUNPATH branch October 4, 2021 02:16
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

Successfully merging this pull request may close these issues.

Audit libraries to check for problematic RUNPATH when building
1 participant