I was recently been asked by a friend how the Linux’s stack canary values work. After performing a quick online research I wasn’t able to find anything useful to give him. So, here is my writing on how GNU C Library stack canary values work. :)

WARNING: There is no exploitation information in this post. Just the GLIBC’s stack canary value’s functionality.



Let’s have a look at this dummy C code…

xorl:~$ cat ahoy.c #include <stdio.h> int main(void) { return printf("Ahoy!

"); } xorl:~$

We’ll compile it using the -fstack-protector-all to force GCC into using the Stack Smashing Protection features it has.

xorl:~$ gcc -fstack-protector-all ahoy.c -o ahoy -ggdb2 xorl:~$ ./ahoy Ahoy! xorl:~$ gdb -q ./ahoy (gdb)

Now it’s time to understand the code. So, here we are…

(gdb) disas main 0x080483f4 <main+0>: lea 0x4(%esp),%ecx 0x080483f8 <main+4>: and $0xfffffff0,%esp 0x080483fb <main+7>: pushl -0x4(%ecx) 0x080483fe <main+10>: push %ebp 0x080483ff <main+11>: mov %esp,%ebp 0x08048401 <main+13>: push %ecx 0x08048402 <main+14>: sub $0x14,%esp

Since this post is mostly written for people that are just getting started with system’s internals, I’ll explain everything. The address of the stack pointer at an offset of 0x4 is loaded to ECX, then stack pointer is aligned and the original stack pointer (ECX-4) is pushed into the stack. Then, the well known function prologue takes place. The current base pointer (indicating a new stack frame) is pushed onto the stack and value of the stack pointer is placed in the base pointer. Next, the current value of ECX (containing the original stack pointer’s value) is also pushed on the stack and stack pointer is decremented by 0x14 in order to make sufficient space for the function.

0x08048405 <main+17>: mov %gs:0x14,%eax 0x0804840b <main+23>: mov %eax,-0x8(%ebp) 0x0804840e <main+26>: xor %eax,%eax

This is the actual stack canary code in the binary. It will obtain the canary’s value from ‘%gs:0x14’ and store it in EAX register. It will then place it on the stack just after the stored, previously constructed stack frame. Then EAX is zeroed out since the canary value has no reason in being left there.

0x08048410 <main+28>: movl $0x8048500,(%esp) 0x08048417 <main+35>: call 0x8048320 <printf@plt>

This is the actual program that places the contents of the 0x8048500 to the stack and invokes printf(3) from the available PLT (the Procedure Linkage Table) entry. Obviously…

(gdb) x/s 0x8048500 0x8048500: "Ahoy!

" (gdb)

After the return of printf(3) library routine, SSP code performs the canary value check…

0x0804841c <main+40>: mov -0x8(%ebp),%edx 0x0804841f <main+43>: xor %gs:0x14,%edx 0x08048426 <main+50>: je 0x804842d <main+57> 0x08048428 <main+52>: call 0x8048330 <__stack_chk_fail@plt>

It retrieves the canary value from the stack and stores it in EDX register. Then compares it against ‘%gs:0x14’ which is the actual canary value. If they are equal it will use the ‘je’ (Jump if Equal) instruction to continue with the execution at the 0x804842d address. Otherwise, it will call the __stack_chk_fail() library routine through the PLT.

In the first case, the execution will continue from this point:

0x0804842d <main+57>: add $0x14,%esp 0x08048430 <main+60>: pop %ecx 0x08048431 <main+61>: pop %ebp 0x08048432 <main+62>: lea -0x4(%ecx),%esp 0x08048435 <main+65>: ret

The first instruction frees the allocated stack space and the next ones are a common function epilogue procedure. It restores the stored stack and frame pointer by popping them from the stack, updating the stack pointer’s value with the original one stored in ECX and calling ‘ret’ to complete the execution.

This is pretty much what’s going on with the SSP. Now, let’s have a look at the __stack_chk_fail() routine which is implemented in the GNU C Library and you can find it at debug/stack_chk_fail.c like this:

#include <stdio.h> #include <stdlib.h> extern char **__libc_argv attribute_hidden; void __attribute__ ((noreturn)) __stack_chk_fail (void) { __fortify_fail ("stack smashing detected"); }

The attribute “noreturn” is used in functions that cannot return such as this one. So, the code is a simple wrapper around __fortify_fail(). This routine is available at debug/fortify_fail.c and here is its code:

#include <stdio.h> #include <stdlib.h> extern char **__libc_argv attribute_hidden; void __attribute__ ((noreturn)) __fortify_fail (msg) const char *msg; { /* The loop is added only to keep gcc happy. */ while (1) __libc_message (2, "*** %s ***: %s terminated

", msg, __libc_argv[0] ?: "<unknown>"); } libc_hidden_def (__fortify_fail)

Once again it’s a non-return function and it will use the __libc_message() to print a simple message like this:

*** stack smashing detected ***: ./bla terminated

Just for your information, __libc_message() is a POSIX compatible library routine available at sysdeps/posix/libc_fatal.c. I won’t describe it since it’s a common error message printing code.

So, we have talked about what happens after we have an executable application using GCC’s SSP but how about what happens before?

Let’s have a look at the Run-Time Dynamic Linker (RTLD) that is located at etc/rtld.c…

#ifndef THREAD_SET_STACK_GUARD /* Only exported for architectures that don't store the stack guard canary in thread local area. */ uintptr_t __stack_chk_guard attribute_relro; #endif /* Only exported for architectures that don't store the pointer guard value in thread local area. */ uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden __attribute__ ((nocommon)); #ifndef THREAD_SET_POINTER_GUARD strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) #endif

The GCC attribute ‘nocommon’ is used to directly allocate space for that variable and not store it in a ‘common’ storage area. A look at elf/stackguard-macros.h will reveal exactly how this variable is initialized…

#include <stdint.h> #ifdef __i386__ # define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("movl %%gs:0x14, %0" : "=r" (x)); x; }) #elif defined __x86_64__ # define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("movq %%fs:0x28, %0" : "=r" (x)); x; }) ... #else extern uintptr_t __stack_chk_guard; # define STACK_CHK_GUARD __stack_chk_guard #endif

Now, if we move to the security features initialization code of the RTLD we can read the following…

static void security_init (void) { /* Set up the stack checker's canary. */ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (); #ifdef THREAD_SET_STACK_GUARD THREAD_SET_STACK_GUARD (stack_chk_guard); #else __stack_chk_guard = stack_chk_guard; #endif /* Set up the pointer guard as well, if necessary. */ if (GLRO(dl_pointer_guard)) { // XXX If it is cheap, we should use a separate value. uintptr_t pointer_chk_guard = stack_chk_guard; #ifndef HP_TIMING_NONAVAIL hp_timing_t now; HP_TIMING_NOW (now); pointer_chk_guard ^= now; #endif #ifdef THREAD_SET_POINTER_GUARD THREAD_SET_POINTER_GUARD (pointer_chk_guard); #endif __pointer_chk_guard_local = pointer_chk_guard; } }

As you can see, it uses _dl_setup_stack_chk_guard() to setup the stack canary value. Next, it will initialize the pointer check guard value with an XOR logical operation using either a high precision timer’s current value or the same stack canary value based on the compile time options. Since our main concern is the canary value, we should now have a look at _dl_setup_stack_chk_guard() which is located either at sysdeps/unix/sysv/linux/dl-osinfo.h or sysdeps/generic/dl-osinfo.h depending on the operating system.

The sysdeps/unix/sysv/linux/dl-osinfo.h is UNIX System V release dependent.

static inline uintptr_t __attribute__ ((always_inline)) _dl_setup_stack_chk_guard (void) { uintptr_t ret; #ifdef ENABLE_STACKGUARD_RANDOMIZE int fd = __open ("/dev/urandom", O_RDONLY); if (fd >= 0) { ssize_t reslen = __read (fd, &ret, sizeof (ret)); __close (fd); if (reslen == (ssize_t) sizeof (ret)) return ret; } #endif ret = 0; unsigned char *p = (unsigned char *) &ret; p[sizeof (ret) - 1] = 255; p[sizeof (ret) - 2] = '

'; return ret; }

If StackGuard’s stack randomization is enabled, it will open ‘/dev/urandom’ and simply read an ‘uintptr_t’ that is stored in ‘ret’ variable. If __read() returned a value that is equal to size of ‘ret’ which means that the reading operation was successful it will simply return that value. If no stack randomization is enabled, it will set ‘p’ to the address of ‘ret’ variable and then change two Bytes of ret’s value to 0xff (255 in decimal) and 0xA (which is the newline character) and return that value. So, the canary value will always be ‘0xff0a0000’ which is the so-called terminator canary value.

The generic implementation which resides at sysdeps/generic/dl-osinfo.h uses just this implementation…

#include <stdint.h> static inline uintptr_t __attribute__ ((always_inline)) _dl_setup_stack_chk_guard (void) { uintptr_t ret = 0; unsigned char *p = (unsigned char *) &ret; p[sizeof (ret) - 1] = 255; p[sizeof (ret) - 2] = '

'; p[0] = 0; return ret; }

That will always provide a terminator canary value.

So, that was pretty much a quick journey around stack canary values of the GNU C Library. :)