GCC как обнаружить переполнение буфера стека

Так как есть опция -fstack-protector-strong в gcc для обнаружения разбиения стека. Однако он не всегда может обнаружить переполнение буфера стека. Для первой функции func, когда я ввожу 10 символов больше строки, программа не всегда аварийно завершает работу. Мой вопрос в том, где есть способ, чтобы обнаружить переполнение буфера.

void func()
{
    char array[10];
    gets(array);
}

void func2()
{
    char buffer[10];
    int n = sprintf(buffer, "%s", "abcdefghpapeas");
    printf("aaaa [%d], [%s]n", n, buffer);
}

int main ()
{
   func();
   func2();
}

4 ответов


переполнения в стеке либо трудно обнаружить, либо очень дорого обнаружить - выбрал свой яд.

в двух словах, когда у вас есть это:

 char a,b;
 char *ptr=&a;
 ptr[1] = 0;

тогда это технически законно: есть пространство, выделенное в стеке, который принадлежит функции. Просто это очень опасно.

таким образом, решение может заключаться в добавлении разрыва между a и b и заполните это шаблоном. Но, Ну, некоторые люди на самом деле пишут код, как указано выше. Итак, ваш компилятор нужно это обнаружить.

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

видишь, куда я иду?

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

всегда использовать snprintf() версии функций, если у вас есть выбор. Если старый код использует небезопасные версии, измените его.


вы можете использовать инструмент под названием Valgrind

http://valgrind.org/


мой вопрос в том, где есть способ, чтобы обнаружить переполнение буфера...

void func()
{
    char array[10];
    gets(array);
}

void func2()
{
    char buffer[10];
    int n = sprintf(buffer, "%s", "abcdefghpapeas");
    printf("aaaa [%d], [%s]\n", n, buffer);
}

поскольку вы используете GCC, вы можете использовать FORTIFY_SOURCES.

FORTIFY_SOURCE использует "более безопасные" варианты функций высокого риска, таких как memcpy, strcpy и gets. Компилятор использует более безопасные варианты, когда он может вывести размер целевого буфера. Если копия превысит размер целевого буфера, программа вызовет abort(). Если компилятор невозможно вывести размер целевого буфера, тогда "безопасные" варианты не используются.

чтобы отключить FORTIFY_SOURCE для тестирования, вы должны скомпилировать программу с помощью -U_FORTIFY_SOURCE или -D_FORTIFY_SOURCE=0.


стандарт C имеет "более безопасные" функции через ISO / IEC TR 24731-1, интерфейсы проверки границ. На соответствующих платформах, вы можете просто позвонить gets_s и sprintf_s. Они предлагают согласованное поведение (например, всегда гарантируя, что строка NULL расторгнут) и последовательные возвращаемые значения (например, 0 при успехе или errno_t).

к сожалению, gcc и glibc не соответствуют стандарту C. Ульрих Дрэппер (один из сопровождающих glibc) назвал интерфейсы проверки границ "ужасно неэффективное дерьмо BSD", и они не были добавлены. Надеюсь, в будущем это изменится.


прежде всего не используйте gets.By теперь почти все знают все проблемы безопасности и надежности, которые могут возникнуть с gets. Но он включен здесь по историческим причинам, потому что это очень хороший пример плохого программирования.

давайте рассмотрим все проблемы с кодом:

// Really bad code
char line[100];
gets(line);

поскольку gets не выполняет проверку границ строки длиной более 100 символов, будет перезаписана память. Если Вам ПОВЕЗЕТ, программа просто рухнет или может демонстрируют странное поведение.

функция gets настолько плоха, что компоновщик GNU gcc выдает предупреждение всякий раз, когда он используется.

/tmp/ccI5WJ5m.o(.text+0x24): In function `main':
: warning: the `gets' function is dangerous and should not be used.

защитить доступы массива с assert

C / C++ не выполняет проверку привязки.

например:

int data[10]

i = 20
data[20] = 100 //Memory Corruption

используйте функцию Assert для вышеуказанного кода

#include<assert.h>


int data[10];
i=20

assert((i >= 0) && (i < sizeof(data) / sizeof(data[0]))); // throws 

data[i] = 100

переполнения массива являются одной из наиболее распространенных ошибок программирования и чрезвычайно неприятно пытаться найти. Этот код не устраняет их, но он заставляет багги-код прерываться на ранней стадии, что значительно упрощает поиск проблемы.

и используйте Snprintf(buffer,sizeof (buffer),"%s","abcdefghpapeas") и некоторые инструменты,такие как valgrind, GDB.

надеюсь, это поможет вам..