Skip to content

Commit 4ca92dc

Browse files
committed
scripts: add MACHO PIE check to security-check.py
1 parent 35fff5b commit 4ca92dc

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

contrib/devtools/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ repository (requires pngcrush).
9898
security-check.py and test-security-check.py
9999
============================================
100100

101-
Perform basic ELF security checks on a series of executables.
101+
Perform basic security checks on a series of executables.
102102

103103
symbol-check.py
104104
===============

contrib/devtools/security-check.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
'''
6-
Perform basic ELF security checks on a series of executables.
6+
Perform basic security checks on a series of executables.
77
Exit status will be 0 if successful, and the program will be silent.
88
Otherwise the exit status will be 1 and it will log which executables failed which checks.
9-
Needs `readelf` (for ELF) and `objdump` (for PE).
9+
Needs `readelf` (for ELF), `objdump` (for PE) and `otool` (for MACHO).
1010
'''
1111
import subprocess
1212
import sys
1313
import os
1414

1515
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
1616
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
17+
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
1718
NONFATAL = {} # checks which are non-fatal for now but only generate a warning
1819

1920
def check_ELF_PIE(executable):
@@ -162,6 +163,31 @@ def check_PE_NX(executable):
162163
(arch,bits) = get_PE_dll_characteristics(executable)
163164
return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
164165

166+
def get_MACHO_executable_flags(executable):
167+
p = subprocess.Popen([OTOOL_CMD, '-vh', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
168+
(stdout, stderr) = p.communicate()
169+
if p.returncode:
170+
raise IOError('Error opening file')
171+
172+
flags = []
173+
for line in stdout.splitlines():
174+
tokens = line.split()
175+
# filter first two header lines
176+
if 'magic' in tokens or 'Mach' in tokens:
177+
continue
178+
# filter ncmds and sizeofcmds values
179+
flags += [t for t in tokens if not t.isdigit()]
180+
return flags
181+
182+
def check_MACHO_PIE(executable) -> bool:
183+
'''
184+
Check for position independent executable (PIE), allowing for address space randomization.
185+
'''
186+
flags = get_MACHO_executable_flags(executable)
187+
if 'PIE' in flags:
188+
return True
189+
return False
190+
165191
CHECKS = {
166192
'ELF': [
167193
('PIE', check_ELF_PIE),
@@ -173,6 +199,9 @@ def check_PE_NX(executable):
173199
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
174200
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
175201
('NX', check_PE_NX)
202+
],
203+
'MACHO': [
204+
('PIE', check_MACHO_PIE),
176205
]
177206
}
178207

@@ -183,6 +212,8 @@ def identify_executable(executable):
183212
return 'PE'
184213
elif magic.startswith(b'\x7fELF'):
185214
return 'ELF'
215+
elif magic.startswith(b'\xcf\xfa'):
216+
return 'MACHO'
186217
return None
187218

188219
if __name__ == '__main__':

contrib/gitian-descriptors/gitian-osx.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ script: |
137137
138138
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS}
139139
make ${MAKEOPTS}
140+
make ${MAKEOPTS} -C src check-security
140141
make install-strip DESTDIR=${INSTALLPATH}
141142
142143
make osx_volname

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ endif
710710
check-security: $(bin_PROGRAMS)
711711
if HARDEN
712712
@echo "Checking binary security..."
713-
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
713+
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
714714
endif
715715

716716
if EMBEDDED_LEVELDB

0 commit comments

Comments
 (0)