What sets fs:[0x28] (stack canary)?

It's easy to track this initialization, as for (almost) every process strace shows a very suspicious syscall during the very beginning of the process run:

arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0

That's what man 2 arch_prctl says:

   ARCH_SET_FS
          Set the 64-bit base for the FS register to addr.

Yay, looks like that's what we need. To find, who calls arch_prctl, let's look for a backtrace:

(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) r
Starting program: <program path>

Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0  0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
#1  0x00007ffff7ddd3e3 in dl_main () from /lib64/ld-linux-x86-64.so.2
#2  0x00007ffff7df04c0 in _dl_sysdep_start () from /lib64/ld-linux-x86-64.so.2
#3  0x00007ffff7dda028 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7dd8fb8 in _start () from /lib64/ld-linux-x86-64.so.2
#5  0x0000000000000001 in ?? ()
#6  0x00007fffffffecef in ?? ()
#7  0x0000000000000000 in ?? ()

So, the FS segment base is set by the ld-linux, which is a part of glibc, during the program loading (if the program is statically linked, this code is embedded into the binary). This is where it all happens.

During the startup, the loader initializes TLS. This includes memory allocation and setting FS base value to point to the TLS beginning. This is done via arch_prctl syscall. After TLS initialization security_init function is called, which generates the value of the stack guard and writes it to the memory location, which fs:[0x28] points to:

  • Stack guard value initialization
  • Stack guard value write, more detailed

And 0x28 is the offset of the stack_guard field in the structure which is located at the TLS start.


What you're seeing is called (in GCC) the Stack Smashing Protector (SSP), which is a form of buffer overflow protection generated by the compiler. The value is a random number generated by the program at startup and as the Wikipedia article mentions, is placed in Thread Local Storage (TLS). Other compilers may use different strategies to implement this type of protection.

Why store the value in TLS? As the value is located there, its address is not accessible by the CS, DS and SS registers, making guessing the stored value very difficult if you're trying to alter the stack from malicious code.