Проблема с распределением памяти gcc - переполнение буфера

Является ли gcc разумным распределением памяти для предотвращения атаки переполнения буфера?

int function(char *str) {
    int a = 0;                 // See the
    char b[16] = "abcd";       // changes here

    if(!strcmp(b, str))
        a = 1;

    return a;
}

и

int function(char *str) {
    char b[16] = "abcd";       // See the
    int a = 0;                 // changes here

    if(!strcmp(b, str))
        a = 1;

    return a;
}

Когда я отлаживаю его с помощью gdb, он всегда выделяет память сначала целым переменным, а затем массиву символов; независимо от того, каков порядок объявления переменных. то есть в вышеприведенном обоих случаях компилятор сначала выделяет память на a, а затем на b.

(higher address)
  Memory
|        |
|        |
+--------+
|        |
|        |
|        |
|        |
+--------+ <----- b (16 bytes)
|        |
+--------+ <----- a (4 bytes)
|        |
(lower address)

Итак, даже если мы поставляем более 16 символов в str, это не может повлиять на значение a. Может кто-нибудь помочь мне здесь?

Спасибо.

Ответы

Ответ 1

Да, если выполняется с флагом -fstack-protector.

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

Дополнительную информацию см. на странице Википедии о защите переполнения буфера и ProPolice.

Ответ 2

Даже если GCC имеет такую ​​функцию для защиты от переполнения буфера, здесь есть много других соображений, которые могут вызвать порядок объявления фиксированной переменной. Если объявление сделано не очень важно, компилятор будет принимать решения о распределении, основанные на том, когда и как переменная используется во время выполнения.

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

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

Ответ 3

Является ли gcc разумным распределением памяти для предотвращения атаки переполнения буфера?

Нет, это не так. Вы не можете предотвратить атаку или переполнение буфера без проверки границ, что не всегда возможно. Вы можете только иногда обнаруживать переполнение после факта.

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