Skip to content

Commit a25b2e9

Browse files
committed
contrib: use LIEF for macOS security checks
1 parent 7e7eae7 commit a25b2e9

File tree

1 file changed

+12
-42
lines changed

1 file changed

+12
-42
lines changed

contrib/devtools/security-check.py

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
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 `objdump` (for PE) and `otool` (for MACHO).
9+
Needs `objdump` (for PE).
1010
'''
1111
import subprocess
1212
import sys
1313
import os
1414
from typing import List, Optional
1515

16+
import lief
1617
import pixie
1718

1819
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
19-
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
2020

2121
def run_command(command) -> str:
2222
p = subprocess.run(command, stdout=subprocess.PIPE, check=True, universal_newlines=True)
@@ -184,71 +184,41 @@ def check_PE_NX(executable) -> bool:
184184
bits = get_PE_dll_characteristics(executable)
185185
return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
186186

187-
def get_MACHO_executable_flags(executable) -> List[str]:
188-
stdout = run_command([OTOOL_CMD, '-vh', executable])
189-
190-
flags: List[str] = []
191-
for line in stdout.splitlines():
192-
tokens = line.split()
193-
# filter first two header lines
194-
if 'magic' in tokens or 'Mach' in tokens:
195-
continue
196-
# filter ncmds and sizeofcmds values
197-
flags += [t for t in tokens if not t.isdigit()]
198-
return flags
199-
200187
def check_MACHO_PIE(executable) -> bool:
201188
'''
202189
Check for position independent executable (PIE), allowing for address space randomization.
203190
'''
204-
flags = get_MACHO_executable_flags(executable)
205-
if 'PIE' in flags:
206-
return True
207-
return False
191+
binary = lief.parse(executable)
192+
return binary.is_pie
208193

209194
def check_MACHO_NOUNDEFS(executable) -> bool:
210195
'''
211196
Check for no undefined references.
212197
'''
213-
flags = get_MACHO_executable_flags(executable)
214-
if 'NOUNDEFS' in flags:
215-
return True
216-
return False
198+
binary = lief.parse(executable)
199+
return binary.header.has(lief.MachO.HEADER_FLAGS.NOUNDEFS)
217200

218201
def check_MACHO_NX(executable) -> bool:
219202
'''
220203
Check for no stack execution
221204
'''
222-
flags = get_MACHO_executable_flags(executable)
223-
if 'ALLOW_STACK_EXECUTION' in flags:
224-
return False
225-
return True
205+
binary = lief.parse(executable)
206+
return binary.has_nx
226207

227208
def check_MACHO_LAZY_BINDINGS(executable) -> bool:
228209
'''
229210
Check for no lazy bindings.
230211
We don't use or check for MH_BINDATLOAD. See #18295.
231212
'''
232-
stdout = run_command([OTOOL_CMD, '-l', executable])
233-
234-
for line in stdout.splitlines():
235-
tokens = line.split()
236-
if 'lazy_bind_off' in tokens or 'lazy_bind_size' in tokens:
237-
if tokens[1] != '0':
238-
return False
239-
return True
213+
binary = lief.parse(executable)
214+
return binary.dyld_info.lazy_bind == (0,0)
240215

241216
def check_MACHO_Canary(executable) -> bool:
242217
'''
243218
Check for use of stack canary
244219
'''
245-
stdout = run_command([OTOOL_CMD, '-Iv', executable])
246-
247-
ok = False
248-
for line in stdout.splitlines():
249-
if '___stack_chk_fail' in line:
250-
ok = True
251-
return ok
220+
binary = lief.parse(executable)
221+
return binary.has_symbol('___stack_chk_fail')
252222

253223
CHECKS = {
254224
'ELF': [

0 commit comments

Comments
 (0)