GCC генерирует Canary или нет?

моя версия gcc — 4.8.2, а операционная система — Ubuntu 14.04 (64-разрядная версия). Я обнаружил, что иногда gcc автоматически генерирует канарейку для защиты от переполнения буфера, а иногда нет, почему?

case для генерации canary: когда SIZE кратен четырем

#include<stdio.h>
#define SIZE 4

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

asm после 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 не генерировать canary : не кратно четырем

#include<stdio.h>
#define SIZE 2

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

asm после 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);
...

person zongyuwu    schedule 28.06.2014    source источник
comment
Какая у вас операционная система (название и версия)? Это важно, потому что разные дистрибутивы включают разные исправления и флаги по умолчанию (см.). Например, у меня не генерируются канарейки, пока я не укажу -fstack-protector.   -  person xaizek    schedule 28.06.2014
comment
Моя операционная система Ubuntu 14.04 64bit.   -  person zongyuwu    schedule 28.06.2014
comment
Тогда, скорее всего, будет использоваться -fstack-protector, но на странице руководства сказано, что canary генерируется для всех функций с буферами больше 8 байт, а компилятор выделяет 16 байт для обоих буферов (одинаковые на вашей машине и на моей), поэтому обе версии должны иметь это. Я получаю другое поведение на той же версии GCC. Вы пробовали большие числа, например. 17 и 20?   -  person xaizek    schedule 28.06.2014
comment
@xaizek: док. говорит буферы больше 8, а не кадр стека больше 8. Может быть, Ubuntu исправил это ограничение до 4?   -  person rodrigo    schedule 28.06.2014
comment
@ Родриго, может быть. Вот почему меня интересует поведение с большими размерами буфера. Лучше всего было бы посмотреть список дополнительных патчей, но я не знаю, где его можно найти (кажется, его нет в списке на launchpad.net).   -  person xaizek    schedule 28.06.2014
comment
Да, попробуйте размер больше 16 байт, там генерируется канарейка. Мне интересно, почему должно быть более 16 байт? Из соображений эффективности? В любом случае заранее спасибо   -  person zongyuwu    schedule 28.06.2014
comment
Действительно, из соображений эффективности прочтите эту страницу Википедии, где описывается различные реализации от нескольких компаний. Есть флаг -fstack-protector-all, который заставляет генерировать канарейки для всех функций, что приводит к снижению производительности.   -  person xaizek    schedule 28.06.2014
comment
@ user3246832: что выводит gcc -Q -v canary.c 2>&1 | egrep '(param|ssp|protector)'? Он должен содержать -fstack-protector и, как предложил @rodrigo, что-то вроде --param ssp-buffer-size=4.   -  person xaizek    schedule 28.06.2014


Ответы (1)


Хорошо, я думаю, мы знаем ответ из комментариев, поэтому я опубликую его здесь, чтобы указать его явно.

Использование канареек во многих функциях может привести к снижению производительности. Вот почему есть несколько способов сообщить GCC, что мы хотим их использовать, которые хорошо описаны здесь. Основные идеи:

  1. Канарейки по умолчанию не используются, нужно передать один из флагов, разрешающих их.
  2. Чтобы сократить время выполнения, GCC использует простую эвристику с флагом -fstack-protector: добавьте канареек для функций, которые используют alloca или локальные буферы размером более 8 байт (по умолчанию).
  3. Эвристику можно настроить с помощью параметра ssp-buffer-size: --param ssp-buffer-size=4.

Судя по всему, Ubuntu поставляет версию GCC с размером буфера, измененным на 4, поэтому буферы меньшего размера не вызывают генерацию канарейки. Я подтверждаю (и любой другой должен быть в состоянии повторить), что компиляцией двух примеров с --param ssp-buffer-size=4 получается сборка с канарейками только для одного из них.

person xaizek    schedule 28.06.2014