9

From this post it is shown that FS:[0x28] is a stack-canary. I'm generating that same code using GCC on this function,

void foo () {
    char a[500] = {};
    printf("%s", a);
}

Specifically, I'm getting this assembly..

    0x000006b5      64488b042528.  mov rax, qword fs:[0x28]                ; [0x28:8]=0x1978 ; '(' ; "x\x19"
    0x000006be      488945f8       mov qword [local_8h], rax
...stuff...
    0x00000700      488b45f8       mov rax, qword [local_8h]
    0x00000704      644833042528.  xor rax, qword fs:[0x28]
    0x0000070d      7405           je 0x714
    0x0000070f      e85cfeffff     call sym.imp.__stack_chk_fail           ; void __stack_chk_fail(void)
    ; CODE XREF from 0x0000070d (sym.foo)
    0x00000714      c9             leave
    0x00000715      c3             ret

What is setting the value of fs:[0x28]? The kernel, or is GCC throwing in the code? Can you show the code in the kernel, or compiled into the binary that sets fs:[0x28]? Is the canary regenerated -- on boot, or process spawn? Where is this documented?

11

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:

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

  • zomfg, really great answer. I was trying to disassemble a binary with radare. this has the form and content that I was looking for. Thanks a ton. – Evan Carroll Jul 6 '18 at 2:05
  • What initializes a process with arch_prctl(ARCH_SET_FS..) I don't see that in the executable? Is that kernel code? – Evan Carroll Jul 6 '18 at 3:26
  • See the "syscall" link in the post. It leads to the actual call site (git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153) where the syscall is executed. It is executed by ld-linux during the TLS initialization. – Danila Kiver Jul 6 '18 at 3:30
5

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.

  • This isn't what i'm looking for, so I've clarified a little in an attempt to be clear. "random number generated by the program at startup" can you show where in an executable it's generated, and what's putting the code to generate it? – Evan Carroll Jul 6 '18 at 1:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.