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, ''))
Beispiel #2
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'))
Beispiel #4
0
    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)
Beispiel #5
0
    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, ''))
Beispiel #7
0
 def __init__(self):
     self.proc = subprocess.Popen(determine_wellknown_cmd(
         'CPPFILT', 'c++filt'),
                                  stdin=subprocess.PIPE,
                                  stdout=subprocess.PIPE,
                                  universal_newlines=True)
Beispiel #8
0
    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)
Beispiel #9
0
    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)