17

my gcc version is 4.8.2 and operating system is ubuntu 14.04 (64 bit). I found that sometimes gcc auto generate the canary to do buffer overflow protection sometimes not, why?

case to generate canary: when SIZE is multiple of four

#include<stdio.h>
#define SIZE 4

int main()
{
    char s[SIZE];
    scanf("%s", s);
    return 0;
}

asm after gcc -c -g -Wa,-a,-ad

...
   4:a.c           **** int main()
   5:a.c           **** {
  13                    .loc 1 5 0
  14                    .cfi_startproc
  15 0000 55            pushq   %rbp
  16                    .cfi_def_cfa_offset 16
  17                    .cfi_offset 6, -16
  18 0001 4889E5        movq    %rsp, %rbp
  19                    .cfi_def_cfa_register 6
  20 0004 4883EC10      subq    $16, %rsp
  21                    .loc 1 5 0
  22 0008 64488B04      movq    %fs:40, %rax
  22      25280000 
  22      00
  23 0011 488945F8      movq    %rax, -8(%rbp)
  24 0015 31C0          xorl    %eax, %eax
   6:a.c           ****     char s[SIZE];
   7:a.c           ****     scanf("%s", s);
...

case not to generate canary : not the multiple of four

#include<stdio.h>
#define SIZE 2

int main()
{
    char s[SIZE];
    scanf("%s", s);
    return 0;
}

asm after gcc -c -g -Wa,-a,-ad

...
   4:a.c           **** int main()
   5:a.c           **** {
  13                    .loc 1 5 0
  14                    .cfi_startproc
  15 0000 55            pushq   %rbp
  16                    .cfi_def_cfa_offset 16
  17                    .cfi_offset 6, -16
  18 0001 4889E5        movq    %rsp, %rbp
  19                    .cfi_def_cfa_register 6
  20 0004 4883EC10      subq    $16, %rsp
   6:a.c           ****     char s[SIZE];
   7:a.c           ****     scanf("%s", s);
...
zongyuwu
  • 325
  • 1
  • 3
  • 8
  • 2
    What is your operating system (both name and version)? It's important because different distributions include different patches and default flags ([see](https://en.wikipedia.org/wiki/Stack-smashing_protection#GNU_Compiler_Collection_.28GCC.29)). For example, canaries are not generated for me unless I specify `-fstack-protector`. – xaizek Jun 28 '14 at 08:49
  • My operating System is Ubuntu 14.04 64bit – zongyuwu Jun 28 '14 at 08:51
  • 1
    Then `-fstack-protector` is likely to be used, but man page says that canary is generated for all functions with buffers greater than 8 bytes and compiler allocates 16 bytes for both buffers (same on your machine and mine), so both versions should have it. I get different behaviour on same version of GCC. Did you try larger numbers, e.g. 17 and 20? – xaizek Jun 28 '14 at 08:55
  • 1
    @xaizek: The doc. says _buffers greater than 8_, not _stack frame greater than 8_. Maybe Ubuntu has patched this limit to 4? – rodrigo Jun 28 '14 at 09:00
  • 1
    @rodrigo, might be. That's why I'm interested in behaviour with bigger buffer sizes. The best way would be to see list of additional patches, but I don't know where it can be found (doesn't seem to be listed on launchpad.net). – xaizek Jun 28 '14 at 09:04
  • Yes, try size bigger than 16bytes there canary is generated. I am wondering why should over 16bytes? For reason of efficiency? Anyway, thanks in advanced – zongyuwu Jun 28 '14 at 09:04
  • Indeed because of efficiency, read [that Wikipedia page](https://en.wikipedia.org/wiki/Stack-smashing_protection#GNU_Compiler_Collection_.28GCC.29), which describes different implementations from several companies. There are `-fstack-protector-all` flag that forces canaries to be generated for all functions, which causes performance penalties. – xaizek Jun 28 '14 at 09:06
  • @user3246832: what is the output of `gcc -Q -v canary.c 2>&1 | egrep '(param|ssp|protector)'`? It should contain `-fstack-protector` and as @rodrigo suggested something like `--param ssp-buffer-size=4`. – xaizek Jun 28 '14 at 09:17

1 Answers1

20

OK, I guess we know the answer from comments, so I'll post it here to state it explicitly.

Putting canaries in a lot of functions can result in performance degradation. That's why there are several ways to tell GCC we want to use them, which are described well here. Main ideas:

  1. Canaries are not used by default, one needs to pass one of flags that enable them.
  2. To save execution time, GCC uses simple heuristic with -fstack-protector flag: add canaries for functions that use alloca or local buffers larger than 8 bytes (by default).
  3. The heuristic can be tweaked with ssp-buffer-size parameter: --param ssp-buffer-size=4.

Apparently Ubuntu ships version of GCC with size of buffer changed to 4, so buffers less than that don't trigger generation of a canary. I confirm (and anyone else should be able to repeat) that by compiling two examples with --param ssp-buffer-size=4, which produces assembly with canaries for only one of them.

xaizek
  • 5,098
  • 1
  • 34
  • 60