Re: use of %fs segment register in x86_64 with -fstack-check

Ruslan Kabatsayev <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <CAHEcG96OuB4OuQcHAr989feHQA7v7EPpGGgROPV2pok8QP15PA@mail.gmail.com>
Hi,

On Tue, 3 Mar 2020 at 17:53, Maxim Blinov <[email protected]> wrote:
>
> Hi all,
>
> I'm looking at some -fstack-check'ed code, and would appreciate it if
> some gdb x86_64 gurus could double check my understanding of a trivial
> example
>
> here is the source:
>
> big-access.c:
> ```
> #include <stdio.h>
> #include <stdlib.h>
> #include <stdint.h>
>
> extern void foo(char *);
>
> int main()
> {
>   char ch[8000];
>   foo (ch);
>
>   return 0;
> }
> ```
>
> foo.c:
> ```
> void foo(char *ch) { }
> ```
>
> And the compilation line:
>
> $ gcc -O2 -fstack-check -o big-access big-access.c foo.c -fdump-rtl-final
>
> And here is the gdb view (ignore the breakpoint and current insn caret):
> ```
> B+ │0x555555554560 <main>           sub    $0x2f78,%rsp
>    │0x555555554567 <main+7>         orq    $0x0,0xf58(%rsp)
>    │0x555555554570 <main+16>        orq    $0x0,(%rsp)
>    │0x555555554575 <main+21>        add    $0x1020,%rsp
>    │0x55555555457c <main+28>        mov    %rsp,%rdi
>    │0x55555555457f <main+31>        mov    %fs:0x28,%rax
>   >│0x555555554588 <main+40>        mov    %rax,0x1f48(%rsp)
>    │0x555555554590 <main+48>        xor    %eax,%eax
>    │0x555555554592 <main+50>        callq  0x5555555546d0 <foo>
>    │0x555555554597 <main+55>        mov    0x1f48(%rsp),%rdx
>    │0x55555555459f <main+63>        xor    %fs:0x28,%rdx
>    │0x5555555545a8 <main+72>        jne    0x5555555545b4 <main+84>
>    │0x5555555545aa <main+74>        xor    %eax,%eax
>    │0x5555555545ac <main+76>        add    $0x1f58,%rsp
>    │0x5555555545b3 <main+83>        retq
>    │0x5555555545b4 <main+84>        callq  0x555555554540 <__stack_chk_fail@plt>
>    │0x5555555545b9                  nopl   0x0(%rax)
> ```
>
> I would just like someone who knows their stuff to double check my
> understanding:
>
> The "orq" at the start are purposefully causing a "dummy" load/store
> event so the VMM can decide whether or not it is sane for us to have
> used those pages for the stack, right?

Not quite. As noted at [1] this OR is to ensure that stack hasn't
overflowed. This is the part added by -fstack-check (you can see it go
away when you remove this option). See [2] for documentation.

>
> Another question, is at address 0x55555555457f. I presume that
> %fs:0x28 is a memory address that points to a sentinel value. We load
> it into %rax, and then we store it in strategic locations in our stack
> to serve as sentinel values. Before we leave, we check that the memory
> location hasn't changed at 0x55555555459f. That implies, that the
> memory location %fs:0x28 is pointing to a globally-used sentinel
> value?

Right. But note that this is enabled not by -fstack-check, but rather
by some of the -fstack-protector* options that are on by default on
modern Linux distributions. You can confirm this by explicitly passing
-fno-stack-protector and seeing this sentinel checking gone.

>
> But who sets %fs? Indeed what is the ABI usage of %fs in the context
> of linux x86_64?

The FS segment base points to the TLS. See [3] and links therein.

> And why 0x28 offset?

It's the offset of stack_guard member of tcbhead_t. See the
corresponding glibc source [4].

>
> Thankyou for reading,
> Maxim

[1]: https://stackoverflow.com/a/44670648/673852
[2]: https://gcc.gnu.org/onlinedocs/gccint/Stack-Checking.html
[3]: https://chao-tic.github.io/blog/2018/12/25/tls
[4]: https://code.woboq.org/userspace/glibc/sysdeps/x86_64/nptl/tls.h.html#42

Regards,
Ruslan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.