Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| #include <cstdio> | |
| #include <cstdlib> | |
| #include <cstdint> | |
| #include <intrin.h> | |
| using namespace std; | |
| typedef int (*int_arg_fn)(int); | |
| typedef int (*float_arg_fn)(float); | |
| static int int_arg(int arg) { | |
| printf("In %s: (%d)\n", __FUNCTION__, arg); | |
| return 0; | |
| } | |
| static int float_arg(float arg) { | |
| printf("CFG will not protect a transfer to here (but clang's CFI would)\n"); | |
| printf("In %s: (%f)\n", __FUNCTION__, (double)arg); | |
| return 0; | |
| } | |
| static int bad_int_arg(int arg) { | |
| printf("CFG will not protect transfer to here\n"); | |
| printf("In %s: (%d)\n", __FUNCTION__, arg); | |
| return 0; | |
| } | |
| static int not_entry_point(int arg) { | |
| // nop sled for x86 / x86-64 | |
| // these instructions act as a buffer | |
| // for an indirect control flow transfer to skip | |
| // a valid function entry point, but continue | |
| // to execute normal code | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); | |
| printf("CFG ensures control flow only transfers to potentially valid destinations\n"); | |
| printf("In %s: (%d)\n", __FUNCTION__, arg); | |
| // need to exit or the program will segfault anyway, | |
| // since the indirect call skipped the function preamble | |
| exit(arg); | |
| } | |
| struct foo { | |
| int_arg_fn int_funcs[1]; | |
| int_arg_fn bad_int_funcs[1]; | |
| float_arg_fn float_funcs[1]; | |
| int_arg_fn not_entries[1]; | |
| }; | |
| // the struct aligns the function pointer arrays | |
| // so indexing past the end will reliably | |
| // call working function pointers | |
| static struct foo f = { {int_arg}, {bad_int_arg}, {float_arg}, {(int_arg_fn)((uintptr_t)(not_entry_point)+0x20)} }; | |
| int main(int argc, const char *argv[]) { | |
| if(argc != 2) { | |
| printf("Usage: %s <option>\n", argv[0]); | |
| printf("Option values:\n"); | |
| printf("\t0\tCall correct function\n"); | |
| printf("\t1\tCall the wrong function but with the same signature\n"); | |
| printf("\t2\tCall a float function with an int function signature\n"); | |
| printf("\t3\tCall into the middle of a function\n"); | |
| printf("\n"); | |
| printf("\tAll other options are undefined, but should be caught by CFG :)\n"); | |
| printf("\n\n"); | |
| printf("Here are some pointers so members of `struct foo f` are not optimized away:\n"); | |
| printf("\tint_funcs: %p\n", (void*)f.int_funcs); | |
| printf("\tbad_int_funcs: %p\n", (void*)f.bad_int_funcs); | |
| printf("\tfloat_funcs: %p\n", (void*)f.float_funcs); | |
| printf("\tnot_entries: %p\n", (void*)f.not_entries); | |
| return 1; | |
| } | |
| printf("Calling a function:\n"); | |
| int idx = argv[1][0] - '0'; | |
| return f.int_funcs[idx](idx); | |
| } |