Comment sécuriser C



Le langage C est très puissant et est beaucoup utilisé là où - en particulier dans le noyau Linux - mais il est également très dangereux. Un développeur de noyau Linux a décrit comment gérer les vulnérabilités de sécurité C.

Vous pouvez faire presque n'importe quoi en C, mais cela ne signifie pas que cela doit être fait. Le code C est très rapide, mais porté sans ceinture de sécurité. Même si vous êtes un expert, comme la plupart des développeurs de noyaux Linux , des erreurs de tueur sont toujours possibles.

En plus des pièges tels que les alias de pointeurs , C a des erreurs fondamentales non corrigées qui attendent leurs victimes. Ce sont les vulnérabilités que Case Cook , ingénieur en sécurité du noyau Google Linux, a corrigées lors de la Linux Security Conference à Vancouver.

«C est une sorte d'assembleur. C'est presque du code machine », a déclaré Cook, se référant à un public de plusieurs centaines de collègues qui comprennent et apprécient la vitesse des applications sur C. Mais la mauvaise nouvelle est que« C vient avec des bagages dangereux, un comportement vague et d'autres faiblesses qui conduisent à des failles de sécurité et des infrastructures vulnérables. »

Si vous utilisez C dans vos projets, vous devez faire attention aux problèmes de sécurité.

Protection du noyau Linux


Au fil du temps, Cook et ses collègues ont découvert de nombreux problèmes avec le C. natif. Pour y remédier, le Kernel Self Protection Project a été lancé. Il travaille lentement et régulièrement pour protéger le noyau Linux contre les attaques, en supprimant le code problématique à partir de là.

C'est compliqué, dit Cook, parce que "le noyau doit faire des choses très spécifiques à une architecture particulière pour la gestion de la mémoire, la gestion des interruptions, le délestage, etc." Une grande quantité de code fait référence à des tâches spécifiques qui doivent être soigneusement vérifiées. Par exemple, "C n'a pas d'API pour définir des tables de pages ou passer en mode 64 bits", a-t-il déclaré.

Avec une telle charge et avec des bibliothèques standard faibles en C, le comportement est trop vague. Cook a cité - et a accepté - l'article du blog de Raf Levien, "Avec un comportement indéfini, tout est possible" .

Cook a donné des exemples spécifiques: «Quel est le contenu des variables« non initialisées »? C'est tout ce qui était dans ma mémoire avant! Il n'y a pas de types dans les pointeurs void, mais les fonctions tapées peuvent-elles être appelées à travers eux? Bien sûr! Le montage est tout de même: vous pouvez contacter n'importe quelle adresse! Pourquoi memcpy() n'a-t-il pas l'argument «longueur de destination maximale»? Peu importe, faites comme vous le dites; toutes les zones de mémoire sont les mêmes! ”

Ignorer les avertissements ... mais pas toujours


Certaines de ces fonctionnalités sont relativement faciles à gérer. Cook a commenté: «Linus [Torvalds] aime l'idée de toujours initialiser les variables locales. Alors fais-le. »

Mais avec une réserve. Si vous initialisez une variable locale dans switch, vous recevrez un avertissement: «L'instruction ne sera jamais exécutée [-Wswitch-unreachable] » en raison de la façon dont le compilateur traite le code. Cet avertissement peut être ignoré.

Mais tous les avertissements ne peuvent pas être ignorés. "Les tableaux de longueur variable sont toujours mauvais", a déclaré Cook. D'autres problèmes incluent l'épuisement de la pile, le débordement de ligne et les violations de protection de page. En outre, Cook a attiré l'attention sur la lenteur de VLA . La suppression de tous les VLA du noyau a augmenté les performances de 13%. L'amélioration de la vitesse et de la sécurité est un double avantage.

Bien que les VLA aient été presque supprimés du noyau, ils sont toujours restés dans du code. Heureusement, les VLA sont faciles à trouver en utilisant l' -Wvla compilateur -Wvla .

Un autre problème est caché dans la sémantique de C. Si la rupture est manquante dans le commutateur, alors que voulait dire le programmeur? Sauter la pause peut conduire à l'exécution de code à partir de plusieurs conditions; Il s'agit d'un problème bien connu.

Si vous recherchez des instructions break / switch dans le code existant, vous pouvez utiliser -Wimplicit-fallthrough pour ajouter une nouvelle instruction switch. C'est en fait un commentaire, mais les compilateurs modernes l'analysent. Vous pouvez également marquer explicitement l’absence de rupture par un commentaire «fallthrough» .

Cook a également constaté un impact sur les performances lors de la vérification des limites d' allocation de mémoire de dalle . Par exemple, la vérification de strcpy()-family réduit les performances de 2%. Des alternatives comme strncpy() leurs propres problèmes. Il s'avère que Strncpy ne se termine pas toujours par un caractère nul. Cook s'est tristement adressé au public: «Où puis-je obtenir les meilleures API?»

Lors d'une session de questions / réponses, un développeur Linux a demandé: «Puis-je me débarrasser des anciennes et mauvaises API?» Cook a répondu que Linux supportait le concept des API héritées depuis un certain temps. Néanmoins, Torvalds a rejeté cette idée, arguant que si une API est obsolète, elle devrait être complètement jetée. Cependant, abandonner pour toujours l'API est «politiquement dangereux», a ajouté Cook. Alors pendant que nous sommes coincés.

Solution à long terme au problème? Plus de développeurs comprenant les problèmes de sécurité


Cook prévoit un voyage long et difficile. L'idée de créer un dialecte Linux C semblait autrefois attrayante, mais elle ne le sera pas. Le vrai problème avec le code dangereux est que "les gens ne veulent pas faire le travail de nettoyage du code - non seulement du mauvais code, mais du C lui-même", a-t-il déclaré. Comme pour tous les projets open source, «nous avons besoin de plus de développeurs, de réviseurs, de testeurs et de spécialistes de backport dédiés.»

Dangerous C: leçons


  • C est un langage mature et puissant, mais il crée des difficultés techniques et des problèmes de sécurité.
  • Les développeurs Linux accordent une attention particulière à la sécurisation de C (sans perdre sa puissance), car la plupart du système d'exploitation est écrit dessus.
  • L'ingénieur de sécurité du noyau Linux Linux a identifié des vulnérabilités linguistiques spécifiques et expliqué comment les éviter.

Source: https://habr.com/ru/post/fr422623/


All Articles