/GS (Vérification de la sécurité de la mémoire tampon)
Mise à jour : novembre 2007
Détecte certains types de dépassement de mémoire tampon qui écrasent l'adresse de retour, technique courante permettant d'exploiter du code n'appliquant pas de restrictions sur la taille de la mémoire tampon. Cette opération est réalisée par l'injection de contrôles de sécurité dans le code compilé.
/GS[-]
Notes
/GS est activé par défaut. Utilisez /GS- si vous attendez de votre application qu'elle n'ait aucune exposition de sécurité.
Pour plus d'informations sur /GS, consultez Compiler Security Checks In Depth (Contrôles de sécurité approfondis du compilateur).
Le compilateur injecte des contrôles dans les fonctions présentant des mémoires tampons de chaîne locales ou, sur les ordinateurs x86, dans les fonctions intégrant la gestion des exceptions. Une mémoire tampon de chaîne se définit comme un tableau dont la taille des éléments est d'un ou deux octets et la taille totale d'au moins cinq octets, ou comme une mémoire tampon allouée avec _alloca.
Sur toutes les plateformes, le compilateur injecte un cookie pour protéger l'adresse de retour de la fonction si cette dernière contient des mémoires tampons de chaîne locales. Ce cookie est vérifié à la sortie de la fonction, et pendant le déroulement du frame sur les systèmes d'exploitation 64 bits ou sur les ordinateurs x86 pour les fonctions présentant une certaine forme de gestion des exceptions. Sur les ordinateurs x86, le compilateur injecte également un cookie pour protéger l'adresse du gestionnaire d'exceptions de la fonction. Ce cookie est vérifié pendant le déroulement du frame.
/GS tente essentiellement de détecter les dépassements de mémoire tampon directe dans l'adresse de retour. Les dépassements de mémoire tampon sont plus facilement exploités sur les ordinateurs utilisant des conventions d'appel qui stockent l'adresse de retour d'appels de fonction sur la pile. Par exemple, x86 utilise des conventions d'appel qui stockent l'adresse de retour d'appels de fonction sur la pile.
Pour les fonctions que le compilateur pourrait associer à des problèmes de dépassement de mémoire tampon, le compilateur alloue de l'espace sur la pile avant l'adresse de retour. À l'entrée de la fonction, l'espace alloué est chargé avec un cookie de sécurité qui est calculé une fois lors du chargement du module. Ensuite, à la sortie de la fonction, une fonction d'assistance est appelée pour vérifier que la valeur du cookie est toujours la même.
Si la valeur n'est pas la même, un remplacement de la pile s'est éventuellement produit et le processus se termine. Avant Visual C++ 2005, une boîte de dialogue s'affichait pour signaler le remplacement de la pile.
/GS protège également contre les paramètres vulnérables passés dans une fonction. Un paramètre vulnérable est un pointeur, une référence C++ ou une structure-C (type POD C++) qui contient un pointeur, une mémoire tampon de chaîne ou référence C++.
Les paramètres vulnérables sont alloués avant le cookie et les variables locales. Un dépassement de mémoire tampon peut remplacer ces paramètres. Le code de la fonction qui utilise ces paramètres peut conduire à une attaque avant que la fonction retourne et donc éviter la vérification de la sécurité. Pour limiter ce risque, le compilateur effectuera une copie des paramètres vulnérables au cours du prologue de la fonction et les placera au-dessous de la zone de stockage pour les mémoires tampon éventuelles.
Le compilateur ne fournit pas de protection de sécurité pour les paramètres vulnérables dans les situations suivantes :
Fonctions qui ne contiennent pas de mémoire tampon.
Si les optimisations (/O (Optimiser le code), options) ne sont pas activées.
Fonctions avec une liste d'arguments variables (...).
Fonctions marquées avec naked (C++).
Fonctions contenant le code assembleur inline dans la première instruction.
Si un paramètre n'est utilisé que de façon moins susceptible d'être exploitable dans le cas d'un dépassement de mémoire tampon.
/GS nécessite l'initialisation du cookie de sécurité. Ce cookie doit être initialisé avant l'exécution d'une fonction qui utilise le cookie. Il doit être initialisé au point d'entrée dans un EXE ou une DLL. Cette procédure est effectuée automatiquement lorsque vous utilisez les points d'entrée CRT par défaut (mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup ou _DllMainCRTStartup), mais elle doit être effectuée manuellement, via un appel à __security_init_cookie, si vous utilisez un autre point d'entrée.
/GS est pris en charge pour les fonctions managées lors de la compilation avec /clr (Compilation pour le Common Language Runtime).
/GS n'apporte pas de protection contre toutes les attaques de sécurité par dépassement de mémoire tampon. Par exemple, si une mémoire tampon et un vtable sont présents dans un objet, le dépassement de mémoire tampon risque d'endommager le vtable et de permettre à une attaque se produire.
Même si vous utilisez /GS, vous devez vous efforcer d'écrire du code sécurisé. Autrement dit, assurez-vous de l'absence de dépassements de mémoire tampon dans votre code. /GS peut protéger votre application des dépassements de mémoire tampon restant dans votre code.
Pour définir cette option du compilateur dans l'environnement de développement Visual Studio
Ouvrez la boîte de dialogue Pages de propriété du projet. Pour plus d'informations, consultez Comment : ouvrir les pages de propriétés d'un projet.
Cliquez sur le dossier C/C++.
Cliquez sur la page de propriétés Génération de code.
Modifiez la propriété Vérification de la sécurité de la mémoire tampon.
Pour définir cette option du compilateur par programme
- Consultez BufferSecurityCheck.
Exemple
Cet exemple provoque un dépassement de mémoire tampon, ce qui entraîne l'échec de l'application pendant l'exécution.
// 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);
}