1 | // RUN: %clangxx_cfi_dso_diag -std=c++11 %s -o %t |
2 | // RUN: %t zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s |
3 | // RUN: %t unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s |
4 | // RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s |
5 | |
6 | // RUN: %clangxx_cfi_diag -std=c++11 %s -o %t2 |
7 | // RUN: %t2 zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s |
8 | // RUN: %t2 unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s |
9 | // RUN: %t2 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s |
10 | |
11 | // REQUIRES: cxxabi |
12 | |
13 | // These checks are unsupported on newer versions of Android due to the |
14 | // following patch that makes it harder to defeat ASLR by not mapping unused |
15 | // shadow regions: |
16 | // https://android-review.googlesource.com/c/platform/bionic/+/1333960 |
17 | // UNSUPPORTED: android |
18 | |
19 | #include <stdio.h> |
20 | #include <stdint.h> |
21 | #include <stdlib.h> |
22 | #include <string.h> |
23 | #include <sys/mman.h> |
24 | |
25 | struct A { |
26 | virtual void f(); |
27 | }; |
28 | |
29 | void A::f() {} |
30 | |
31 | int main(int argc, char *argv[]) { |
32 | char *volatile p = reinterpret_cast<char *>(new A()); |
33 | if (argc > 1 && strcmp(s1: argv[1], s2: "unaddressable" ) == 0) { |
34 | void *vtable = mmap(addr: nullptr, len: 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, fd: 0, offset: 0); |
35 | // Create an object with a vtable in an unaddressable memory region. |
36 | *(uintptr_t *)p = (uintptr_t)vtable + 64; |
37 | // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast |
38 | // CHECK-UNADDR: note: invalid vtable |
39 | // CHECK-UNADDR: <memory cannot be printed> |
40 | // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast |
41 | // CHECK-UNADDR: note: invalid vtable |
42 | // CHECK-UNADDR: <memory cannot be printed> |
43 | } else if (argc > 1 && strcmp(s1: argv[1], s2: "zero" ) == 0) { |
44 | // Create an object with a vtable outside of any known DSO, but still in an |
45 | // addressable area. |
46 | void *vtable = calloc(nmemb: 1, size: 128); |
47 | *(uintptr_t *)p = (uintptr_t)vtable + 64; |
48 | // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast |
49 | // CHECK-ZERO: note: invalid vtable |
50 | // CHECK-ZERO: 00 00 00 00 00 00 00 00 |
51 | // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast |
52 | // CHECK-ZERO: note: invalid vtable |
53 | // CHECK-ZERO: 00 00 00 00 00 00 00 00 |
54 | } else { |
55 | // Create an object with a seemingly fine vtable, but with an unaddressable |
56 | // typeinfo pointer. |
57 | void *vtable = calloc(nmemb: 1, size: 128); |
58 | memset(s: vtable, c: 0xFE, n: 128); |
59 | *(uintptr_t *)p = (uintptr_t)vtable + 64; |
60 | // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast |
61 | // CHECK-TYPEINFO: note: invalid vtable |
62 | // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe |
63 | // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast |
64 | // CHECK-TYPEINFO: note: invalid vtable |
65 | // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe |
66 | } |
67 | |
68 | A *volatile pa = reinterpret_cast<A *>(p); |
69 | pa = reinterpret_cast<A *>(p); |
70 | } |
71 | |