3
3
import tempfile
4
4
5
5
from ..elf import get_shobj_deps , is_dynamic , LddError
6
+ from ..errors import Error , UnsupportedRpathError , UnsupportedRunpathError
6
7
from ..utils import make_executable , mkdirs_for
7
8
8
9
def process_pyinstaller_archive (sx ):
@@ -44,9 +45,15 @@ def __exit__(self, *exc_info):
44
45
45
46
def process (self ):
46
47
binaries = self ._extract_binaries ()
48
+
49
+ # These could be Python libraries, shared object dependencies, or
50
+ # anything else a user might add via `binaries` in the .spec file.
51
+ # Filter out everything except dynamic ELFs
52
+ binaries = [b for b in binaries if is_dynamic (b )]
53
+
54
+ self ._audit_libs (binaries )
55
+
47
56
for binary in binaries :
48
- # These could be Python libraries, shared object dependencies, or
49
- # anything else a user might add via `binaries` in the .spec file.
50
57
self ._add_required_deps (binary )
51
58
52
59
@@ -69,32 +76,41 @@ def _extract_binaries(self):
69
76
with open (tmppath , 'wb' ) as f :
70
77
f .write (data )
71
78
79
+ # Silence "you do not have execution permission" warning from ldd
80
+ make_executable (tmppath )
81
+
72
82
# We can't use yield here, because we need all of the libraries to be
73
83
# extracted prior to running ldd (see #61)
74
84
result .append (tmppath )
75
85
76
86
return result
77
87
88
+ def _audit_libs (self , libs ):
89
+ """Audit the dynamic libraries included in the PyInstaller archive"""
90
+ errors = []
91
+ for lib in libs :
92
+ # Check for RPATH/RUNPATH, but only "dangerous" values and let
93
+ # "harmless" values pass (e.g. "$ORIGIN/cffi.libs")
94
+ try :
95
+ self .sx .check_library_rpath (lib , dangerous_only = True )
96
+ except (UnsupportedRpathError , UnsupportedRunpathError ) as e :
97
+ # Unfortunately, there's no easy way to fix an UnsupportedRunpathError
98
+ # here, because staticx is not about to to modify the library and
99
+ # re-pack the PyInstaller archive itself.
100
+ errors .append (e )
101
+
102
+ if errors :
103
+ msg = "Unsupported PyInstaller input\n \n "
104
+ msg += "One or more libraries included in the PyInstaller"
105
+ msg += " archive uses unsupported RPATH/RUNPATH tags:\n \n "
106
+ for e in errors :
107
+ msg += " {}: {}={!r}\n " .format (e .libpath , e .tag , e .value )
108
+ msg += "\n See https://github.com/JonathonReinhart/staticx/issues/188"
109
+ raise Error (msg )
78
110
79
111
def _add_required_deps (self , lib ):
80
112
"""Add dependencies of lib to staticx archive"""
81
113
82
- # Verify this is a shared library
83
- if not is_dynamic (lib ):
84
- # It's okay if there's a static executable in the PyInstaller
85
- # archive. See issue #78
86
- return
87
-
88
- # Silence "you do not have execution permission" warning from ldd
89
- make_executable (lib )
90
-
91
- # Check for RPATH/RUNPATH, but only "dangerous" values and let
92
- # "harmless" values pass (e.g. "$ORIGIN/cffi.libs")
93
- self .sx .check_library_rpath (lib , dangerous_only = True )
94
- # Unfortunately, there's no easy way to fix an UnsupportedRunpathError
95
- # here, because staticx is not about to to modify the library and
96
- # re-pack the PyInstaller archive itself.
97
-
98
114
# Try to get any dependencies of this file
99
115
try :
100
116
deps = get_shobj_deps (lib , libpath = [self .tmpdir .name ])
0 commit comments