1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
// Compile with /home/llozano/local2/proj/vtable/gcc-root/usr/local/bin/g++ -m32 -fvtable-verify=std -fpic -rdynamic -Wl,-R,/home/llozano/local2/proj/vtable/gcc-root/usr/local/lib32:./lib32 -I/home/llozano/local2/proj/vtable/vt2/gcc-4_6-mobile-vtable-security//libstdc++-v3/libsupc++ temp_deriv.cc -O0 -ldl -lpthread -Wl,--whole-archive,-lvtv_init,--no-whole-archive,-z,relro -DTPID=0 -g
// Look at assembly with: objdump -drl a.out
#include <dlfcn.h>
#include <assert.h>
#include <stdlib.h>
extern "C" int printf(const char *, ...);
static int counter = 0;
int i = TPID;
struct base
{
virtual void inc() { counter += i; }
};
struct derived: public base
{
virtual void inc() { counter += (10*i); }
};
// We don't use this class. It is just here so that the
// compiler does not devirtualize calls to derived::inc()
struct derived2: public derived
{
virtual void inc() { counter += (20*i); }
};
/*
static base * bp = new base();
static derived * dp = new derived();
static base * dbp = new derived();
*/
struct my_struct {
base *bp;
derived *dp;
base *dbp;
};
typedef void * vtptr;
vtptr get_vtptr(void * object_ptr)
{
vtptr * object_vtptr_ptr = (vtptr *)object_ptr;
return *object_vtptr_ptr;
}
void set_vptr(void * object_ptr, vtptr vtp)
{
vtptr * object_vtptr_ptr = (vtptr *)object_ptr;
*object_vtptr_ptr = vtp;
}
// Given 2 pointers to C++ objects (non PODs), exchange the pointers to vtable
void exchange_vtptr(void * object1_ptr, void * object2_ptr)
{
vtptr object1_vtptr = get_vtptr(object1_ptr);
vtptr object2_vtptr = get_vtptr(object2_ptr);
set_vptr(object1_ptr, object2_vtptr);
set_vptr(object2_ptr, object1_vtptr);
}
main()
{
int prev_counter;
struct my_struct *my_obj = (struct my_struct *) malloc (sizeof (struct my_struct));
my_obj->bp = new base();
my_obj->dp = new derived ();
my_obj->dbp = new derived ();
counter = 0;
my_obj->bp->inc();
my_obj->dp->inc();
my_obj->dbp->inc();
assert(counter == (TPID + 10*TPID + 10*TPID));
prev_counter = counter;
printf("before ex bp vptr=%x dp vptr=%x\n", get_vtptr(my_obj->bp), get_vtptr(my_obj->dp));
exchange_vtptr(my_obj->bp, my_obj->dp);
printf("after ex bp vptr=%x dp vptr=%x\n", get_vtptr(my_obj->bp), get_vtptr(my_obj->dp));
my_obj->bp->inc(); // This one should not abort but it is calling the wrong member
assert(counter == (prev_counter + 10*TPID));
printf("Pass first attack! Expected!\n");
printf("TPDI=%d counter %d\n", TPID, counter);
my_obj->dp->inc();
printf("Pass second attack! SHOULD NOT BE HERE!\n");
printf("TPDI=%d counter %d\n", TPID, counter);
exit(1);
}
|