| // { dg-do run } |
| |
| #include <assert.h> |
| #include <signal.h> |
| #include <setjmp.h> |
| #include <stdio.h> |
| |
| #include <iostream> |
| #include <fstream> |
| |
| using std::ofstream; |
| using std::ifstream; |
| using std::ios; |
| |
| struct A { |
| A():value(123) {} |
| int value; |
| virtual int access() { return this->value; } |
| }; |
| struct B { |
| B():value(456) {} |
| int value; |
| virtual int access() { return this->value; } |
| }; |
| struct C : public A, public B { |
| C():better_value(789) {} |
| int better_value; |
| virtual int access() { return this->better_value; } |
| }; |
| struct D: public C { |
| D():other_value(987) {} |
| int other_value; |
| virtual int access() { return this->other_value; } |
| }; |
| |
| volatile static int signal_count = 0; |
| |
| sigjmp_buf before_segv; |
| |
| static void |
| handler(int sig, siginfo_t *si, void *unused) |
| { |
| /* |
| printf("Got SIGSEGV at address: 0x%lx\n", |
| (long) si->si_addr); |
| */ |
| |
| signal_count++; |
| /* You are not supposed to longjmp out of a signal handler but it seems |
| to work for this test case and it simplifies it */ |
| siglongjmp(before_segv, 1); |
| /* exit(1); */ |
| } |
| |
| /* Access one of the vtable_map variables generated by this .o */ |
| extern void * _ZN4_VTVI1BE12__vtable_mapE; |
| |
| /* Access one of the vtable_map variables generated by libstdc++ */ |
| extern void * _ZN4_VTVISt8ios_baseE12__vtable_mapE; |
| |
| int use(B *b) |
| { |
| int ret; |
| |
| ret = sigsetjmp(before_segv, 1); |
| if (ret == 0) |
| { |
| /* This should generate a segmentation violation. ie: at this point it should |
| be protected */ |
| _ZN4_VTVI1BE12__vtable_mapE = 0; |
| } |
| assert(ret == 1 && signal_count == 1); |
| |
| ret = sigsetjmp(before_segv, 1); |
| if (ret == 0) |
| { |
| /* Try to modify one of the vtable_map variables in the stdc++ library. |
| This should generate a segmentation violation. ie: at this point it |
| should be protected */ |
| _ZN4_VTVISt8ios_baseE12__vtable_mapE = 0; |
| } |
| assert(ret == 1 && signal_count == 2); |
| |
| return b->access(); |
| } |
| |
| void myread(std::istream * in) |
| { |
| char input_str[50] = "\0"; |
| if (in->good()) |
| (*in) >> input_str; |
| std::cout << input_str << std::endl; |
| delete in; |
| } |
| |
| int main() |
| { |
| ifstream * infile = new ifstream("./thunk_vtable_map_attack.cpp"); |
| myread(infile); |
| |
| /* Set up handler for SIGSEGV. */ |
| struct sigaction sa; |
| sa.sa_flags = SA_SIGINFO; |
| sigemptyset(&sa.sa_mask); |
| sa.sa_sigaction = handler; |
| if (sigaction(SIGSEGV, &sa, NULL) == -1) |
| assert(0); |
| |
| C c; |
| assert(use(&c) == 789); |
| |
| return 0; |
| } |