/GS (Comprobación de seguridad del búfer)
Detecta algunas saturaciones de búfer que sobrescriben el remite de una función, dirección del controlador de excepciones o ciertos tipos de parámetros. Producir una saturación del búfer es una técnica utilizada por los piratas informáticos para aprovechar que el código no impone restricciones del tamaño de búfer.
/GS[-]
Comentarios
De manera predeterminada, /GS está habilitada. Si cree que su aplicación no se va a ver expuesta a ningún riesgo de seguridad, use /GS-. Para obtener más información sobre /GS, vea Compiler Security Checks In Depth. Para obtener más información acerca de la detección de la supresión de saturación del búfer, vea safebuffers.
Comprobaciones de seguridad
En las funciones que el compilador reconoce como sujeto a problemas de saturación de búfer, el compilador asigna espacio en la pila antes de la dirección de retorno. En la entrada de la función, se carga una cookie de seguridad en el espacio asignado, que se procesa una vez durante la carga del módulo. A la salida de la función, y durante el desenredo del marco en sistemas operativos de 64 bits, se llama a una función auxiliar para asegurarse de que el valor de la cookie todavía es el mismo. Un valor diferente indica que se puede haber producido una sobrescritura de la pila. Si se detecta un valor diferente, se finaliza el proceso.
Búferes GS
Se realiza una comprobación de seguridad de saturación del búfer en un búfer GS. Un búfer GS puede ser uno de éstos:
Matriz que tiene más de 4 bytes, tiene más de dos elementos y tiene un elemento que no es de tipo de puntero.
Una estructura de datos cuyo tamaño es más de 8 bytes y no contiene punteros.
Un búfer asignado mediante la función _alloca.
Cualquier clase o estructura que contiene un búfer GS.
Por ejemplo, las siguientes instrucciones declaran los búferes GS.
char buffer[20];
int buffer[20];
struct { int a; int b; int c; int d; } myStruct;
struct { int a; char buf[20]; };
Sin embargo, las siguientes instrucciones no declaran búferes GS. Las primeras dos declaraciones contienen elementos de tipo de puntero. Las instrucciones tercera y cuarta declaran matrices cuyo tamaño es demasiado pequeño. La quinta instrucción declara una estructura cuyo tamaño en una plataforma x86 no es mayor de 8 bytes.
char *pBuf[20];
void *pv[20];
char buf[4];
int buf[2];
struct { int a; int b; };
Inicializar la cookie de seguridad
La opción del compilador /GS requiere que se inicialice la cookie de seguridad antes de que se ejecute cualquier función que use la cookie. La cookie de seguridad se debe inicializar en la entrada a un archivo EXE o DLL. Automáticamente se hace esto si utiliza los puntos de entrada predeterminados de CRT (mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup o _DllMainCRTStartup). Si usa un punto de entrada alternativo, debe inicializar manualmente la cookie de seguridad llamando a __security_init_cookie.
Lo que está protegido
La opción del compilador /GS protege los elementos siguientes:
Dirección de devolución de una llamada de función.
La dirección de un controlador de excepciones para una función.
Parámetros de función vulnerables.
En todas las plataformas, /GS intenta detectar saturaciones de búfer en la dirección de devolución. Las saturaciones de búfer se utilizan con mayor facilidad en plataformas como x86 y x64, que usan convenciones de llamada para almacenar la dirección de retorno de una llamada a función en la pila.
En x86, si una función usa un controlador de excepciones, el compilador inserta una cookie de seguridad para proteger la dirección del controlador de excepciones de la función. La cookie se comprueba durante el desenredo del marco.
/GS protege los parámetros vulnerables que se pasan en una función. Un parámetro vulnerable es un puntero, una referencia de C++, una estructura C (del tipo POD de C++) que contiene un puntero o un búfer GS.
Un parámetro vulnerable se asigna antes de la cookie y las variables locales. Una saturación del búfer puede sobrescribir estos parámetros. Y el código de la función que usa estos parámetros puede provocar un ataque antes de que se devuelva la función y se realice la comprobación de seguridad. Para reducir este riesgo, el compilador realiza una copia de los parámetros vulnerables durante el prólogo de la función y los colocará bajo el área de almacenamiento de cualquier búfer.
El compilador no realiza copias de los parámetros vulnerables en las siguientes situaciones:
Funciones que no contienen un búfer GS.
No se habilitan las optimizaciones (opciones /O).
Funciones que tienen una lista de argumentos variable (...).
Funciones que se marcan con naked.
Funciones que contienen código de ensamblado alineado en la primera instrucción.
Un parámetro sólo se utiliza de manera que sea poco probable que se pueda usar de forma malintencionada en caso de una saturación del búfer.
Lo que no está protegido
La opción del compilador /GS no protege frente a todos los ataques a la seguridad relacionados con la saturación del búfer. Por ejemplo, si tiene un búfer y vtable en un objeto, la saturación de un búfer podría dañar vtable.
Incluso cuando utiliza /GS, siempre intente escribir código seguro que no tenga ninguna saturación de búfer.
Para establecer esta opción del compilador en Visual Studio
En el Explorador de soluciones, haga clic con el botón secundario del mouse en el proyecto y, a continuación, seleccione Propiedades.
Para obtener más información, vea Cómo: Abrir páginas de propiedades del proyecto.
En el cuadro de diálogo Páginas de propiedades, haga clic en la carpeta C/C++.
Haga clic en la página de propiedades Generación de código.
Modifique la propiedad Comprobación de seguridad del búfer.
Para establecer esta opción del compilador mediante programación
- Vea BufferSecurityCheck.
Ejemplo
En este ejemplo se satura un búfer. Esto provoca que la aplicación falle en tiempo de ejecución.
// 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);
}