Skip to content

Commit be4f782

Browse files
committed
contrib: test for FORTIFY_SOURCE in security-check.py
1 parent 94bc3c4 commit be4f782

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

contrib/devtools/security-check.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
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.
99
'''
10+
import re
1011
import sys
1112

1213
import lief
@@ -116,6 +117,25 @@ def check_ELF_CONTROL_FLOW(binary) -> bool:
116117
return True
117118
return False
118119

120+
def check_ELF_FORTIFY(binary) -> bool:
121+
122+
# bitcoin-util does not currently contain any fortified functions
123+
if 'Bitcoin Core bitcoin-util utility version ' in binary.strings:
124+
return True
125+
126+
chk_funcs = set()
127+
128+
for sym in binary.imported_symbols:
129+
match = re.search(r'__[a-z]*_chk', sym.name)
130+
if match:
131+
chk_funcs.add(match.group(0))
132+
133+
# ignore stack-protector and bdb
134+
chk_funcs.discard('__stack_chk')
135+
chk_funcs.discard('__db_chk')
136+
137+
return len(chk_funcs) >= 1
138+
119139
def check_PE_DYNAMIC_BASE(binary) -> bool:
120140
'''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''
121141
return lief.PE.DLL_CHARACTERISTICS.DYNAMIC_BASE in binary.optional_header.dll_characteristics_lists
@@ -228,11 +248,11 @@ def check_MACHO_BRANCH_PROTECTION(binary) -> bool:
228248

229249
CHECKS = {
230250
lief.EXE_FORMATS.ELF: {
231-
lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW)],
232-
lief.ARCHITECTURES.ARM: BASE_ELF,
233-
lief.ARCHITECTURES.ARM64: BASE_ELF,
234-
lief.ARCHITECTURES.PPC: BASE_ELF,
235-
lief.ARCHITECTURES.RISCV: BASE_ELF,
251+
lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW), ('FORTIFY', check_ELF_FORTIFY)],
252+
lief.ARCHITECTURES.ARM: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)],
253+
lief.ARCHITECTURES.ARM64: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)],
254+
lief.ARCHITECTURES.PPC: BASE_ELF + [('FORTIFY', check_ELF_FORTIFY)],
255+
lief.ARCHITECTURES.RISCV: BASE_ELF, # Skip FORTIFY. See https://github.com/lief-project/LIEF/issues/1082.
236256
},
237257
lief.EXE_FORMATS.PE: {
238258
lief.ARCHITECTURES.X86: BASE_PE,

contrib/devtools/test-security-check.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,22 @@ def test_ELF(self):
5959
arch = get_arch(cxx, source, executable)
6060

6161
if arch == lief.ARCHITECTURES.X86:
62-
pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']
62+
pass_flags = ['-D_FORTIFY_SOURCE=3', '-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']
6363
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX'))
6464
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE'))
6565
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO'))
6666
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE'))
6767
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW'))
68+
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-U_FORTIFY_SOURCE']), (1, executable + ': failed FORTIFY'))
6869
self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))
6970
else:
70-
pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code']
71+
pass_flags = ['-D_FORTIFY_SOURCE=3', '-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code']
7172
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX'))
72-
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE'))
73+
# LIEF fails to parse RISC-V with no PIE correctly, and doesn't detect the fortified function,
74+
# so skip this test for RISC-V (for now). See https://github.com/lief-project/LIEF/issues/1082.
75+
if arch != lief.ARCHITECTURES.RISCV:
76+
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE'))
77+
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-U_FORTIFY_SOURCE']), (1, executable + ': failed FORTIFY'))
7378
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO'))
7479
self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE'))
7580
self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, ''))

0 commit comments

Comments
 (0)