xorl %eax, %eax

Linux GLibC Stack Canary Values

with 6 comments

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!\n");
}

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!\n"
(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\n",
                    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] = '\n';
  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] = '\n';
  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. :)

Written by xorl

October 14, 2010 at 11:50

Posted in security

6 Responses

Subscribe to comments with RSS.

  1. More modern versions of glibc will use the AT_RANDOM bytes provided by the kernel instead of using /dev/urandom or the static canary. Prior to this, many distros would patch the dl_setup_stack_chk_guard() function to extract entropy from the stack and library memory positions to try to get some amount of randomness to avoid the static canary.

    Unfortunately, glibc still has a bug open where it is not leaving the lowest byte a “0”, which would have the affect of stopping str*() functions from operating on the canary:
    http://sourceware.org/bugzilla/show_bug.cgi?id=10149

    Kees Cook

    October 14, 2010 at 18:46

  2. Nice.

    GS contains interesting values on its segment. ‘0x14’ for 32bits(or ‘0x28’ for 64bits) is an index defined by “stack_guard” macro, and you have also pointer_guard to mangle some function pointers initialized for handle libc routines.

    definition
    ——————-
    #ifdef X86_ARCH
    asm(“movw %%gs, %w0” : “=q” (__main_thread_desc));
    asm(“movl %%gs:(0x10), %0″:”=r” (sysinfo));
    asm(“movl %%gs:(0x14), %0″:”=r” (stack_guard));
    asm(“movl %%gs:(0x18), %0″:”=r” (pointer_guard));
    ——————-

    bizou,
    ipv

    ipv

    October 14, 2010 at 19:33

  3. RE: “Then EAX is zeroed out since the canary value has no reason in being left there.”

    True, and it improves security. The clearing of EAX after setting the canary, and the use of XOR to test (and clear) the value in EDX, is most likely done to avoid situations where the canary value could be leaked. This way, the value is only present in a register during the setting and checking of the canary; so a program bug will be less likely to leak the value (which it will then have to get from the TLS or the stack).

    Morten S. Kirkegaard

    October 15, 2010 at 16:42

  4. I’m kind of new to this and my question might sound very stupid, but what is “%gs:0x14”?

    Thanks

    Boo

    November 9, 2011 at 22:58

  5. It’s just an offset (0x14) from GS segment selector which from the above code snippets you can see that it points to stack_guard value which is used as the canary.

    xorl

    November 11, 2011 at 10:43

  6. Hi,

    I’ve enabled the stack_canary and I don’t it was working for me. I got the core file even though I was not enabled.

    Thanks,
    Kesav.

    Kesav

    July 26, 2012 at 13:38


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s