1*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so
2*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso %s -o %t1
3*7c3d14c8STreehugger Robot // RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s
4*7c3d14c8STreehugger Robot // RUN: %expect_crash %t1 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
5*7c3d14c8STreehugger Robot // RUN: %expect_crash %t1 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
6*7c3d14c8STreehugger Robot
7*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so
8*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DB32 %s -o %t2
9*7c3d14c8STreehugger Robot // RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s
10*7c3d14c8STreehugger Robot // RUN: %expect_crash %t2 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
11*7c3d14c8STreehugger Robot // RUN: %expect_crash %t2 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
12*7c3d14c8STreehugger Robot
13*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so
14*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DB64 %s -o %t3
15*7c3d14c8STreehugger Robot // RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s
16*7c3d14c8STreehugger Robot // RUN: %expect_crash %t3 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
17*7c3d14c8STreehugger Robot // RUN: %expect_crash %t3 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
18*7c3d14c8STreehugger Robot
19*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so
20*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DBM %s -o %t4
21*7c3d14c8STreehugger Robot // RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s
22*7c3d14c8STreehugger Robot // RUN: %expect_crash %t4 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s
23*7c3d14c8STreehugger Robot // RUN: %expect_crash %t4 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
24*7c3d14c8STreehugger Robot
25*7c3d14c8STreehugger Robot // RUN: %clangxx -g -DBM -DSHARED_LIB -DNOCFI %s -fPIC -shared -o %t5-so.so
26*7c3d14c8STreehugger Robot // RUN: %clangxx -g -DBM -DNOCFI %s -ldl -o %t5
27*7c3d14c8STreehugger Robot // RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s
28*7c3d14c8STreehugger Robot // RUN: %t5 cast 2>&1 | FileCheck --check-prefix=NCFI %s
29*7c3d14c8STreehugger Robot // RUN: %t5 dlclose 2>&1 | FileCheck --check-prefix=NCFI %s
30*7c3d14c8STreehugger Robot
31*7c3d14c8STreehugger Robot // Test that calls to uninstrumented library are unchecked.
32*7c3d14c8STreehugger Robot // RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t6-so.so
33*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -DBM %s -o %t6
34*7c3d14c8STreehugger Robot // RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s
35*7c3d14c8STreehugger Robot // RUN: %t6 cast 2>&1 | FileCheck --check-prefix=NCFI %s
36*7c3d14c8STreehugger Robot
37*7c3d14c8STreehugger Robot // Call-after-dlclose is checked on the caller side.
38*7c3d14c8STreehugger Robot // RUN: %expect_crash %t6 dlclose 2>&1 | FileCheck --check-prefix=CFI %s
39*7c3d14c8STreehugger Robot
40*7c3d14c8STreehugger Robot // Tests calls into dlopen-ed library.
41*7c3d14c8STreehugger Robot // REQUIRES: cxxabi
42*7c3d14c8STreehugger Robot
43*7c3d14c8STreehugger Robot #include <assert.h>
44*7c3d14c8STreehugger Robot #include <dlfcn.h>
45*7c3d14c8STreehugger Robot #include <stdio.h>
46*7c3d14c8STreehugger Robot #include <stdint.h>
47*7c3d14c8STreehugger Robot #include <string.h>
48*7c3d14c8STreehugger Robot #include <sys/mman.h>
49*7c3d14c8STreehugger Robot
50*7c3d14c8STreehugger Robot #include <string>
51*7c3d14c8STreehugger Robot
52*7c3d14c8STreehugger Robot struct A {
53*7c3d14c8STreehugger Robot virtual void f();
54*7c3d14c8STreehugger Robot };
55*7c3d14c8STreehugger Robot
56*7c3d14c8STreehugger Robot #ifdef SHARED_LIB
57*7c3d14c8STreehugger Robot
58*7c3d14c8STreehugger Robot #include "../utils.h"
59*7c3d14c8STreehugger Robot struct B {
60*7c3d14c8STreehugger Robot virtual void f();
61*7c3d14c8STreehugger Robot };
f()62*7c3d14c8STreehugger Robot void B::f() {}
63*7c3d14c8STreehugger Robot
create_B()64*7c3d14c8STreehugger Robot extern "C" void *create_B() {
65*7c3d14c8STreehugger Robot create_derivers<B>();
66*7c3d14c8STreehugger Robot return (void *)(new B());
67*7c3d14c8STreehugger Robot }
68*7c3d14c8STreehugger Robot
do_nothing()69*7c3d14c8STreehugger Robot extern "C" __attribute__((aligned(4096))) void do_nothing() {}
70*7c3d14c8STreehugger Robot
71*7c3d14c8STreehugger Robot #else
72*7c3d14c8STreehugger Robot
f()73*7c3d14c8STreehugger Robot void A::f() {}
74*7c3d14c8STreehugger Robot
75*7c3d14c8STreehugger Robot static const int kCodeAlign = 4096;
76*7c3d14c8STreehugger Robot static const int kCodeSize = 4096;
77*7c3d14c8STreehugger Robot static char saved_code[kCodeSize];
78*7c3d14c8STreehugger Robot static char *real_start;
79*7c3d14c8STreehugger Robot
save_code(char * p)80*7c3d14c8STreehugger Robot static void save_code(char *p) {
81*7c3d14c8STreehugger Robot real_start = (char *)(((uintptr_t)p) & ~(kCodeAlign - 1));
82*7c3d14c8STreehugger Robot memcpy(saved_code, real_start, kCodeSize);
83*7c3d14c8STreehugger Robot }
84*7c3d14c8STreehugger Robot
restore_code()85*7c3d14c8STreehugger Robot static void restore_code() {
86*7c3d14c8STreehugger Robot char *code = (char *)mmap(real_start, kCodeSize, PROT_WRITE | PROT_EXEC,
87*7c3d14c8STreehugger Robot MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
88*7c3d14c8STreehugger Robot assert(code == real_start);
89*7c3d14c8STreehugger Robot memcpy(code, saved_code, kCodeSize);
90*7c3d14c8STreehugger Robot }
91*7c3d14c8STreehugger Robot
main(int argc,char * argv[])92*7c3d14c8STreehugger Robot int main(int argc, char *argv[]) {
93*7c3d14c8STreehugger Robot const bool test_cast = argc > 1 && strcmp(argv[1], "cast") == 0;
94*7c3d14c8STreehugger Robot const bool test_dlclose = argc > 1 && strcmp(argv[1], "dlclose") == 0;
95*7c3d14c8STreehugger Robot
96*7c3d14c8STreehugger Robot std::string name = std::string(argv[0]) + "-so.so";
97*7c3d14c8STreehugger Robot void *handle = dlopen(name.c_str(), RTLD_NOW);
98*7c3d14c8STreehugger Robot assert(handle);
99*7c3d14c8STreehugger Robot void *(*create_B)() = (void *(*)())dlsym(handle, "create_B");
100*7c3d14c8STreehugger Robot assert(create_B);
101*7c3d14c8STreehugger Robot
102*7c3d14c8STreehugger Robot void *p = create_B();
103*7c3d14c8STreehugger Robot A *a;
104*7c3d14c8STreehugger Robot
105*7c3d14c8STreehugger Robot // CFI: =0=
106*7c3d14c8STreehugger Robot // CFI-CAST: =0=
107*7c3d14c8STreehugger Robot // NCFI: =0=
108*7c3d14c8STreehugger Robot fprintf(stderr, "=0=\n");
109*7c3d14c8STreehugger Robot
110*7c3d14c8STreehugger Robot if (test_cast) {
111*7c3d14c8STreehugger Robot // Test cast. BOOM.
112*7c3d14c8STreehugger Robot a = (A*)p;
113*7c3d14c8STreehugger Robot } else {
114*7c3d14c8STreehugger Robot // Invisible to CFI. Test virtual call later.
115*7c3d14c8STreehugger Robot memcpy(&a, &p, sizeof(a));
116*7c3d14c8STreehugger Robot }
117*7c3d14c8STreehugger Robot
118*7c3d14c8STreehugger Robot // CFI: =1=
119*7c3d14c8STreehugger Robot // CFI-CAST-NOT: =1=
120*7c3d14c8STreehugger Robot // NCFI: =1=
121*7c3d14c8STreehugger Robot fprintf(stderr, "=1=\n");
122*7c3d14c8STreehugger Robot
123*7c3d14c8STreehugger Robot if (test_dlclose) {
124*7c3d14c8STreehugger Robot // Imitate an attacker sneaking in an executable page where a dlclose()d
125*7c3d14c8STreehugger Robot // library was loaded. This needs to pass w/o CFI, so for the testing
126*7c3d14c8STreehugger Robot // purpose, we just copy the bytes of a "void f() {}" function back and
127*7c3d14c8STreehugger Robot // forth.
128*7c3d14c8STreehugger Robot void (*do_nothing)() = (void (*)())dlsym(handle, "do_nothing");
129*7c3d14c8STreehugger Robot assert(do_nothing);
130*7c3d14c8STreehugger Robot save_code((char *)do_nothing);
131*7c3d14c8STreehugger Robot
132*7c3d14c8STreehugger Robot int res = dlclose(handle);
133*7c3d14c8STreehugger Robot assert(res == 0);
134*7c3d14c8STreehugger Robot
135*7c3d14c8STreehugger Robot restore_code();
136*7c3d14c8STreehugger Robot
137*7c3d14c8STreehugger Robot do_nothing(); // UB here
138*7c3d14c8STreehugger Robot } else {
139*7c3d14c8STreehugger Robot a->f(); // UB here
140*7c3d14c8STreehugger Robot }
141*7c3d14c8STreehugger Robot
142*7c3d14c8STreehugger Robot // CFI-NOT: =2=
143*7c3d14c8STreehugger Robot // CFI-CAST-NOT: =2=
144*7c3d14c8STreehugger Robot // NCFI: =2=
145*7c3d14c8STreehugger Robot fprintf(stderr, "=2=\n");
146*7c3d14c8STreehugger Robot }
147*7c3d14c8STreehugger Robot #endif
148