10
10
11
11
find ../path/to/binaries -type f -executable | xargs python3 contrib/devtools/symbol-check.py
12
12
'''
13
- import subprocess
14
13
import sys
15
14
from typing import List , Optional
16
15
17
16
import lief
18
- import pixie
19
17
20
- from utils import determine_wellknown_cmd
18
+ # temporary constant, to be replaced with lief.ELF.ARCH.RISCV
19
+ # https://github.com/lief-project/LIEF/pull/562
20
+ LIEF_ELF_ARCH_RISCV = lief .ELF .ARCH (243 )
21
21
22
22
# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases
23
23
#
43
43
MAX_VERSIONS = {
44
44
'GCC' : (4 ,8 ,0 ),
45
45
'GLIBC' : {
46
- pixie . EM_386 : (2 ,17 ),
47
- pixie . EM_X86_64 : (2 ,17 ),
48
- pixie . EM_ARM : (2 ,17 ),
49
- pixie . EM_AARCH64 :(2 ,17 ),
50
- pixie . EM_PPC64 : (2 ,17 ),
51
- pixie . EM_RISCV : (2 ,27 ),
46
+ lief . ELF . ARCH . i386 : (2 ,17 ),
47
+ lief . ELF . ARCH . x86_64 : (2 ,17 ),
48
+ lief . ELF . ARCH . ARM : (2 ,17 ),
49
+ lief . ELF . ARCH . AARCH64 :(2 ,17 ),
50
+ lief . ELF . ARCH . PPC64 : (2 ,17 ),
51
+ LIEF_ELF_ARCH_RISCV : (2 ,27 ),
52
52
},
53
53
'LIBATOMIC' : (1 ,0 ),
54
54
'V' : (0 ,5 ,0 ), # xkb (bitcoin-qt only)
58
58
59
59
# Ignore symbols that are exported as part of every executable
60
60
IGNORE_EXPORTS = {
61
- '_edata' , '_end' , '__end__' , '_init' , '__bss_start' , '__bss_start__' , '_bss_end__' , '__bss_end__' , '_fini' , '_IO_stdin_used' , 'stdin' , 'stdout' , 'stderr' ,
61
+ '_edata' , '_end' , '__end__' , '_init' , '__bss_start' , '__bss_start__' , '_bss_end__' ,
62
+ '__bss_end__' , '_fini' , '_IO_stdin_used' , 'stdin' , 'stdout' , 'stderr' ,
62
63
'environ' , '_environ' , '__environ' ,
63
64
}
64
65
133
134
'WTSAPI32.dll' ,
134
135
}
135
136
136
- class CPPFilt (object ):
137
- '''
138
- Demangle C++ symbol names.
139
-
140
- Use a pipe to the 'c++filt' command.
141
- '''
142
- def __init__ (self ):
143
- self .proc = subprocess .Popen (determine_wellknown_cmd ('CPPFILT' , 'c++filt' ), stdin = subprocess .PIPE , stdout = subprocess .PIPE , universal_newlines = True )
144
-
145
- def __call__ (self , mangled ):
146
- self .proc .stdin .write (mangled + '\n ' )
147
- self .proc .stdin .flush ()
148
- return self .proc .stdout .readline ().rstrip ()
149
-
150
- def close (self ):
151
- self .proc .stdin .close ()
152
- self .proc .stdout .close ()
153
- self .proc .wait ()
154
-
155
137
def check_version (max_versions , version , arch ) -> bool :
156
- if '_' in version :
157
- (lib , _ , ver ) = version .rpartition ('_' )
158
- else :
159
- lib = version
160
- ver = '0'
138
+ (lib , _ , ver ) = version .rpartition ('_' )
161
139
ver = tuple ([int (x ) for x in ver .split ('.' )])
162
140
if not lib in max_versions :
163
141
return False
@@ -167,41 +145,42 @@ def check_version(max_versions, version, arch) -> bool:
167
145
return ver <= max_versions [lib ][arch ]
168
146
169
147
def check_imported_symbols (filename ) -> bool :
170
- elf = pixie .load (filename )
171
- cppfilt = CPPFilt ()
172
148
ok : bool = True
149
+ binary = lief .parse (filename )
173
150
174
- for symbol in elf . dyn_symbols :
175
- if not symbol .is_import :
151
+ for symbol in binary . imported_symbols :
152
+ if not symbol .imported :
176
153
continue
177
- sym = symbol .name .decode ()
178
- version = symbol .version .decode () if symbol .version is not None else None
179
- if version and not check_version (MAX_VERSIONS , version , elf .hdr .e_machine ):
180
- print ('{}: symbol {} from unsupported version {}' .format (filename , cppfilt (sym ), version ))
181
- ok = False
154
+
155
+ version = symbol .symbol_version if symbol .has_version else None
156
+
157
+ if version :
158
+ aux_version = version .symbol_version_auxiliary .name if version .has_auxiliary_version else None
159
+ if aux_version and not check_version (MAX_VERSIONS , aux_version , binary .header .machine_type ):
160
+ print (f'{ filename } : symbol { symbol .name } from unsupported version { version } ' )
161
+ ok = False
182
162
return ok
183
163
184
164
def check_exported_symbols (filename ) -> bool :
185
- elf = pixie .load (filename )
186
- cppfilt = CPPFilt ()
187
165
ok : bool = True
188
- for symbol in elf .dyn_symbols :
189
- if not symbol .is_export :
166
+ binary = lief .parse (filename )
167
+
168
+ for symbol in binary .dynamic_symbols :
169
+ if not symbol .exported :
190
170
continue
191
- sym = symbol .name . decode ()
192
- if elf . hdr . e_machine == pixie . EM_RISCV or sym in IGNORE_EXPORTS :
171
+ name = symbol .name
172
+ if binary . header . machine_type == LIEF_ELF_ARCH_RISCV or name in IGNORE_EXPORTS :
193
173
continue
194
- print ('{ }: export of symbol {} not allowed' . format ( filename , cppfilt ( sym )) )
174
+ print (f' { filename } : export of symbol { name } not allowed!' )
195
175
ok = False
196
176
return ok
197
177
198
178
def check_ELF_libraries (filename ) -> bool :
199
179
ok : bool = True
200
- elf = pixie .load (filename )
201
- for library_name in elf .query_dyn_tags (pixie .DT_NEEDED ):
202
- assert (isinstance (library_name , bytes ))
203
- if library_name .decode () not in ELF_ALLOWED_LIBRARIES :
204
- print ('{}: NEEDED library {} is not allowed' .format (filename , library_name .decode ()))
180
+ binary = lief .parse (filename )
181
+ for library in binary .libraries :
182
+ if library not in ELF_ALLOWED_LIBRARIES :
183
+ print (f'{ filename } : { library } is not in ALLOWED_LIBRARIES!' )
205
184
ok = False
206
185
return ok
207
186
0 commit comments