Стек разбивает не пожары. Зачем?

Я пытаюсь заставить glibc обнаруживать разрушение стека и использую следующий код:

 #include <stdio.h>
#include <string.h>

static const int n = 5;

int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("usage: %s string\n", argv[0]);
return -1;
}
printf("%s, len = %d\n", argv[1], strlen(argv[1]));
unsigned char a[n][n];
unsigned char * b = a[n - 1];
memcpy(b, argv[1], (strlen(argv[1]) + 1) * sizeof(unsigned char));
return 0;
}

Если длина argv [1] больше 5, я ожидаю обнаружения ошибки разрушения стека, однако я этого не делаю, и valgrind не обнаруживает ошибок. Что я должен изменить, чтобы получить эту ошибку? (массив должен быть двумерным)

0

Решение

Кажется, что логика в gcc, которая решает, когда включить защиту стека, немного хитра. Первое примечание из документов:

-fstack-протектор

Выдать дополнительный код для проверки переполнения буфера, например, атак с разбиванием стека. Это делается путем добавления переменной защиты к функциям с уязвимыми объектами. Это включает в себя функции, которые вызывают alloca, и функции с буферами больше 8 байт. Защитные устройства инициализируются при входе в функцию, а затем проверяются при выходе из функции. Если контрольная проверка не пройдена, выводится сообщение об ошибке и программа завершается

Таким образом, мы должны ожидать, что функция с локальными буферами размером менее 8 байт будет незащищенной. Например, это:

int unprotected() {
char a[5];
strcpy(a, "this is much too long");
return a[0];
}

составлено с gcc -fstack-protector -Wstack-protectorвыдаёт предупреждение как

предупреждение: функция защиты стека не защищает: все локальные массивы имеют длину менее 8 байт [-Wstack-protector]

Итак, вы можете подумать, что ваш char[5][5] будет защищен, так как его длина превышает 8 байт. Однако, когда я собираю это на ассемблере, я не получаю предупреждения или же защита стека (вы можете найти ассемблер для поиска в эта статья доктора Доббса). Кажется, что gcc рассматривает это как 5 буферов по 5 байт каждый вместо одного буфера из 25 байт.

Вы можете убедить gcc включить защиту стека, показав один буфер размером более 8 байт:

void protected(char *arg) {
union {
char dummy[5 * 5];
char a[5][5];
} u;
memcpy(u.a[4], arg, (strlen(arg) + 1));
}

или просто используя -fstack-protector-all,

1

Другие решения

По умолчанию GCC добавляет код только для обнаружения разрушения стека, когда вы делаете что-то особенно опасное, например alloca (или же gets, как вы упоминаете в комментарии), или объявить большой автоматический массив.

Если вы хотите включить защиту для всех функций, используйте -fstack-protector-all вариант. Вы также можете запросить предупреждение о незащищенных функциях с -Wstack-protector,

3

По вопросам рекламы [email protected]