/GS (verificação de segurança do buffer)

Detecta algumas saturações de buffer que substituem o endereço de retorno de uma função, o endereço do manipulador de exceção ou determinados tipos de parâmetros. Causar uma saturação de buffer é uma técnica usada por hackers para explorar o código que não impõe restrições de tamanho de buffer.

Sintaxe

/GS[-]

Comentários

/GS fica ativo por padrão. Se você espera que seu aplicativo não tenha exposição de segurança, use /GS-. Para obter mais informações sobre como suprimir a detecção de saturação de buffer, confira safebuffers.

Verificações de segurança

Nas funções que o compilador reconhece como sujeitas a problemas de saturação de buffer, o compilador aloca espaço na pilha antes do endereço de retorno. Na entrada da função, o espaço alocado é carregado com um cookie de segurança que é calculado uma vez na carga do módulo. Na saída da função e durante o desenrolamento do quadro em sistemas operacionais de 64 bits, uma função auxiliar é chamada para garantir que o valor do cookie ainda seja o mesmo. Um valor diferente indica que uma substituição da pilha possa ter ocorrido. Se um valor diferente for detectado, o processo será encerrado.

Buffers GS

Uma verificação de segurança de saturação de buffer é executada em um buffer GS. Um buffer GS pode ser um destes:

  • Uma matriz maior que 4 bytes, com mais de dois elementos e com um tipo de elemento que não é um tipo de ponteiro.

  • Uma estrutura de dados cujo tamanho é maior que 8 bytes e que não contém ponteiros.

  • Um buffer alocado usando a função _alloca.

  • Qualquer classe ou estrutura que contenha um buffer GS.

Por exemplo, as instruções a seguir declaram buffers GS.

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

No entanto, as instruções a seguir não declaram buffers GS. As duas primeiras declarações contêm elementos do tipo de ponteiro. A terceira e quarta instruções declaram matrizes cujo tamanho é muito pequeno. A quinta instrução declara uma estrutura cujo tamanho em uma plataforma x86 não é superior a 8 bytes.

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

A opção do compilador /GS exige que o cookie de segurança seja inicializado antes que qualquer função que use o cookie seja executada. O cookie de segurança deve ser inicializado imediatamente na entrada de um EXE ou DLL. Isso será feito automaticamente se você usar os pontos de entrada padrão mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup ou _DllMainCRTStartup. Se você usar um ponto de entrada alternativo, deverá inicializar manualmente o cookie de segurança chamando __security_init_cookie.

O que é protegido

A opção do compilador /GS protege os seguintes itens:

  • O endereço de retorno de uma chamada de função.

  • O endereço de um manipulador de exceção para uma função.

  • Parâmetros de função vulneráveis.

Em todas as plataformas, a /GS tenta detectar saturações de buffer no endereço de retorno. As saturações de buffer são mais facilmente exploradas em plataformas como x86 e x64, que usam convenções de chamada que armazenam o endereço de retorno de uma chamada de função na pilha.

No x86, se uma função usa um manipulador de exceção, o compilador injeta um cookie de segurança para proteger o endereço do manipulador de exceção. O cookie é verificado durante o desenrolamento do quadro.

A /GS protege parâmetros vulneráveis que são passados para uma função. Um parâmetro vulnerável é um ponteiro, uma referência do C++, uma estrutura do C (tipo de POD do C++) que contém um ponteiro ou um buffer GS.

Um parâmetro vulnerável é alocado antes do cookie e das variáveis locais. Um saturação de buffer pode substituir esses parâmetros. E o código na função que usa esses parâmetros pode causar um ataque antes que a função retorne e a verificação de segurança seja executada. Para minimizar esse perigo, o compilador faz uma cópia dos parâmetros vulneráveis durante o prólogo da função e a coloca abaixo da área de armazenamento de qualquer buffer.

O compilador não faz cópias de parâmetros vulneráveis nas seguintes situações:

  • Funções que não contêm um buffer GS.

  • As otimizações (opções /O) não estão habilitadas.

  • Funções que têm uma lista de argumentos variáveis (...).

  • Funções marcadas com naked.

  • Funções que contêm código de assembly embutido na primeira instrução.

  • Um parâmetro é usado apenas de maneiras menos propensas a exploração no caso de uma saturação de buffer.

O que não é protegido

A opção do compilador /GS não protege contra todos os ataques de segurança de saturação de buffer. Por exemplo, se você tiver um buffer e uma vtable em um objeto, uma saturação de buffer poderá corromper a vtable.

Mesmo que você use a /GS, sempre tente escrever um código seguro que não tenha nenhuma saturação de buffer.

Para definir essa opção do compilador no Visual Studio

  1. Abra a caixa de diálogo Páginas de Propriedades do projeto. Para obter detalhes, confira Definir as propriedades de build e do compilador do C++ no Visual Studio.

  2. Selecione a página de propriedades Propriedades da Configuração>C/C++>Geração de Código.

  3. Modifique a propriedade Verificação de Segurança do Buffer.

Para definir essa opção do compilador via programação

Exemplo

Este exemplo satura um buffer. Isso faz com que o aplicativo falhe no runtime.

// 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);
}

Confira também

Opções do compilador MSVC
Sintaxe da linha de comando do compilador MSVC