Поделиться через


Параметр /GS (проверка безопасности буфера)

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

/GS[-]

Заметки

По умолчанию параметр /GS включен. Если в приложении предполагается отсутствие проблем безопасности, используйте параметр /GS-. Дополнительные сведения о параметре /GS см. в статье Подробная проверка безопасности компилятора (на английском языке). Дополнительные сведения о подавлении обнаружения переполнения буфера см. в разделе safebuffers.

Проверки безопасности

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

Буферы GS

В буфере GS выполняется проверка безопасности переполнения буфера. Буфер GS может принимать одно из следующих значений:

  • Массив, размер которого больше 4 байтов, содержащий более двух элементов, тип элементов которого не является типом указателя.

  • Структура данных, размер которых более чем 8 байтов и не содержит указателей.

  • Буфер, выделенный с использованием функции _alloca.

  • Любой класс или структура, содержащие буфер GS.

Например, следующие инструкции объявляют буферы GS.

    char buffer[20];
    int buffer[20];
    struct { int a; int b; int c; int d; } myStruct;
    struct { int a; char buf[20]; };

Однако следующие инструкции не объявляют буферы GS. Первые два объявления содержат элементы типа указателя. Третий и четвертый операторы объявляют массивы, размер которых слишком мал. Пятый оператор объявляет структуру, размер которой на платформе x86 не превышает 8 байт.

    char *pBuf[20];
    void *pv[20];
    char buf[4];
    int buf[2];
    struct { int a; int b; };

Параметр компилятора /GS требует, чтобы файл безопасности cookie инициализироваться перед запуском любой функции, которая использует файл cookie. Объект безопасности cookie необходимо инициализировать до входа в файл EXE или DLL. При использовании точек входа библиотеки CRT по умолчанию (mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup или _DllMainCRTStartup) инициализация выполняется автоматически. При использовании альтернативной точки входа необходимо вручную инициализировать объект безопасности cookie, вызвав __security_init_cookie.

Что защищается

Параметр компилятора /GS защищает следующие элементы:

  • Возвращаемый адрес вызова функции.

  • Адрес обработчика исключений для функции.

  • Параметры уязвимой функции.

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

На платформе x86, если функция использует обработчик исключений, при компиляции также вставляется объект cookie для защиты адреса обработчика исключений. Этот объект cookie проверяется при очистке кадра.

Параметр /GS защищает уязвимые параметры, передаваемые в функцию. К уязвимым параметрам относятся указатели, ссылки C++, структуры C (тип POD C++), в которых содержатся указатели, а также буферы GC.

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

Компилятор не создает копии уязвимых параметров в следующих случаях:

  • Функции, которые не содержат буферов GS.

  • Оптимизации (параметры /O) не включены.

  • Функции, имеющие список аргументов переменной (...).

  • Функции, помеченные с помощью атрибута naked.

  • Функции, в первом операторе которых содержится встроенный код ассемблера.

  • Параметр применяется только таким образом, чтобы обеспечивалась минимальная возможность его использования в случае переполнения буфера.

Что не защищается

Параметр компилятора /GS не обеспечивает защиту от всех атак на систему безопасности, связанных с переполнением буфера. Например, если в объекте используются буфер и таблица vtable, при переполнении буфера возможно повреждение таблицы vtable.

Даже при использовании /GS всегда пытайтесь писать безопасный код, не имеющий переполнений буфера.

Установка параметра компилятора в Visual Studio

  1. В обозревателе решений щелкните правой кнопкой мыши проект и выберите пункт Свойства.

    Дополнительные сведения см. в разделе Открытие свойств страниц проекта.

  2. В диалоговом окне Страницы свойств щелкните папку C/C++.

  3. Выберите страницу свойств Создание кода.

  4. Измените значение свойства Проверка переполнения буфера.

Установка этого параметра компилятора программным способом

Пример

В этом примере происходит переполнение буфера. Это приведет к сбою приложения во время выполнения.

// compile with: /c /W1
#include <cstring>
#include <stdlib.h>
#pragma warning(disable : 4996)   // for strcpy use

// Vulnerable function
void vulnerable(const char *str) {
   char buffer[10];
   strcpy(buffer, str); // overrun buffer !!!

   // use a secure CRT function to help prevent buffer overruns
   // truncate string to fit a 10 byte buffer
   // strncpy_s(buffer, _countof(buffer), str, _TRUNCATE);
}

int main() {
   // declare buffer that is bigger than expected
   char large_buffer[] = "This string is longer than 10 characters!!";
   vulnerable(large_buffer);
}

См. также

Ссылки

Параметры компилятора

Настройка параметров компилятора