Skip to content

vijeth-aradhya/safe-shadow-stack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Safe ShadowCallStack Impl

This is a Dynamorio client that maintains a return address (and stack pointer) shadow stack of a program. In case of buffer overflows, there is a control-flow transfer (to the adversary) through overwriting the return address on the stack. This client, during execution of the program, compares the return address of the current function with the top of the shadow stack (that is protected by the Dynamorio memory), right before the ret instruction is executed.

Additionally, this dr client also handles longjmp(). In particular, there are two cases: (1) backward jumps, and (2) forward jumps. longjmps are typically used as a clever error handling / debugging technique. Forward jumps (usually) exhibit undefined behaviour, and therefore, should be handled carefully (exits with 139, indicating seg fault). On the other hand, backward jump, i.e., a jump from the current function to a previous function on the stack, is perfectly fine. And, these cases should be differentiated from a buffer overflow case, as in both cases, the return addresses (shadow return address and current-go-to return address) are different.

To do this, this dr client uses drvector (in drcontainers) to store both the return address and the value of the stack pointer (right before the call instruction is executed). An important observation is that, when the program returns from the callee (to be specific, after the execution of leave instruction), the stack pointer is updated so that it still points to the top of the stack, after the program returns to caller. Thus, the difference between the xsp in the callee (check during ret) and xsp in the caller (on the shadow stack) is always <= 8.

Notice that, in case of buffer overflow attacks, the return address does not match, but the stack pointer does match. But, in case of longjmp, both the return address and stack pointer values do not match!

For someone who is new to DBI and Dynamorio, I recommend, running libcountcalls.so or libinstrcalls.so dr client with a simple helloworld C program; read the source code to get an idea about dr_api.h.

Safety

shadowcallstack makes use of Dynamorio's safe thread-local storage; you can read more about Dynamorio's code cache and its safety in their tutorial (Page 129 onwards), or in their doc. In thid dr client, drvectors and files are stored in the reachable thread-specfic storage in drcontext.

Some of the protections in Dynamrio (see this too):

  • ASLR of its memory: code cache, heap, and stack
  • Guard pages around every memory block: cache, heap, and stack
  • Dynamrio stack starts from the base again each time

Using

  • Set DYNAMORIO_HOME to the dynamrio directory (in build.sh)
  • Set SHADOWCALLSTACK_DIR to this project directory
  • ./build.sh builds the dr client
  • To use the client, drrun -c $SHADOWCALLSTACK_DIR/build/libshadowcallstack.so -- <program>

Testing

  • bin/run_tests is currently used to run the client against different tests

Benchmarks

Program Program without DynamoRio Program with vanilla Dynamorio Program with ShadowCallStack
echo 0.000 0.094 0.154
touch 0.004 0.087 0.142
md5sum 0.005 0.093 0.162
who 0.005 0.109 0.211
pwd 0.000 0.081 0.136

Notes

☑ Handling multi-threading

☑ Handling longjmp

☑ Add extensive test suite

  • Note: In addition to the basic tests, the following programs in coreutils were run (on benign inputs) with shadowcallstack client: md5sum, who, ls, echo, uname, pwd, touch.
  • Of course, more complicated test cases in longjmp_progs and exploit_progs category should be added.

☑ Add benchmark results

System

  • Operating System: Ubuntu 16.04.6 LTS
  • Cmake version: 3.14.7
  • Architecture: x86-64
  • Dynamorio version: 7.91.18229

Helpful Blogs

Some Readings

  1. https://clang.llvm.org/docs/ShadowCallStack.html#security
  2. https://security.stackexchange.com/questions/185125/how-to-protect-the-shadow-stack
  3. https://www.phoronix.com/scan.php?page=news_item&px=LLVM-Drops-ShadowCallStack-x64
  4. https://en.wikipedia.org/wiki/Shadow_stack
  5. x86-64 cheatsheet; compiling loops using jmp