What sets fs:[0x28] (stack canary)?
Solution 1
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.
Solution 2
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.
Related videos on Youtube
Brandon Condrey
Consider opposing apartheid in Palestine and signing onto the BDS Movement; #1 User for DBA.SE 2017. Available for contracting: 281.901.0011 PostgreSQL & PostGIS / MySQL / SQL Server JavaScript, Typescript, Rx.js, Node.js, Angular Also: C / Perl / Python / Rust / x86 Assembly
Updated on September 18, 2022Comments
-
Brandon Condrey over 1 year
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 setsfs:[0x28]
? Is the canary regenerated -- on boot, or process spawn? Where is this documented? -
Brandon Condrey almost 6 yearsThis 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?
-
Brandon Condrey almost 6 yearszomfg, 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.
-
Brandon Condrey almost 6 yearsWhat initializes a process with
arch_prctl(ARCH_SET_FS..)
I don't see that in the executable? Is that kernel code? -
Danila Kiver almost 6 yearsSee 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.