1

*I'm on an Ubuntu x86_64 system, gcc 11.4.0

I have this C program in a file test.c :

int fx( int a, int* b ){

     *b = 12;
      return a;

}


int main(){
    
    int a = 20;
    int b = fx(10,&a);
    b+= 5;
    
}

I compile this file with "gcc test.c -o test". Then I inspect it with "objdump -dw -M suffix test" and I get :

0000000000001149 <fx>:
    1149:   f3 0f 1e fa             endbr64 
    114d:   55                      pushq  %rbp
    114e:   48 89 e5                movq   %rsp,%rbp
    1151:   89 7d fc                movl   %edi,-0x4(%rbp)
    1154:   48 89 75 f0             movq   %rsi,-0x10(%rbp)
    1158:   48 8b 45 f0             movq   -0x10(%rbp),%rax
    115c:   c7 00 0c 00 00 00       movl   $0xc,(%rax)
    1162:   8b 45 fc                movl   -0x4(%rbp),%eax
    1165:   5d                      popq   %rbp
    1166:   c3                      retq   

0000000000001167 <main>:
    1167:   f3 0f 1e fa                     endbr64 
    116b:   55                              pushq  %rbp
    116c:   48 89 e5                        movq   %rsp,%rbp
    116f:   48 83 ec 10                     subq   $0x10,%rsp
    1173:   64 48 8b 04 25 28 00 00 00      movq   %fs:0x28,%rax
    117c:   48 89 45 f8                     movq   %rax,-0x8(%rbp)
    1180:   31 c0                           xorl   %eax,%eax
    1182:   c7 45 f0 14 00 00 00            movl   $0x14,-0x10(%rbp)
    1189:   48 8d 45 f0                     leaq   -0x10(%rbp),%rax
    118d:   48 89 c6                        movq   %rax,%rsi
    1190:   bf 0a 00 00 00                  movl   $0xa,%edi
    1195:   e8 af ff ff ff                  callq  1149 <fx>
    119a:   89 45 f4                        movl   %eax,-0xc(%rbp)
    119d:   83 45 f4 05                     addl   $0x5,-0xc(%rbp)
    11a1:   b8 00 00 00 00                  movl   $0x0,%eax
    11a6:   48 8b 55 f8                     movq   -0x8(%rbp),%rdx
    11aa:   64 48 2b 14 25 28 00 00 00      subq   %fs:0x28,%rdx
    11b3:   74 05                           je     11ba <main+0x53>
    11b5:   e8 96 fe ff ff                  callq  1050 <__stack_chk_fail@plt>
    11ba:   c9                              leaveq 
    11bb:   c3                              retq

It looks like the compiler uses stack protector by default as you can tell by looking at the main instructions.

My questions :

  1. Is it ok to compile my C program with "gcc test.c -fno-stack-protector -o test"?

  2. Is -fno-stack-protector just a safety option that makes us vulnerable to some stack attacks or we should be careful when using this option while compiling because it could break something or create some errors/incompatibilities of some kind ?

  3. Why doesn't my gcc compiler have it on by default whereas in other systems ( macOS x86_64 clang ) I've noticed it is on ?

  4. What are the scenarios where it makes sense using it versus the ones we should absolutely avoid it ?

fuz
  • 88,405
  • 25
  • 200
  • 352
alessio solari
  • 313
  • 1
  • 6
  • I thought Ubuntu did configure their GCC to have `-fstack-protector-strong` on by default. Your program doesn't have any local arrays or even structs, but even just taking the address of one `int` was enough to get GCC to set up a stack-cookie (with a value from `movq %fs:0x28,%rax`), so yes, your GCC does have a pretty paranoid setting of stack-protector on by default. – Peter Cordes Aug 23 '23 at 23:26
  • Try something like `void canary_twitter (void) { volatile unsigned char buf[8] = {0}; for(size_t i=0;i<9; i++) { buf[i] = 1; } }` with or without `-fstack-protector`. On Linux I get SIGSEGV either way, but with the protector it also reports the cause as stack smashing. But if I add `buf[8]=0;` then the canary is happy and I get neither seg fault nor stack smashing, even though my code _was_ quite obviously mucking around out of bounds on the stack. – Lundin Aug 25 '23 at 11:48

2 Answers2

5
  1. Yes, it's perfectly fine to do so. At your own risk though. Without it, you will have one less protection against potential stack buffer-overflow vulnerabilities in your program.
  2. Yeah it's just a safety feature/option, compiling with/without it will not break stuff unless you are developing complex low-level standard library code.
  3. Depends on your compiler version and OS/distro. Each OS/distribution has its own compiler build with different configurations and defaults. Yours apparently decided to configure GCC with default stack protector. Actually, if I am not mistaken, from a certain version onwards GCC just enabled -fstack-protector by default so a distro would need to explicitly configure GCC to disable it by default to change that.
  4. The only scenario when you may want to avoid it is microbenchmarks or particular low-level programming situations where code has to be exactly what you expect without additional compiler-generated noise. In the general case, it doesn't make much sense to disable it, its overhead should be negligible.
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
5

Is it ok to compile my C program with "gcc test.c -fno-stack-protector -o test"?

I do not see any problem with doing that. For convention, it might be better to place options before operands like so:

gcc -fno-stack-protector -o test test.c

Is -fno-stack-protector just a safety option that makes us vulnerable to some stack attacks or we should be careful when using this option while compiling because it could break something or create some errors/incompatibilities of some kind ?

The option -fstack-protector=... enables extra hardening against stack smashing attacks. If you disable it with -fno-stack-protector, your code will not benefit from this hardening and may be easier to exploit if it already has an exploitable defect. You can mix and match object files compiled with and without the stack protector as you desire, use of the stack protector causes no incompatibilities. However, only functions defined in translation units that have been compiled with stack protector turned on benefit from this hardening.

Why doesn't my gcc compiler have it on by default whereas in other systems ( macOS x86_64 clang ) I've noticed it is on ?

Canonical has decided to enable this option by default as to make hardening against stack-smashing an “opt out” instead of an ”opt in” as it is on macOS. This improves overall security.

What are the scenarios where it makes sense using it versus the ones we should absolutely avoid it ?

Compiling with stack protector turned on is generally useful and especially so if your code is ran with untrusted input or input coming from network or external storage media. However, there is a minor performance cost. If this is is significant, you may want to turn off the stack protector. Be aware that your application may then be easier to exploit with stack smashing attacks if it has such a defect.

fuz
  • 88,405
  • 25
  • 200
  • 352