From b4285d03da3d87ef366aae522f089bd886563126 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 25 Mar 2020 15:32:39 +0100 Subject: [PATCH] Merge #18395: scripts: add PE dylib checking to symbol-check.py 1a0993ae354c36d6f219e67f82ca8236530d6201 scripts: add PE dylib checking to symbol-check.py (fanquake) Pull request description: Uses `objdump -x` and looks for `DLL Name:` lines. i.e: ```bash objdump -x src/qt/bitcoin-qt.exe | grep "DLL Name:" DLL Name: ADVAPI32.dll DLL Name: dwmapi.dll DLL Name: GDI32.dll DLL Name: IMM32.dll DLL Name: IPHLPAPI.DLL DLL Name: KERNEL32.dll DLL Name: msvcrt.dll DLL Name: ole32.dll DLL Name: OLEAUT32.dll DLL Name: SHELL32.dll DLL Name: SHLWAPI.dll DLL Name: USER32.dll DLL Name: UxTheme.dll DLL Name: VERSION.dll DLL Name: WINMM.dll DLL Name: WS2_32.dll ``` ACKs for top commit: dongcarl: Concept ACK 1a0993ae354c36d6f219e67f82ca8236530d6201 hebasto: ACK 1a0993ae354c36d6f219e67f82ca8236530d6201, tested on Linux Mint 19.3: Tree-SHA512: 0099a50e2c616d5239a15cafa9a7c483e9c40244af41549e4738be0f5360f27a2afb956eb50b47cf446b242f4cfc6dc9d111306a056fb83789eefbd71eddabd2 --- contrib/devtools/README.md | 2 +- contrib/devtools/symbol-check.py | 51 ++++++++++++++++++++++- contrib/gitian-descriptors/gitian-win.yml | 1 + src/Makefile.am | 5 +++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index 357767b0ae..c9860d83bc 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -170,7 +170,7 @@ certain symbols and are only linked against allowed libraries. For Linux this means checking for allowed gcc, glibc and libstdc++ version symbols. This makes sure they are still compatible with the minimum supported distribution versions. -For macOS we check that the executables are only linked against libraries we allow. +For macOS and Windows we check that the executables are only linked against libraries we allow. Example usage after a Gitian build: diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index be3969061a..aafdd80789 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -4,8 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' A script to check that the (Linux) release executables only contain -allowed gcc and glibc version symbols. This makes sure they are still compatible -with the minimum supported Linux distribution versions. +certain symbols and are only linked against allowed libraries. Example usage: @@ -57,6 +56,7 @@ IGNORE_EXPORTS = { 'environ', '_environ', '__environ', } CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') +OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool') # Allowed NEEDED libraries @@ -107,6 +107,30 @@ MACHO_ALLOWED_LIBRARIES = { 'QuartzCore', # animation } +PE_ALLOWED_LIBRARIES = { +'ADVAPI32.dll', # security & registry +'IPHLPAPI.DLL', # IP helper API +'KERNEL32.dll', # win32 base APIs +'msvcrt.dll', # C standard library for MSVC +'SHELL32.dll', # shell API +'USER32.dll', # user interface +'WS2_32.dll', # sockets +'bcrypt.dll', +# bitcoin-qt only +'dwmapi.dll', # desktop window manager +'GDI32.dll', # graphics device interface +'IMM32.dll', # input method editor +'NETAPI32.dll', +'ole32.dll', # component object model +'OLEAUT32.dll', # OLE Automation API +'SHLWAPI.dll', # light weight shell API +'USERENV.dll', +'UxTheme.dll', +'VERSION.dll', # version checking +'WINMM.dll', # WinMM audio API +'WTSAPI32.dll', +} + class CPPFilt(object): ''' Demangle C++ symbol names. @@ -200,6 +224,26 @@ def check_MACHO_libraries(filename) -> bool: ok = False return ok +def pe_read_libraries(filename) -> List[str]: + p = subprocess.Popen([OBJDUMP_CMD, '-x', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + libraries = [] + for line in stdout.splitlines(): + if 'DLL Name:' in line: + tokens = line.split(': ') + libraries.append(tokens[1]) + return libraries + +def check_PE_libraries(filename) -> bool: + ok = True + for dylib in pe_read_libraries(filename): + if dylib not in PE_ALLOWED_LIBRARIES: + print('{} is not in ALLOWED_LIBRARIES!'.format(dylib)) + ok = False + return ok + CHECKS = { 'ELF': [ ('IMPORTED_SYMBOLS', check_imported_symbols), @@ -208,6 +252,9 @@ CHECKS = { ], 'MACHO': [ ('DYNAMIC_LIBRARIES', check_MACHO_libraries) +], +'PE' : [ + ('DYNAMIC_LIBRARIES', check_PE_libraries) ] } diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 0a6ddfacdd..9faa6057bd 100755 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -159,6 +159,7 @@ script: | CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security + make ${MAKEOPTS} -C src check-symbols make deploy BITCOIN_WIN_INSTALLER="${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe" make install DESTDIR=${INSTALLPATH} cd installed diff --git a/src/Makefile.am b/src/Makefile.am index 970fb38312..39ba9af3ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -938,6 +938,11 @@ if TARGET_DARWIN $(AM_V_at) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) endif +if TARGET_WINDOWS + @echo "Checking Windows dynamic libraries..." + $(AM_V_at) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) +endif + if GLIBC_BACK_COMPAT @echo "Checking glibc back compat..." $(AM_V_at) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)