Strengths and weaknesses of LLVM ' s safestack Buffer Overflow PROTECTION__LLVM

Source: Internet
Author: User
IntroductionIn June 2015, a new Memory corruption exploit mitigation named Safestack is merged into the LLVM Development Branch by Pe ter Collingbourne from Google and would be available to the upcoming 3.8 release. Safestack was developed as part of the Code pointer Integrity (CPI) project but is also available as stand-alone Mitigati On. We like to stay ahead of the "curve on security" so this post aims for discuss the inner workings and the security benefits of safestack for consideration in future attacks and possible future to the improvements.

Safestack in a nutshellSafestack is a mitigation similar to (but potentially the more powerful than) Stack Cookies. It tries to protect critical data in the stack by separating the native stack into two safe stack, AREAS:A is which For control flow information as OK as data that's only ever accessed in a safe way (as determined through static Analys IS). and an unsafe stack which was used for everything else this is stored on the stack. The two stacks are located in different memory regions at the process ' s address spaces and thus prevent a buffer overflow o n the unsafe stack from corrupting anything on the safe stack.

Safestack promises a generally good protection against common stack based memory corruption attacks while introducing A low performance overhead (around 0.1% in average according to the documentation) when implemented.

When Safestack are enabled, the stack pointer register (ESP/RSP on x86/x64 respectively) would be used for the safe stack wh Ile The unsafe stack is tracked by a thread-local variable. The unsafe stack is allocated during initialization of the binary by mmap ' ing a region of readable and writable memory and Preceding this region with a guard page and presumably to catch stack overflows in the unsafe stack region.

Safestack is (currently) incompatible with Stack cookie and disables them when it is used.

implementation DetailsSafestack is implemented as a LLVM instrumentation pass, the main logic was implemented in Lib/transforms/instrumentation /safestack.cpp. The instrumentation pass runs as one of the last steps before (native) code generation.

More technically:the Instrumentation Pass works by examining all "alloca" instructions in the intermediate representatio N (IR) of a function (clang the code into LLVM's intermediate representation and later, after various InStr Umentation/optimization passes, translates the IR into machine code). An "alloca" instruction allocates spaces on the stack for a local variable or array. The Safestack instrumentation Pass then traverses the "list of instructions" make use of this variable and determines W Hether these are accesses are safe or not. If any access was determined to being "unsafe" by the instrumentation Pass, the "alloca" instruction was replaced by code that Allocates spaces on the unsafe stack instead and the instructions using the variable are updated.

The Issafestackalloc function is responsible for deciding whether a stack variable can ever being accessed in an "unsafe" WA Y. The definition of "unsafe" is currently rather conservative:a variable are relocated to the unsafe stack in the Followi Ng cases:

A pointer to the variable are stored somewhere in memory a element of A/b is accessed with a non-constant index (i.e. Another variable) A variable sized array is accessed (with constant or non-constant index) a pointer to the variable is G Iven to a function as argument
The Safestack runtime support, which is responsible for allocating and initializing the unsafe stack, can are found here. As previously mentioned, the unsafe stack is just a regular mmap ' Ed region.

exploring Safestack:implementation in PracticeLet's look in a very simple example to understand how-safestack works under the hood. For me testing I compiled CLANG/LLVM from source following this guide:

We ll use the following C code snippet:

void function (char *str) {
    char buffer[16];
    strcpy (buffer, str);

Let's start by looking in the generated assembly when no stack protection is used. For so we compile with "Clang-o1 example.c" (optimization are enabled to reduce noise)

0000000000400580 <function>:
  400580: The    EC            Sub    rsp,0x18
  400584:    F8               mov    Rax,rdi
  400587:    8d 3c    RDI,[RSP]
  40058b:    c6               mov    rsi,rax
  40058e:    e8 BD FE FF FF         call   400450 <strcpy@plt>
  400593:    c4 (            Add)    rsp,0x18
  400597:    c3                     ret

Easy enough. The function allocates spaces on the stack for the "buffer" at 400580, then calls strcpy with a pointer to the buffer at 4005 8e.

Now let's look at the assembly code generated when using Stack Cookies. For so we need to use The-fstack-protector flag (available in GCC and clang): "Clang-o1-fstack-protector example.c":

00000000004005f0 <function>:
  4005f0: The    EC            Sub    rsp,0x18
  4005f4:    F8               mov    Rax,rdi
  4005f7:    8b 0c   mov    rcx,qword PTR fs:0x28
  400600:    4c         mov    qword PTR [rsp+0x10],rcx
  400605:    8d 3c-            Lea    RDI,[RSP ]
  400609:    c6               mov    rsi,rax
  40060c:    E8 9f FE FF FF call   4004b0 < Strcpy@plt>
  400611:    8b   mov    rax,qword PTR fs:0x28
  All 40061A:    3b of         CMP    rax,qword PTR [rsp+0x10]
  40061f:                  jne    400626 < Function+0x36>
  400621:    c4            add    rsp,0x18
  400625:    c3                     ret
  400626:    E8 FE FF FF call   4004c0 <_stack_chk_fail@plt>

At 4005f7 the master cookie (the reference value of the cookies) is read to the Thread control blocks (TCB which is Thread data structure provided by LIBC) and put on the stack, below the return address. Later, at 40061a, this value is then compared and the value in the TCB before the function returns. If the two values do not match, __stack_chk_fail are called which terminates the process with a message similar to this one : "* * * Stack smashing detected * * * *:/example terminated".

Now we'll enable safestack by using The-fsanitize=safe-stack flag: "Clang-o1-fsanitize=safe-stack example.c":

0000000000410D70 <function>:
  410d70: A                  push   R14
  410d72:                     push   RBX
  410d73:                     push   rax
  410d74:   f8               mov    rax,rdi
  410d77:   4c 8b 35 6a   mov    r14,qword ptr [rip+0x20926a]
  410d7e: $   8b 1e            mov    rbx,qword ptr fs:[r14 ]
  410d82:   8d 7b F0            Lea    rdi,[rbx-0x10]
  410d86: $   3e            mov    qword PTR fs: [R14],rdi
  410d8a:   c6               mov    rsi,rax
  410d8d: E8 to   FF   FF call 400e50 <strcpy@plt>
  410d92:   1e            mov    qword PTR fs:[r14],rbx
  410d96:   08 C4            add    rsp,0x8
  410d9a:   5b                     pop    rbx
  410d9b:   5e                  pop    R14
  410d9d:   c3                     ret

At 410d7e the current value of the unsafe stack pointer be retrieved from Thread local Storage (TLS). Since Each thread also has it's own unsafe stack, the stack pointer for the unsafe stack gets stored as a thread local var Iable. Next, at 410D82, the program allocates spaces for we buffer on the unsafe thread and writes the new value back to the TLS (410d86). It then calls the strcpy function with a pointer to the unsafe stack. In the function Epilog (410d92), the old value of the unsafe stack pointer are written back to TLS (basically, these inst Ruction do the equivalent of sub RSP, X; ... add rsp, X ", but for the unsafe stack) and the function returns.

If we compile with the "-fsanitize=safe-stack option" and a overflow occurs, the saved return address (on the Safe stack) is unaffected and the program likely segfaults as it tries to write behind the unsafe stack into UNMAPPED/UNW Ritable memory.

Security Details:stack Cookies vs. SafestackWhile stack cookie provide fairly good protection against stack corruption exploits, the security measure in general has A few weaknesses. In particular, bypasses are possible in least the following scenarios:

The vulnerability in code was a non-linear overflow/arbitrary relative write on the stack. The cookie can simply be ' skipped over '. Data (e.g. function pointers) further up the stack can is corrupted and are used before the function returns.  the AT Tacker has access to a information leak. Depending on the "leak", the attacker can either leak the cookie from the stack directly or leak the Master Co Okie. Once obtained, the attacker overflows stack and overwrites the cookie again with the value obtained in the information Leak. In the case of weak entropy. If not enough entropy is available during generation of the cookie value, a attacker may being able to calculate the correct Cookie value. In the case of a forking service, the stack cookie value would stay the same for all child processes. This could make it possible to bruteforce the stack cookie value byte-by-byte, overwriting only a single byte of the cookie and observing whether the process crashes (WROng guess) or continues past the next return statement (correct guess). This would require at most 255 tries the per unknown stack cookie byte.
It is important to however, which most stack based overflows that are caused by functions operating on C strings (e.g. strcpy) are unexploitable when compiled with stack cookies enabled. As most stack cookie implementations usually force one of the bytes of the stack cookie to be a zero byte which makes Stri Ng overwriting past that impossible with a C string (it's still possible with a network buffer and raw memory copy though) .

Possible implementation bugs aside, Safestack is, at least in theory, immune to all of this due to the separation of the Memory regions.

However, what Safestack (by design) does not protect against-corruption of data on the unsafe stack. Or, phrased differently, the security of Safestack is based around the assumption this no critical the data is stored on the U Nsafe stack.

Moreover, in contrast to Stack Cookies, Safestack does not prevent the callee from corrupting data of the caller (more pre cisely, Stack Cookies prevent the caller from using the corrupted data after the callee returns). The following example demonstrates this:

void Smash_me () {
    char buffer[16];
    Gets (buffer);

int main () {
    char buffer[16];
    sizeof (buffer));
    Smash_me ();
    puts (buffer);
     return 0;

Compiling this code with "-fsanitize=safe-stack" and supplying more than bytes as input to overflow into the buffer O F Main () and corrupt its content. In contrast, where compiled with "-fstack-protector", the overflow would be detected and the process terminated main ( ) uses the corrupted buffer.
This weakness could is (partially) addressed by using Stack cookie in addition to Safestack. In this scenario, the master cookie could even is stored on the safe stack and regenerated for every function call (or Cha In of function calls). This would further protect against some of the weaknesses of plain Stack Cookies as described above.

The lack of unsafe stack protections combined with the conservativeness of the ' current definition of ' unsafe ' in the imple Mentation potentially provides a attacker with enough critical stack to unsafe the compromise. As an example, we'll devise a, more or less, realistic piece of code that would result in the (Security critical) variable ' PL ' being placed on the unsafe stack, above ' buffer ' (although it seems this enabling the optimization during compilation CA Uses less variables to is placed on the unsafe stack):

void Determine_privilege_level (int *pl) {
    //dummy function
    *pl = 0x42;

int main () {
    int pl;
    Char buffer[16];
    Determine_privilege_level (&PL);
    Gets (buffer);             This can overflow and corrupt ' pl '
    printf ("Privilege level:%x\ n", pl);
     return 0;

This ' data-only ' attack is possible due to the fact ' that ' current implementation never recurses into called functions B UT rather considers (most) function arguments as unsafe.

The risk of corrupting critical data on the unsafe stack can however is greatly decreased through improved static analysis , variable reordering, and, as mentioned above, by protecting the callee ' s unsafe stack frame.

It should also be noted this current implementation does not protect the safe stack in any other way besides system le Vel ASLR. This means is information leak combined with a arbitrary write primitive'll still allow a attacker to overwrite T He return address (or other data) on the safe stack. The comment at the top of the runtime support implementation for more information. Finally We should mention there has been a academic study that points out some additional detail regarding CPI.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.