Разница между gcc -D_FORTIFY_SOURCE = 1 и -D_FORTIFY_SOURCE = 2

Может ли кто-нибудь указать разницу между gcc -D_FORTIFY_SOURCE = 1 и -D_FORTIFY_SOURCE = 2? Я полагаю, что = 2 более безопасен? Мне не удалось найти список, в котором перечислены различия по пунктам.

Я также прочитал, что -D_FORTIFY_SOURCE = 2 следует использовать с -O2, иначе не все функции будут доступны. Также здесь я не нашел список, который бы подробно определял регрессии. Мне было бы особенно интересно скомпилировать с -Os, поскольку целью является устройство с не столько флэш-памятью.

Любые подсказки о том, где это задокументировано, приветствуются!

Ответ 1

На странице руководства для макросов проверки функций (man 7 feature_test_macros)

_FORTIFY_SOURCE (так как glibc 2.3.4)

Определение этого макроса вызывает некоторые легкие проверки для обнаружения некоторых ошибок переполнения буфера при использовании различных функций манипуляции строкой и памятью (например, memcpy, memset, stpcpy, strcpy, strncpy, strcat, strncat, sprintf, snprintf, vsprintf, vsnprintf, gets и их широкие характерные варианты). Для некоторых функций проверяется согласованность аргументов; например, делается проверка, что open был снабжен аргументом mode, когда указанные флаги включают O_CREAT. Не все проблемы обнаружены, просто некоторые распространенные случаи.

Если _FORTIFY_SOURCE установлено значение 1, с уровнем оптимизации компилятора 1 (gcc -O1) и выше, выполняются проверки, которые не должны изменять поведение соответствующих программ.

Если параметр _FORTIFY_SOURCE установлен на 2, добавлена ​​дополнительная проверка, но некоторые соответствующие программы могут выйти из строя.

Некоторые проверки могут выполняться во время компиляции (через логику макросов, реализованных в файлах заголовков), и приводят к предупреждениям компилятора; другие проверки выполняются во время выполнения и приводят к ошибке выполнения во время выполнения проверки.

Использование этого макроса требует поддержки компилятора, доступного с помощью gcc с версии 4.0.

Кроме того, статья Повысить безопасность приложений с помощью FORTIFY_SOURCE (март 2014 года):

  • gcc -D_FORTIFY_SOURCE=1 добавляет проверки только во время компиляции (некоторые заголовки необходимы как #include <string.h>)
  • gcc -D_FORTIFY_SOURCE=2 также добавляет проверки во время выполнения (обнаруженное переполнение буфера завершает программу)

По существу, уровень _FORTIFY_SOURCE уровня 2 более безопасен, но представляет собой немного более рискованную стратегию компиляции; если вы используете его, убедитесь, что у вас очень сильные регрессионные тесты для вашего скомпилированного кода, чтобы доказать, что компилятор не представил никаких неожиданных действий.

Ответ 2

http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html более подробно, чем feature_test_macros(7).

Здесь соответствующая выдержка, слегка отредактированная/переформатированная для ясности:

Разница между -D_FORTIFY_SOURCE=1 и -D_FORTIFY_SOURCE=2например, для

  struct S {
      struct T {
        char buf[5];
        int x;
      } t;
      char buf[20];
  } var;

С -D_FORTIFY_SOURCE=1,

  strcpy (&var.t.buf[1], "abcdefg");

не считается переполнением (объект является целым VAR), тогда как с -D_FORTIFY_SOURCE=2

  strcpy (&var.t.buf[1], "abcdefg");

будет считаться переполнением буфера.

Другим отличием является то, что при -D_FORTIFY_SOURCE=2, %nв строках формата наиболее распространенных функций семейства *printfразрешается только в том случае, если он хранится в постоянной памяти (обычно строковые литералы, gettext _("%s string %n") тоже прекрасны), но обычно, когда злоумышленник пытается использовать строку формата уязвимость, %n будет где-то, где злоумышленник мог напишите его.