diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2015-12-15 23:00:33 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2015-12-15 23:00:33 +0000 |
commit | 7a7e357f3e2b05d0d7aa2973a6d46110a94df8a3 (patch) | |
tree | 0abf00eaa4cb7ffdcca36a9258da795dc7a9315b /test/cfi | |
parent | 2dea2b0d44457345e1fcab69ed99c6c97889e055 (diff) |
Cross-DSO control flow integrity (compiler-rt part).
This is an initial version of the runtime cross-DSO CFI support
library.
It contains a number of FIXMEs, ex. it does not support the
diagnostic mode nor dlopen/dlclose, but it works and can be tested.
Diagnostic mode, in particular, would require some refactoring (we'd
like to gather all CFI hooks in the UBSan library into one function
so that we could easier pass the diagnostic information down to
__cfi_check). It will be implemented later.
Once the diagnostic mode is in, I plan to create a second test
configuration to run all existing tests in both modes. For now, this
patch includes only a few new cross-DSO tests.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@255695 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/cfi')
-rw-r--r-- | test/cfi/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/cfi/cross-dso/icall/icall-from-dso.cpp | 26 | ||||
-rw-r--r-- | test/cfi/cross-dso/icall/icall.cpp | 21 | ||||
-rw-r--r-- | test/cfi/cross-dso/icall/lit.local.cfg | 3 | ||||
-rw-r--r-- | test/cfi/cross-dso/simple-fail.cpp | 87 | ||||
-rw-r--r-- | test/cfi/cross-dso/simple-pass.cpp | 65 | ||||
-rw-r--r-- | test/cfi/lit.cfg | 5 |
7 files changed, 207 insertions, 1 deletions
diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 09672953b..c4f7eb92c 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -6,6 +6,7 @@ configure_lit_site_cfg( set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND CFI_TEST_DEPS + cfi opt ubsan ) diff --git a/test/cfi/cross-dso/icall/icall-from-dso.cpp b/test/cfi/cross-dso/icall/icall-from-dso.cpp new file mode 100644 index 000000000..1995f05f4 --- /dev/null +++ b/test/cfi/cross-dso/icall/icall-from-dso.cpp @@ -0,0 +1,26 @@ +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s + +#include <stdio.h> + +#ifdef SHARED_LIB +void g(); +void f() { + // CHECK: =1= + fprintf(stderr, "=1=\n"); + ((void (*)(void))g)(); + // CHECK: =2= + fprintf(stderr, "=2=\n"); + ((void (*)(int))g)(42); // UB here + // CHECK-NOT: =3= + fprintf(stderr, "=3=\n"); +} +#else +void f(); +void g() { +} + +int main() { + f(); +} +#endif diff --git a/test/cfi/cross-dso/icall/icall.cpp b/test/cfi/cross-dso/icall/icall.cpp new file mode 100644 index 000000000..d7cc2f9ca --- /dev/null +++ b/test/cfi/cross-dso/icall/icall.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s + +#include <stdio.h> + +#ifdef SHARED_LIB +void f() { +} +#else +void f(); +int main() { + // CHECK: =1= + fprintf(stderr, "=1=\n"); + ((void (*)(void))f)(); + // CHECK: =2= + fprintf(stderr, "=2=\n"); + ((void (*)(int))f)(42); // UB here + // CHECK-NOT: =3= + fprintf(stderr, "=3=\n"); +} +#endif diff --git a/test/cfi/cross-dso/icall/lit.local.cfg b/test/cfi/cross-dso/icall/lit.local.cfg new file mode 100644 index 000000000..db08765a2 --- /dev/null +++ b/test/cfi/cross-dso/icall/lit.local.cfg @@ -0,0 +1,3 @@ +# The cfi-icall checker is only supported on x86 and x86_64 for now. +if config.root.host_arch not in ['x86', 'x86_64']: + config.unsupported = True diff --git a/test/cfi/cross-dso/simple-fail.cpp b/test/cfi/cross-dso/simple-fail.cpp new file mode 100644 index 000000000..dda57d2a8 --- /dev/null +++ b/test/cfi/cross-dso/simple-fail.cpp @@ -0,0 +1,87 @@ +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so +// RUN: %clangxx_cfi_dso %s -o %t1 %t1-so.so +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t1 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so +// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 %t2-so.so +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t2 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so +// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 %t3-so.so +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t3 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so +// RUN: %clangxx_cfi_dso -DBM %s -o %t4 %t4-so.so +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t4 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t5-so.so +// RUN: %clangxx -DBM %s -o %t5 %t5-so.so +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s + +// Tests that the CFI mechanism crashes the program when making a virtual call +// to an object of the wrong class but with a compatible vtable, by casting a +// pointer to such an object and attempting to make a call through it. + +// REQUIRES: cxxabi + +#include <stdio.h> +#include <string.h> + +struct A { + virtual void f(); +}; + +void *create_B(); + +#ifdef SHARED_LIB + +#include "../utils.h" +struct B { + virtual void f(); +}; +void B::f() {} + +void *create_B() { + create_derivers<B>(); + return (void *)(new B()); +} + +#else + +void A::f() {} + +int main(int argc, char *argv[]) { + void *p = create_B(); + A *a; + + // CFI: =0= + // CFI-CAST: =0= + // NCFI: =0= + fprintf(stderr, "=0=\n"); + + if (argc > 1 && argv[1][0] == 'x') { + // Test cast. BOOM. + a = (A*)p; + } else { + // Invisible to CFI. Test virtual call later. + memcpy(&a, &p, sizeof(a)); + } + + // CFI: =1= + // CFI-CAST-NOT: =1= + // NCFI: =1= + fprintf(stderr, "=1=\n"); + + a->f(); // UB here + + // CFI-NOT: =2= + // CFI-CAST-NOT: =2= + // NCFI: =2= + fprintf(stderr, "=2=\n"); +} +#endif diff --git a/test/cfi/cross-dso/simple-pass.cpp b/test/cfi/cross-dso/simple-pass.cpp new file mode 100644 index 000000000..42f7a2734 --- /dev/null +++ b/test/cfi/cross-dso/simple-pass.cpp @@ -0,0 +1,65 @@ +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so +// RUN: %clangxx_cfi_dso %s -o %t1 %t1-so.so +// RUN: %t1 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so +// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 %t2-so.so +// RUN: %t2 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so +// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 %t3-so.so +// RUN: %t3 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so +// RUN: %clangxx_cfi_dso -DBM %s -o %t4 %t4-so.so +// RUN: %t4 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t5-so.so +// RUN: %clangxx -DBM %s -o %t5 %t5-so.so +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s + +// Tests that the CFI mechanism crashes the program when making a virtual call +// to an object of the wrong class but with a compatible vtable, by casting a +// pointer to such an object and attempting to make a call through it. + +// REQUIRES: cxxabi + +#include <stdio.h> +#include <string.h> + +struct A { + virtual void f(); +}; + +A *create_B(); + +#ifdef SHARED_LIB + +#include "../utils.h" +struct B : public A { + virtual void f(); +}; +void B::f() {} + +A *create_B() { + create_derivers<B>(); + return new B(); +} + +#else + +void A::f() {} + +int main(int argc, char *argv[]) { + A *a = create_B(); + + // CFI: =1= + // NCFI: =1= + fprintf(stderr, "=1=\n"); + a->f(); // OK + // CFI: =2= + // NCFI: =2= + fprintf(stderr, "=2=\n"); +} +#endif diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index a9b8992ea..687c80f4f 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -10,8 +10,11 @@ clangxx = ' '.join([config.clang] + config.cxx_mode_flags) config.substitutions.append((r"%clangxx ", clangxx + ' ')) if config.lto_supported: clangxx_cfi = ' '.join(config.lto_launch + [clangxx] + config.lto_flags + ['-flto -fsanitize=cfi ']) + clangxx_cfi_diag = clangxx_cfi + '-fno-sanitize-trap=cfi -fsanitize-recover=cfi ' config.substitutions.append((r"%clangxx_cfi ", clangxx_cfi)) - config.substitutions.append((r"%clangxx_cfi_diag ", clangxx_cfi + '-fno-sanitize-trap=cfi -fsanitize-recover=cfi ')) + config.substitutions.append((r"%clangxx_cfi_diag ", clangxx_cfi_diag)) + config.substitutions.append((r"%clangxx_cfi_dso ", clangxx_cfi + '-fsanitize-cfi-cross-dso ')) + config.substitutions.append((r"%clangxx_cfi_dso_diag ", clangxx_cfi_diag + '-fsanitize-cfi-cross-dso ')) else: config.unsupported = True |