/GS (vérification de la sécurité des mémoires tampons)
Détecte des dépassements de mémoire tampon qui remplacent l’adresse de retour d’une fonction, l’adresse du gestionnaire d’exceptions ou certains types de paramètres. La cause d’un dépassement de mémoire tampon est une technique utilisée par les pirates pour exploiter le code qui n’applique pas de restrictions de taille de mémoire tampon.
Syntaxe
/GS[-]
Notes
/GS est activé par défaut. Si vous attendez que votre application n’ait aucune exposition de sécurité, utilisez /GS-. Pour plus d’informations sur la suppression de la détection de dépassement de mémoire tampon, consultez safebuffers.
Vérifications de sécurité
Sur les fonctions que le compilateur reconnaît comme étant sujettes à des problèmes de dépassement de mémoire tampon, le compilateur alloue de l’espace sur la pile avant l’adresse de retour. Lors de l’entrée de fonction, l’espace alloué est chargé avec un cookie de sécurité calculé une fois au chargement du module. Lors de la sortie de la fonction et pendant le déroulement de l’image sur les systèmes d’exploitation 64 bits, une fonction d’assistance est appelée pour s’assurer que la valeur du cookie est toujours la même. Une valeur différente indique qu’un remplacement de la pile peut s’être produit. Si une autre valeur est détectée, le processus est arrêté.
Mémoires tampons GS
Un contrôle de sécurité de dépassement de mémoire tampon est effectué sur une mémoire tampon GS. Une mémoire tampon GS peut être l’une des suivantes :
Un tableau qui est supérieur à 4 octets, a plus de deux éléments et a un type d’élément qui n’est pas un type de pointeur.
Structure de données dont la taille est supérieure à 8 octets et ne contient aucun pointeur.
Mémoire tampon allouée à l’aide de la fonction _alloca .
Toute classe ou structure qui contient une mémoire tampon GS.
Par exemple, les instructions suivantes déclarent des mémoires tampons GS.
char buffer[20];
int buffer[20];
struct { int a; int b; int c; int d; } myStruct;
struct { int a; char buf[20]; };
Toutefois, les instructions suivantes ne déclarent pas de mémoires tampons GS. Les deux premières déclarations contiennent des éléments de type pointeur. Les troisième et quatrième instructions déclarent des tableaux dont la taille est trop petite. La cinquième instruction déclare une structure dont la taille sur une plateforme x86 n’est pas supérieure à 8 octets.
char *pBuf[20];
void *pv[20];
char buf[4];
int buf[2];
struct { int a; int b; };
Initialiser le cookie de sécurité
L’option du compilateur /GS exige que le cookie de sécurité soit initialisé avant toute fonction qui utilise le cookie est exécutée. Le cookie de sécurité doit être initialisé immédiatement lors de l’entrée dans un EXE ou une DLL. Cette opération est effectuée automatiquement si vous utilisez les points d’entrée VCRuntime par défaut : mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, wWinMainCRTStartup ou _DllMainCRTStartup. Si vous utilisez un autre point d’entrée, vous devez initialiser manuellement le cookie de sécurité en appelant __security_init_cookie.
Qu’est-ce qui est protégé
L’option du compilateur /GS protège les éléments suivants :
Adresse de retour d’un appel de fonction.
Adresse d’un gestionnaire d’exceptions pour une fonction.
Paramètres de fonction vulnérables.
Sur toutes les plateformes, /GS tente de détecter les dépassements de mémoire tampon dans l’adresse de retour. Les dépassements de mémoire tampon sont plus facilement exploités sur des plateformes telles que x86 et x64, qui utilisent des conventions d’appel qui stockent l’adresse de retour d’un appel de fonction sur la pile.
Sur x86, si une fonction utilise un gestionnaire d’exceptions, le compilateur injecte un cookie de sécurité pour protéger l’adresse du gestionnaire d’exceptions. Le cookie est vérifié pendant le déroulement de l’image.
/GS protège les paramètres vulnérables passés dans une fonction. Un paramètre vulnérable est un pointeur, une référence C++, une structure C (type POD C++) qui contient un pointeur ou une mémoire tampon GS.
Un paramètre vulnérable est alloué 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 entraîner une attaque avant que la fonction ne retourne et que la vérification de sécurité soit effectuée. Pour réduire ce danger, le compilateur effectue une copie des paramètres vulnérables pendant le prolog de fonction et les place sous la zone de stockage pour toutes les mémoires tampons.
Le compilateur n’effectue pas de copies de paramètres vulnérables dans les situations suivantes :
Fonctions qui ne contiennent pas de mémoire tampon GS.
Les optimisations (options/S) ne sont pas activées.
Fonctions qui ont une liste d’arguments variables (...).
Fonctions marquées avec nu.
Fonctions qui contiennent du code d’assembly inline dans la première instruction.
Un paramètre est utilisé uniquement de manière moins susceptible d’être exploitable en cas de dépassement de mémoire tampon.
Ce qui n’est pas protégé
L’option du compilateur /GS ne protège pas contre toutes les attaques de sécurité de dépassement de mémoire tampon. Par exemple, si vous disposez d’une mémoire tampon et d’une table virtuelle dans un objet, un dépassement de mémoire tampon peut endommager la table virtuelle.
Même si vous utilisez /GS, essayez toujours d’écrire du code sécurisé sans dépassement de mémoire tampon.
Pour définir cette option de compilateur dans Visual Studio
Ouvrez la boîte de dialogue Pages de propriété du projet. Pour plus d’informations, consultez Définir le compilateur C++ et les propriétés de build dans Visual Studio.
Sélectionnez la page de propriétés De configuration>C/C++>Génération de code.
Modifiez la propriété Buffer Security Check .
Pour définir cette option du compilateur par programmation
- Consultez BufferSecurityCheck.
Exemple
Cet exemple dépasse une mémoire tampon. Cela provoque l’échec de l’application au moment de 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);
}
Voir aussi
Options du compilateur MSVC
Syntaxe de la ligne de commande du compilateur MSVC