Les débordements de mémoire tampon sont depuis longtemps une source notoire de problèmes de sécurité dans le développement de logiciels. Alors que les assainisseurs ont atténué certaines de ces vulnérabilités en insérant automatiquement un contrôle des limites, les membres de tableaux flexibles sont restés une exception difficile. La taille de ces tableaux est généralement opaque pour le compilateur, ce qui rend difficile la vérification des limites en dehors de la fonction d'allocation.
La solution de Google, mise en œuvre dans Clang et GCC, introduit l'attribut counted_by. Cet attribut référence explicitement le champ qui stocke le nombre d'éléments dans un membre de tableau flexible, ce qui permet à l'assainisseur de limites de tableaux de vérifier les opérations sur ces tableaux.
Cette amélioration permet de remédier à la vulnérabilité critique de la programmation en C liée aux débordements de mémoire tampon, en particulier ceux impliquant des membres de tableaux flexibles dont la taille est déterminée au moment de l'exécution. Cette approche crée une relation implicite entre le membre du tableau flexible et le champ count, améliorant ainsi la capacité des assainisseurs à détecter les débordements potentiels.
Vérification des limites des membres d'un tableau flexible
Les débordements de mémoire tampon sont à l'origine de nombreux problèmes de sécurité et constituent une épine persistante dans le pied des programmeurs. Le langage C y est particulièrement sensible.
L'avènement des assainisseurs atténue certains problèmes de sécurité en insérant automatiquement une vérification des limites, mais ils ne sont pas en mesure de le faire dans toutes les situations ; en particulier pour les membres de tableaux flexibles, car leur taille n'est connue qu'au moment de l'exécution.
La taille d'un membre de tableau flexible est généralement opaque pour le compilateur. L'attribut alloc_size de malloc() peut être utilisé pour vérifier les limites des membres d'un tableau flexible dans la même fonction que l'allocation. Mais l'information de l'attribut n'est pas transportée avec l'objet alloué, ce qui rend impossible l'exécution d'une vérification des limites ailleurs.
Pour pallier cet inconvénient, Clang et GCC introduisent1 l'attribut counted_by pour les membres de tableaux flexibles.
Spécifier le nombre d'éléments d'un membre de tableau flexible
Le nombre d'éléments alloués à un membre de tableau flexible est souvent stocké dans un autre champ de la même structure. Lorsqu'il est appliqué à un membre de tableau flexible, l'attribut counted_by est utilisé par l'assainisseur - activé par -fsanitize=array-bounds - en référençant explicitement le champ qui stocke le nombre d'éléments. L'attribut crée une relation implicite entre le membre de tableau flexible et le champ count, ce qui permet à l'assainisseur de vérifier les opérations sur les tableaux flexibles.
Certaines règles doivent être respectées lors de l'utilisation de cette fonctionnalité. Pour cette structure :
Code : | Sélectionner tout |
1 2 3 4 5 | struct foo { /* ... */ size_t count; /* Number of elements in array */ int array[] __attribute__((counted_by(count))); }; |
- Le champ count doit se trouver dans la même structure englobante non anonyme que le membre du tableau flexible.
- Le champ count doit être défini avant tout accès au tableau.
- Le champ array doit avoir au moins le nombre d'éléments disponibles à tout moment.
* - Le champ count peut changer, mais ne doit jamais être plus grand que le nombre d'éléments alloués à l'origine.
Exemple d'allocation de la structure ci-dessus :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | struct foo *foo_alloc(size_t count) { struct foo *ptr = NULL; size_t size = MAX(sizeof(struct foo), offsetof(struct foo, array[0]) + count * sizeof(p->array[0])); ptr = calloc(1, size); ptr->count = count; return ptr; } |
Utilisations de la fortification
La fortification (activée par la macro _FORTIFY_SOURCE) est un projet en cours visant à rendre le noyau Linux plus sûr. Il se concentre principalement sur la prévention des débordements de mémoire tampon lors des opérations sur la mémoire et les chaînes de caractères.
La fortification utilise les modules __builtin_object_size() et __builtin_dynamic_object_size() pour essayer de déterminer si l'entrée passée dans une fonction est valide (c'est-à-dire "sûre"). Un appel à __builtin_dynamic_object_size() n'est généralement pas en mesure de prendre en compte la taille d'un membre de tableau flexible. Mais avec l'attribut counted_by, il est en mesure de calculer la taille et d'améliorer la sécurité.
Utilisations dans le noyau Linux
L'attribut counted_by est déjà utilisé dans le noyau Linux et permettra de détecter des problèmes tels que les débordements d'entiers, qui ont entraîné un débordement de la mémoire tampon du tas. Google va étendre son utilisation à des membres de tableaux plus flexibles, et renforcer son utilisation à l'avenir.
Conclusion
L'attribut counted_by aide à résoudre un problème de fortification de longue date où les limites de la mémoire d'un membre de tableau flexible ne pouvaient pas être déterminées par le compilateur, rendant ainsi Linux, et d'autres applications renforcées, moins exploitables.
Source : Google
Et vous ?
Quel est votre avis sur le sujet ?
Voir aussi :
Linux Kernel 6.10 est disponible : cette version introduit un nouvel appel système pour atténuer les problèmes de corruption de la mémoire et prend en charge le langage Rust pour l'architecture RISC-V
Google veut absolument vous convaincre de migrer votre PC de Windows vers Linux ChromeOS Flex : non seulement pour la sécurité, mais aussi pour la facilité, la flexibilité et les couts
Faut-il convertir le noyau Linux de C à C++ moderne ? Oui, selon un développeur Linux de longue date. Peter Anvin explique pourquoi, selon lui, il est temps de le faire