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/cross-dso | |
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/cross-dso')
-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 |
5 files changed, 202 insertions, 0 deletions
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 |