def test_PE(self): source = 'test1.c' executable = 'test1.exe' cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') with open(source, 'w', encoding="utf8") as f: f.write(''' #include <pdh.h> int main() { PdhConnectMachineA(NULL); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1' ]), (1, 'pdh.dll is not in ALLOWED_LIBRARIES!\n' + executable + ': failed DYNAMIC_LIBRARIES')) source = 'test2.c' executable = 'test2.exe' with open(source, 'w', encoding="utf8") as f: f.write(''' int main() { return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9' ]), (1, executable + ': failed SUBSYSTEM_VERSION')) source = 'test3.c' executable = 'test3.exe' with open(source, 'w', encoding="utf8") as f: f.write(''' #include <windows.h> int main() { CoFreeUnusedLibrariesEx(0,0); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1' ]), (0, ''))
def test_PE(self): source = 'test1.c' executable = 'test1.exe' cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') write_testcode(source) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--disable-nxcompat', '-Wl,--disable-reloc-section', '-Wl,--disable-dynamicbase', '-Wl,--disable-high-entropy-va', '-no-pie', '-fno-PIE' ]), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW' )) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--disable-reloc-section', '-Wl,--disable-dynamicbase', '-Wl,--disable-high-entropy-va', '-no-pie', '-fno-PIE' ]), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW' )) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--disable-dynamicbase', '-Wl,--disable-high-entropy-va', '-no-pie', '-fno-PIE' ]), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--disable-dynamicbase', '-Wl,--disable-high-entropy-va', '-pie', '-fPIE' ]), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW') ) # -pie -fPIE does nothing unless --dynamicbase is also supplied self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--disable-high-entropy-va', '-pie', '-fPIE' ]), (1, executable + ': failed HIGH_ENTROPY_VA CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--high-entropy-va', '-pie', '-fPIE' ]), (1, executable + ': failed CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--high-entropy-va', '-pie', '-fPIE', '-fcf-protection=full' ]), (0, '')) clean_files(source, executable)
def test_MACHO(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'clang') with open(source, 'w', encoding="utf8") as f: f.write(''' #include <expat.h> int main() { XML_ExpatVersion(); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-lexpat', '-Wl,-platform_version', '-Wl,macos', '-Wl,11.4', '-Wl,11.4' ]), (1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' + f'{executable}: failed DYNAMIC_LIBRARIES MIN_OS SDK')) source = 'test2.c' executable = 'test2' with open(source, 'w', encoding="utf8") as f: f.write(''' #include <CoreGraphics/CoreGraphics.h> int main() { CGMainDisplayID(); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-framework', 'CoreGraphics', '-Wl,-platform_version', '-Wl,macos', '-Wl,11.4', '-Wl,11.4' ]), (1, f'{executable}: failed MIN_OS SDK')) source = 'test3.c' executable = 'test3' with open(source, 'w', encoding="utf8") as f: f.write(''' int main() { return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, [ '-Wl,-platform_version', '-Wl,macos', '-Wl,10.15', '-Wl,11.4' ]), (1, f'{executable}: failed SDK'))
def test_MACHO(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'clang') write_testcode(source) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-Wl,-allow_stack_execute', '-fno-stack-protector' ]), (1, executable + ': failed PIE NOUNDEFS NX LAZY_BINDINGS Canary CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-Wl,-allow_stack_execute', '-fstack-protector-all' ]), (1, executable + ': failed PIE NOUNDEFS NX LAZY_BINDINGS CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-fstack-protector-all' ]), (1, executable + ': failed PIE NOUNDEFS LAZY_BINDINGS CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, ['-Wl,-no_pie', '-fstack-protector-all']), (1, executable + ': failed PIE LAZY_BINDINGS CONTROL_FLOW')) self.assertEqual( call_security_check( cc, source, executable, ['-Wl,-no_pie', '-Wl,-bind_at_load', '-fstack-protector-all']), (1, executable + ': failed PIE CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-bind_at_load', '-fstack-protector-all', '-fcf-protection=full' ]), (1, executable + ': failed PIE')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-pie', '-Wl,-bind_at_load', '-fstack-protector-all', '-fcf-protection=full' ]), (0, '')) clean_files(source, executable)
def test_ELF(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'gcc') write_testcode(source) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE NX RELRO Canary')) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO Canary')) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), (1, executable+': failed PIE RELRO')) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), (1, executable+': failed RELRO')) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), (1, executable+': failed separate_code')) self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), (0, '')) clean_files(source, executable)
def test_ELF(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'gcc') # there's no way to do this test for RISC-V at the moment; we build for # RISC-V in a glibc 2.27 envinonment and we allow all symbols from 2.27. if 'riscv' in get_machine(cc): self.skipTest("test not available for RISC-V") # nextup was introduced in GLIBC 2.24, so is newer than our supported # glibc (2.17), and available in our release build environment (2.24). with open(source, 'w', encoding="utf8") as f: f.write(''' #define _GNU_SOURCE #include <math.h> double nextup(double x); int main() { nextup(3.14); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, ['-lm']), (1, executable + ': symbol nextup from unsupported version GLIBC_2.24\n' + executable + ': failed IMPORTED_SYMBOLS')) # -lutil is part of the libc6 package so a safe bet that it's installed # it's also out of context enough that it's unlikely to ever become a real dependency source = 'test2.c' executable = 'test2' with open(source, 'w', encoding="utf8") as f: f.write(''' #include <utmp.h> int main() { login(0); return 0; } ''') self.assertEqual( call_symbol_check(cc, source, executable, ['-lutil']), (1, executable + ': NEEDED library libutil.so.1 is not allowed\n' + executable + ': failed LIBRARY_DEPENDENCIES')) # finally, check a simple conforming binary source = 'test3.c' executable = 'test3' with open(source, 'w', encoding="utf8") as f: f.write(''' #include <stdio.h> int main() { printf("42"); return 0; } ''') self.assertEqual(call_symbol_check(cc, source, executable, []), (0, ''))
def __init__(self): self.proc = subprocess.Popen(determine_wellknown_cmd( 'CPPFILT', 'c++filt'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
def test_ELF(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'gcc') write_testcode(source) arch = get_arch(cc, source, executable) if arch == lief.ARCHITECTURES.X86: self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-zexecstack', '-fno-stack-protector', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE NX RELRO Canary CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fno-stack-protector', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE RELRO Canary CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE RELRO CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-znorelro', '-pie', '-fPIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed RELRO CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,noseparate-code' ]), (1, executable + ': failed separate_code CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full' ]), (0, '')) else: self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-zexecstack', '-fno-stack-protector', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE NX RELRO Canary')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fno-stack-protector', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE RELRO Canary')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-znorelro', '-no-pie', '-fno-PIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed PIE RELRO')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-znorelro', '-pie', '-fPIE', '-Wl,-z,separate-code' ]), (1, executable + ': failed RELRO')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,noseparate-code' ]), (1, executable + ': failed separate_code')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-znoexecstack', '-fstack-protector-all', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code' ]), (0, '')) clean_files(source, executable)
def test_MACHO(self): source = 'test1.c' executable = 'test1' cc = determine_wellknown_cmd('CC', 'clang') write_testcode(source) arch = get_arch(cc, source, executable) if arch == lief.ARCHITECTURES.X86: self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-Wl,-allow_stack_execute', '-fno-stack-protector' ]), (1, executable + ': failed NOUNDEFS LAZY_BINDINGS Canary PIE NX CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-Wl,-allow_stack_execute', '-fstack-protector-all' ]), (1, executable + ': failed NOUNDEFS LAZY_BINDINGS PIE NX CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-flat_namespace', '-fstack-protector-all' ]), (1, executable + ': failed NOUNDEFS LAZY_BINDINGS PIE CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, ['-Wl,-no_pie', '-fstack-protector-all']), (1, executable + ': failed LAZY_BINDINGS PIE CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-bind_at_load', '-fstack-protector-all' ]), (1, executable + ': failed PIE CONTROL_FLOW')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-no_pie', '-Wl,-bind_at_load', '-fstack-protector-all', '-fcf-protection=full' ]), (1, executable + ': failed PIE')) self.assertEqual( call_security_check(cc, source, executable, [ '-Wl,-pie', '-Wl,-bind_at_load', '-fstack-protector-all', '-fcf-protection=full' ]), (0, '')) else: # arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks self.assertEqual( call_security_check( cc, source, executable, ['-Wl,-flat_namespace', '-fno-stack-protector']), (1, executable + ': failed NOUNDEFS LAZY_BINDINGS Canary')) self.assertEqual( call_security_check( cc, source, executable, ['-Wl,-flat_namespace', '-fstack-protector-all']), (1, executable + ': failed NOUNDEFS LAZY_BINDINGS')) self.assertEqual( call_security_check(cc, source, executable, ['-fstack-protector-all']), (1, executable + ': failed LAZY_BINDINGS')) self.assertEqual( call_security_check( cc, source, executable, ['-Wl,-bind_at_load', '-fstack-protector-all']), (0, '')) clean_files(source, executable)