scripts: add MACHO PIE check to security-check.py

pull/764/head
fanquake 5 years ago
parent 35fff5be60
commit 4ca92dc6d3
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1

@ -98,7 +98,7 @@ repository (requires pngcrush).
security-check.py and test-security-check.py security-check.py and test-security-check.py
============================================ ============================================
Perform basic ELF security checks on a series of executables. Perform basic security checks on a series of executables.
symbol-check.py symbol-check.py
=============== ===============

@ -3,10 +3,10 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
''' '''
Perform basic ELF security checks on a series of executables. Perform basic security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent. Exit status will be 0 if successful, and the program will be silent.
Otherwise the exit status will be 1 and it will log which executables failed which checks. Otherwise the exit status will be 1 and it will log which executables failed which checks.
Needs `readelf` (for ELF) and `objdump` (for PE). Needs `readelf` (for ELF), `objdump` (for PE) and `otool` (for MACHO).
''' '''
import subprocess import subprocess
import sys import sys
@ -14,6 +14,7 @@ import os
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
NONFATAL = {} # checks which are non-fatal for now but only generate a warning NONFATAL = {} # checks which are non-fatal for now but only generate a warning
def check_ELF_PIE(executable): def check_ELF_PIE(executable):
@ -162,6 +163,31 @@ def check_PE_NX(executable):
(arch,bits) = get_PE_dll_characteristics(executable) (arch,bits) = get_PE_dll_characteristics(executable)
return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
def get_MACHO_executable_flags(executable):
p = subprocess.Popen([OTOOL_CMD, '-vh', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
flags = []
for line in stdout.splitlines():
tokens = line.split()
# filter first two header lines
if 'magic' in tokens or 'Mach' in tokens:
continue
# filter ncmds and sizeofcmds values
flags += [t for t in tokens if not t.isdigit()]
return flags
def check_MACHO_PIE(executable) -> bool:
'''
Check for position independent executable (PIE), allowing for address space randomization.
'''
flags = get_MACHO_executable_flags(executable)
if 'PIE' in flags:
return True
return False
CHECKS = { CHECKS = {
'ELF': [ 'ELF': [
('PIE', check_ELF_PIE), ('PIE', check_ELF_PIE),
@ -173,6 +199,9 @@ CHECKS = {
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
('NX', check_PE_NX) ('NX', check_PE_NX)
],
'MACHO': [
('PIE', check_MACHO_PIE),
] ]
} }
@ -183,6 +212,8 @@ def identify_executable(executable):
return 'PE' return 'PE'
elif magic.startswith(b'\x7fELF'): elif magic.startswith(b'\x7fELF'):
return 'ELF' return 'ELF'
elif magic.startswith(b'\xcf\xfa'):
return 'MACHO'
return None return None
if __name__ == '__main__': if __name__ == '__main__':

@ -137,6 +137,7 @@ script: |
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS}
make ${MAKEOPTS} make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
make install-strip DESTDIR=${INSTALLPATH} make install-strip DESTDIR=${INSTALLPATH}
make osx_volname make osx_volname

@ -710,7 +710,7 @@ endif
check-security: $(bin_PROGRAMS) check-security: $(bin_PROGRAMS)
if HARDEN if HARDEN
@echo "Checking binary security..." @echo "Checking binary security..."
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
endif endif
if EMBEDDED_LEVELDB if EMBEDDED_LEVELDB

Loading…
Cancel
Save