Единственное отличие между багом и эксплойтом — интеллект взломщика.
Разработчики OpenBSD
Расширение _FORTIFY_SOURCE добавляет для некоторых функций из стандартной библиотеки, работающих со строками и памятью, альтернативные функции с проверкой на допустимость длинны копируемых данных. Это обеспечивает защиту от некоторых типов атак переполнения буфера, вернее не дает взломщику воспользоваться уязвимостью для получения контроля над системой, так как при обнаружении возможного переполнения программа аварийно завершается. Вот пример альтернативной функции strcpy():
сhar * __strcpy_chk (char *__restrict__ dest, const char *__restrict__ src, size_t slen)
{
size_t len = strlen (src);
if (len >= slen)
__chk_fail ();
return memcpy (dest, src, len + 1);
}
Переполнения буфера может определяться на стадии компиляции или во время выполнения программы, на основании количества байт до конца объекта (массива, структуры и т.д.) и длинны копируемых данных. В зависимости от ситуации компилятор выбирает какие функции использовать, обычные или с проверкой. У функций с проверкой есть дополнительный параметр, в котором компилятор указывает количество байт до конца объекта. Если во время выполнения программы в функции с проверкой обнаруживается переполнение, то управление передается функции __chk_fail() , которая выводит сообщение в stderr, и завершает работу программы.
Возможны следующие варианты:
char buf[5];
1)
memcpy (buf, foo, 5);
strcpy (buf, "abcd");
В данном случае компилятору известно, что переполнения не будет, поэтому будут использоваться функции memcpy и strcpy.
2)
memcpy (buf, foo, n);
strcpy (buf, bar);
В этой ситуации компилятору не известно, будет переполнение или нет, но он знает размер буфера buf, поэтому будут использоваться функции с проверкой __memcpy_chk и __strcpy_chk.
3)
memcpy (buf, foo, 6);
strcpy (buf, "abcde");
Тут компилятору известно, что переполнение будет, поэтому он выдаст предупреждение при компиляции, и будет использовать функции __memcpy_chk и __strcpy_chk.
4)
char *p;
memcpy (p, q, n);
strcpy (p, q);
В данной ситуации на стадии компиляции неизвестен размер буфера, и невозможно определить возможно ли переполнение, в программе будут использоваться функции memcpy и strcpy.
Расширение доступно в версии GCC 4.0+, и включается при помощи параметров -D_FORTIFY_SOURCE=1 или -D_FORTIFY_SOURCE=2, при включённом уровне оптимизации -O1 и выше. Между -D_FORTIFY_SOURCE=1 и -D_FORTIFY_SOURCE=2 следующие различия:
1)
struct S
{
struct T
{
char buf[5];
int x;
} t;
char buf[20];
} var;
strcpy (&var.t.buf[1], "abcdefg");
При -D_FORTIFY_SOURCE=1, переполнение не обнаруживается, так как данные не выходят за приделы объекта VAR.
При -D_FORTIFY_SOURCE=2, компилятор выдаст предупреждение и во время выполнения, программа аварийно завершится.
2) При -D_FORTIFY_SOURCE=2, требуется, чтобы спецификатор %n находился в области памяти доступной только для чтения, если это не так то при компиляции ни какого предупреждения не будет, а при выполнении появится сообщение «*** %n in writable segment detected ***» и программа аварийно завершится. Например следующий код будет приводить к аварийному завершению программы при -D_FORTIFY_SOURCE=2:
char buf[20];
int a;
strcpy(buf, "hello%n");
printf(buf, &a);
Дополнительная информация по данной теме
Сдесь