Les limites de la fonction scanf




La fonction scanf(), que je vous ai présentée dès le début du cours de C, est une fonction à double tranchant :


elle est facile à utiliser quand on débute (c'est pour ça que je vous l'ai présentée)…

… mais son fonctionnement interne est complexe et elle peut même être dangereuse dans certains cas.


C'est un peu contradictoire, n'est-ce pas ? En fait, scanf a l'air facile à utiliser, mais elle ne l'est pas en pratique. Je vais vous montrer ses limites par deux exemples concrets.

Entrer une chaîne de caractères avec des espaces


Supposons qu'on demande une chaîne de caractères à l'utilisateur, mais que celui-ci insère un espace dans sa chaîne :

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

    char nom[20] = {0};

 

    printf("Quel est votre nom ? ");

    scanf("%s", nom);

    printf("Ah ! Vous vous appelez donc %s !\n\n", nom);

 

    return 0;

}



Quel est votre nom ? Jean Dupont

Ah ! Vous vous appelez donc Jean !


Pourquoi le « Dupont » a disparu ?


Parce que la fonction scanf s'arrête si elle tombe au cours de sa lecture sur un espace, une tabulation ou une entrée.

Vous ne pouvez donc pas récupérer la chaîne si celle-ci comporte un espace.


En fait, le mot "Dupont" se trouve toujours en mémoire, dans ce qu'on appelle le buffer. La prochaine fois qu'on appellera scanf, la fonction lira toute seule le mot « Dupont » qui était resté en attente dans la mémoire.


On peut utiliser la fonction scanf de telle sorte qu'elle lise les espaces, mais c'est assez compliqué. Si vous voulez apprendre à bien vous servir de scanf, on peut trouver des cours très détaillés sur le web, notamment un tutoriel de Developpez.com (attention, c'est assez difficile).

Entrer une chaîne de caractères trop longue


Il y a un autre problème, beaucoup plus grave encore : celui du dépassement de mémoire.

Dans le code que nous venons de voir, il y a la ligne suivante :

1

char nom[5] = {0};


Vous voyez que j'ai alloué 5 cases pour mon tableau de char appelé nom. Cela signifie qu'il y a la place d'écrire 4 caractères, le dernier étant toujours réservé au caractère de fin de chaîne \0.


Revoyez absolument le cours sur les chaînes de caractères si vous avez oublié tout cela.

La fig. suivante vous présente l'espace qui a été alloué pour nom.





Que se passe-t-il si vous écrivez plus de caractères qu'il n'y a d'espace prévu pour les stocker ?

Quel est votre nom ? Patrice

Ah ! Vous vous appelez donc Patrice !


A priori, il ne s'est rien passé. Et pourtant, ce que vous voyez là est un véritable cauchemar de programmeur !

On dit qu'on vient de faire un dépassement de mémoire, aussi appelé buffer overflow en anglais.

Comme vous le voyez sur la fig. suivante, on avait alloué 5 cases pour stocker le nom, mais en fait il en fallait 8. Qu'a fait la fonction scanf ? Elle a continué à écrire à la suite en mémoire comme si de rien n'était ! Elle a écrit dans des zones mémoire qui n'étaient pas prévues pour cela.






Les caractères en trop ont « écrasé » d'autres informations en mémoire. C'est ce qu'on appelle un buffer overflow (fig. suivante).




En quoi cela est-il dangereux ?


Sans entrer dans les détails, car on pourrait en parler pendant 50 pages sans avoir fini, il faut savoir que si le programme ne contrôle pas ce genre de cas, l'utilisateur peut écrire ce qu'il veut à la suite en mémoire. En particulier, il peut insérer du code en mémoire et faire en sorte qu'il soit exécuté par le programme. C'est l'attaque par buffer overflow, une attaque de pirate célèbre mais difficile à réaliser.


Si cela vous intéresse, vous pouvez lire l'article « Dépassement de tampon » de Wikipédia (attention c'est quand même assez compliqué).

Le but de ce chapitre sera de sécuriser la saisie de nos données, en empêchant l'utilisateur de faire déborder et de provoquer un buffer overflow. Bien sûr, on pourrait allouer un très grand tableau (10 000 caractères), mais ça ne changerait rien au problème : une personne qui veutfaire dépasser de la mémoire n'aura qu'à envoyer plus de 10 000 caractères et son attaque marchera tout aussi bien.

Aussi bête que cela puisse paraître, tous les programmeurs n'ont pas toujours fait attention à cela. S'ils avaient fait les choses proprement depuis le début, une bonne partie des failles de sécurité dont on entend parler encore aujourd'hui ne serait jamais apparue !

Créé avec HelpNDoc Personal Edition: Produire des aides en ligne pour les applications Qt