Skip to content

Commit 309eac9

Browse files
fanquakedongcarl
andcommitted
scripts: use LIEF for ELF checks in symbol-check.py
Co-authored-by: Carl Dong <[email protected]>
1 parent 610a8a8 commit 309eac9

File tree

5 files changed

+38
-72
lines changed

5 files changed

+38
-72
lines changed

Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,5 +376,5 @@ if TARGET_WINDOWS
376376
endif
377377
if TARGET_LINUX
378378
$(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF
379-
$(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' CPPFILT='$(CPPFILT)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF
379+
$(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF
380380
endif

configure.ac

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ AC_PATH_PROG([GIT], [git])
113113
AC_PATH_PROG(CCACHE,ccache)
114114
AC_PATH_PROG(XGETTEXT,xgettext)
115115
AC_PATH_PROG(HEXDUMP,hexdump)
116-
AC_PATH_TOOL(CPPFILT, c++filt)
117116
AC_PATH_TOOL(OBJCOPY, objcopy)
118117
AC_PATH_PROG(DOXYGEN, doxygen)
119118
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])

contrib/devtools/symbol-check.py

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
1111
find ../path/to/binaries -type f -executable | xargs python3 contrib/devtools/symbol-check.py
1212
'''
13-
import subprocess
1413
import sys
1514
from typing import List, Optional
1615

1716
import lief
18-
import pixie
1917

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)
2121

2222
# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases
2323
#
@@ -43,12 +43,12 @@
4343
MAX_VERSIONS = {
4444
'GCC': (4,8,0),
4545
'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),
5252
},
5353
'LIBATOMIC': (1,0),
5454
'V': (0,5,0), # xkb (bitcoin-qt only)
@@ -58,7 +58,8 @@
5858

5959
# Ignore symbols that are exported as part of every executable
6060
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',
6263
'environ', '_environ', '__environ',
6364
}
6465

@@ -133,31 +134,8 @@
133134
'WTSAPI32.dll',
134135
}
135136

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-
155137
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('_')
161139
ver = tuple([int(x) for x in ver.split('.')])
162140
if not lib in max_versions:
163141
return False
@@ -167,41 +145,42 @@ def check_version(max_versions, version, arch) -> bool:
167145
return ver <= max_versions[lib][arch]
168146

169147
def check_imported_symbols(filename) -> bool:
170-
elf = pixie.load(filename)
171-
cppfilt = CPPFilt()
172148
ok: bool = True
149+
binary = lief.parse(filename)
173150

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:
176153
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
182162
return ok
183163

184164
def check_exported_symbols(filename) -> bool:
185-
elf = pixie.load(filename)
186-
cppfilt = CPPFilt()
187165
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:
190170
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:
193173
continue
194-
print('{}: export of symbol {} not allowed'.format(filename, cppfilt(sym)))
174+
print(f'{filename}: export of symbol {name} not allowed!')
195175
ok = False
196176
return ok
197177

198178
def check_ELF_libraries(filename) -> bool:
199179
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!')
205184
ok = False
206185
return ok
207186

contrib/devtools/test-symbol-check.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def test_ELF(self):
6060
''')
6161

6262
self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
63-
(1, executable + ': symbol nextup from unsupported version GLIBC_2.24\n' +
63+
(1, executable + ': symbol nextup from unsupported version GLIBC_2.24(3)\n' +
6464
executable + ': failed IMPORTED_SYMBOLS'))
6565

6666
# -lutil is part of the libc6 package so a safe bet that it's installed
@@ -79,7 +79,7 @@ def test_ELF(self):
7979
''')
8080

8181
self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
82-
(1, executable + ': NEEDED library libutil.so.1 is not allowed\n' +
82+
(1, executable + ': libutil.so.1 is not in ALLOWED_LIBRARIES!\n' +
8383
executable + ': failed LIBRARY_DEPENDENCIES'))
8484

8585
# finally, check a simple conforming binary

src/Makefile.am

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -808,20 +808,8 @@ clean-local:
808808
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
809809

810810
check-symbols: $(bin_PROGRAMS)
811-
if TARGET_DARWIN
812-
@echo "Checking macOS dynamic libraries..."
811+
@echo "Running symbol and dynamic library checks..."
813812
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
814-
endif
815-
816-
if TARGET_WINDOWS
817-
@echo "Checking Windows dynamic libraries..."
818-
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
819-
endif
820-
821-
if TARGET_LINUX
822-
@echo "Checking glibc back compat..."
823-
$(AM_V_at) CPPFILT='$(CPPFILT)' $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
824-
endif
825813

826814
check-security: $(bin_PROGRAMS)
827815
if HARDEN

0 commit comments

Comments
 (0)