Thursday, March 27, 2014

Hardening against stack corruptions


Stack is hardened against corruption by protecting the sanity of stack using gcc flags.

  • -fstack-protector: When compiled with this option, gcc 
    • Adds additional protective code to vulnerable functions. This code adds a canary variable before the return function address. With such protection, a buffer overrun is likely corrupt the canary first before being able to reach the return function address. So, the protective code verifies the sanity of canary before returning. If canary is corrupt, then the program is instead aborted with error indicating stack corruption.
    • re-orders stack variables so that buffers are placed after pointers & hence reducing the possibility of corrupted pointers corrupting other memory.

This mechanism is applied only to vulnerable functions - the functions with character array >= 8 bytes. This value can be tuned using --param=ssp-buffer-size=N option.

The cost of this protective mechanism is reduced performance and increased binary size .

This flag is available in gcc from 4.1 version. If you have a gcc version less than 4.1, then stack protection feature should be backported. you can apply the ProPolice/StackGuard patches. I have never done such patching. 

History of -fstack-protector:
IBM implemented this mechanism as StackGuard &introduced it as patches to gcc version 2.7. Then IBM improved this idea in ProPolice by reorganizing stack variable to detect pointer corruption. Then, RedHat re-implemented all this to introduce -fstack-protection (and -fstack-protection-all discussed below) in gcc version 4.1

  • -fstack-protector-all: This is same as -fstack-protector, but applied to all function rather than just vulnerable functions.
  • -fstack-protector-strong: -fstack-protector is available only for functions with character arrays & -fstack-protector-all is an overkill for performance. -fstack-protetion-strong extend this protective mechanism to functions with any type of arrays & length: structs/unions/char/.. So, essentially, this option increases the scope of protection mechanism to more vulnerable functions without having to enable it on every function (the way -f-stack-protector-all does) & hence provides better balance of stack corruption detection and performance cost. This option is contributed by Google to gcc & is available in gcc version 4.9 onwards. If your gcc version is <4.9, you can apply the path at http://gcc.gnu.org/ml/gcc-patches/2012-06/msg00974.html to your gcc. Looks like Google enabled this option in Chrome OS by default.

<<compare increase in function coverage & binary size with -fstack-protector vs -fstack-protector-string>>> - TBD.

How to build user space applications stack protection flags?
gcc -fstack-protector <c_file> 

Some distribution like Ubuntu & Fedora Core enable this option by default in gcc.

How to disable stack protections flags enabled by default in user space applications?
gcc -fno-stack-protector <c_file> 

How to build kernel or kernel modules stack protection flags?
Linux kernel has this mechanism only for some architectures. For x86:
  • kernels < 2.6.19 don't have stack protection mechanism
  • -fstack-protection is available in linux kernels >= 2.6.19 
    • CONFIG_CC_STACKPROTECTOR: enables -fstack-protection. By default, stack protection is disabled
  • -fstack-protection-strong & -fstack-protection is available in linux kernels >=3.14
    • CONFIG_CC_STACKPROTECTOR_NONE: default value & doesn't enable any stack protection
    • CONFIG_CC_STACKPROTECTOR_STRONG: enables -fstack-protection-strong
    • CONFIG_CC_STACKPROTECTOR_REGULAR: enables -fstack-protector
For other architectures, check the diff for this compile flag at http://lxr.linux.no and attempt porting. I haven't done so yet & so I don't know the challenges involved. Looks like its NOT simply a matter of which version of gcc & gcc flags you compile the kernel with.
 

Do we need to enable in kernel to use it for kernel modules?
TBD.


References:



No comments:

UA-48797665-1