Améliorer les tests LLVM grâce à un fuzzing spécialisé
Un nouveau fuzzer améliore la détection des bugs dans le code complexe d'LLVM.
― 7 min lire
Table des matières
Les compilateurs modernes, comme LLVM, sont des morceaux de software super compliqués. À cause de cette complexité, faire des tests réguliers peut pas suffire à attraper tous les bugs. Les méthodes traditionnelles, comme la vérification formelle, peuvent être galères à appliquer à grande échelle. Un moyen de checker les bugs, c'est le Fuzzing, qui envoie des entrées random à la software. Mais le fuzzing ne couvre pas toujours toutes les parties de LLVM efficacement.
Dans ce boulot, on se concentre sur un type spécifique de fuzzing adapté au backend de LLVM. On a développé un nouveau fuzzer qui utilise deux principales techniques pour améliorer les tests. D'abord, il s’assure que les entrées sont valides. Ensuite, il donne un meilleur retour pour guider le processus de test.
Le fuzzer qu'on a créé peut produire une large variété d'entrées valides en LLVM Intermediate Representation (IR). Ça inclut différents flux de contrôle, types de vecteurs, et définitions de fonctions. Pour ça, on a aussi construit des outils qui suivent comment le logiciel se comporte pendant les tests. Comme ça, on peut récolter des retours utiles pour voir quelles parties du code ont été testées et lesquelles ne l'ont pas été.
Nos tests montrent que notre fuzzer surpasse les fuzzer existants lorsqu'il est appliqué aux backends de LLVM. Pendant notre travail, on a découvert de nouveaux bugs dans le code de LLVM, et beaucoup d'entre eux ont déjà été corrigés. Ça indique que notre approche spécialisée au fuzzing peut donner des insights précieux pour les développeurs de LLVM.
Introduction à LLVM et Fuzzing
LLVM est un framework de compilateur largement utilisé qui joue un rôle crucial dans de nombreuses applications software. Il a une grosse base de code avec des millions de lignes écrites en C et C++. Vu son importance dans le monde informatique, s'assurer que LLVM est exempt de bugs est super important. Mais à cause de sa complexité, trouver des bugs peut être galère.
Le fuzzing est une technique de test utilisée pour trouver des failles de sécurité et des bugs en générant automatiquement des entrées random. Cependant, les outils de fuzzing généraux échouent souvent à explorer les diverses entrées possibles efficacement. Pour LLVM, une approche plus spécialisée est nécessaire pour examiner le backend, qui est responsable de la génération de code machine à partir de LLVM IR.
Défis du Fuzzing de LLVM
Le fuzzing de LLVM présente plusieurs défis :
Validité des Entrées : Les entrées générées par les fuzzer typiques sont souvent invalides quand il s'agit de LLVM IR. Beaucoup de chaînes binaires ne correspondent pas à des entrées valides pour le compilateur, ce qui rend difficile le test efficace du backend.
Flux de Contrôle Complexes : Le backend de LLVM a des flux de contrôle complexes qui peuvent ne pas être couverts par la génération d'entrées random. Beaucoup de langages de programmation courants n'exploitent pas toute la gamme des fonctionnalités disponibles dans LLVM.
Spécificités d'Architecture : Différentes architectures peuvent implémenter des instructions personnalisées dans LLVM, ajoutant encore plus de complexité. Ces aspects spécifiques à l'architecture peuvent mener à des bugs supplémentaires qui ne se montrent pas avec des méthodes de fuzzing standard.
Problèmes de Couverture de Branches : Les fuzzer traditionnels se concentrent sur la couverture des bords, ce qui peut ne pas refléter adéquatement quelles parties du backend ont été testées. Générer une mesure significative de couverture pour LLVM est crucial pour un test efficace.
Notre Solution de Fuzzing
Pour relever ces défis, on a conçu un fuzzer spécialisé qui utilise une approche systématique pour créer des LLVM IR valides. Voici les composants clés de notre solution :
1. Génération d'Entrées Valides
La première étape de notre approche est de générer des LLVM IR valides. Notre mutateur s’assure que toutes les entrées générées respectent toujours les règles de LLVM IR. On y arrive en :
Créant des fonctions et définissant des types : On ajoute de nouvelles définitions de fonctions avec des arguments et types de retour appropriés. Ça s'assure que les entrées sont valides et peuvent être compilées sans erreurs.
Maintenant le flux de contrôle : Quand on change le flux de contrôle du programme, on gère soigneusement quels blocs dominent d'autres. Ça empêche les références invalides qui pourraient casser le processus de compilation.
Vérifications de syntaxe : On s'assure que toutes les fonctions et opérations générées respectent les règles de syntaxe de LLVM IR. Cette étape est essentielle pour garantir qu'aucun code invalide n'est produit pendant le processus de fuzzing.
2. Mécanisme de Retour Amélioré
Notre fuzzer inclut aussi un système de retour qui surveille l'exécution du code. En suivant quelles parties du code ont été exécutées, on peut guider plus efficacement les futures mutations. Le retour est basé sur :
Couverture de Table de Correspondance : On suit combien de différents patterns d'instructions ont été testés. Cette nouvelle métrique de couverture donne des insights sur quelles instructions doivent encore être exercées pendant le fuzzing.
Couverture de Branches : On continue d'utiliser la couverture de branches traditionnelle pour surveiller quels chemins à travers le code ont été explorés. Combiner ça avec la couverture de table de correspondance donne une image plus complète de la performance du fuzzer.
Évaluation de Notre Fuzzer
On a testé notre fuzzer sur divers backends matures de LLVM et on a comparé les résultats avec les fuzzer existants, y compris AFL++ et GrayC. Nos découvertes montrent que notre fuzzer spécialisé est beaucoup plus efficace. On a réussi à obtenir une meilleure couverture dans les métriques de branches et de table de correspondance, ce qui indique un test plus complet du code de LLVM.
Pendant notre évaluation, on a aussi identifié plusieurs bugs confirmés dans le code de LLVM. Nos résultats mettent en avant l'importance des techniques de fuzzing spécialisées qui se concentrent sur les caractéristiques uniques des backends de compilateurs.
Contributions au Développement de LLVM
Les bugs qu'on a découverts n'étaient pas juste triviaux ; ils avaient le potentiel de causer des problèmes significatifs dans des applications réelles. Beaucoup de ces bugs étaient passés inaperçus pendant des années, montrant que même les outils établis peuvent bénéficier d'approches de test ciblées.
Notre travail a non seulement identifié des bugs mais aussi fourni des suggestions et des insights que les développeurs de LLVM peuvent utiliser pour améliorer encore leur code. Cette collaboration est essentielle pour pousser les frontières de la qualité et de la sécurité du software.
Conclusion
En résumé, notre fuzzer spécialisé pour la génération de code backend de LLVM démontre que des approches ciblées peuvent dramatiquement améliorer la détection de bugs dans des systèmes complexes. En s'assurant d'entrées valides et en mettant en place un mécanisme de retour robuste, on peut tester efficacement les fonctionnalités complexes de LLVM. Nos découvertes révèlent qu'il reste encore beaucoup à explorer dans le testing de compilateurs, et on espère que notre travail inspire de nouveaux avancements dans ce domaine.
Le paysage du testing logiciel est en constante évolution, et des innovations comme le fuzzing spécialisé pour LLVM continueront de contribuer à la robustesse des infrastructures logiciels critiques. En répondant aux besoins uniques des backends de compilateur, on peut s'assurer que des outils comme LLVM restent fiables pour les développeurs du monde entier.
Titre: IRFuzzer: Specialized Fuzzing for LLVM Backend Code Generation
Résumé: Modern compilers, such as LLVM, are complex pieces of software. Due to their complexity, manual testing is unlikely to suffice, yet formal verification is difficult to scale. End-to-end fuzzing can be used, but it has difficulties in achieving high coverage of some components of LLVM. In this paper, we implement IRFuzzer to investigate the effectiveness of specialized fuzzing of the LLVM compiler backend. We focus on two approaches to improve the fuzzer: guaranteed input validity using constrained mutations and improved feedback quality. The mutator in IRFuzzer is capable of generating a wide range of LLVM IR inputs, including structured control flow, vector types, and function definitions. The system instruments coding patterns in the compiler to monitor the execution status of instruction selection. The instrumentation not only provides a new coverage feedback called matcher table coverage, but also provides an architecture specific guidance to the mutator. We show that IRFuzzer is more effective than existing fuzzers by fuzzing on 29 mature LLVM backend targets. In the process, we reported 74 confirmed new bugs in LLVM upstream, out of which 49 have been fixed, five have been back ported to LLVM 15, showing that specialized fuzzing provides useful and actionable insights to LLVM developers.
Auteurs: Yuyang Rong, Zhanghan Yu, Zhenkai Weng, Stephen Neuendorffer, Hao Chen
Dernière mise à jour: 2024-02-07 00:00:00
Langue: English
Source URL: https://arxiv.org/abs/2402.05256
Source PDF: https://arxiv.org/pdf/2402.05256
Licence: https://creativecommons.org/licenses/by/4.0/
Changements: Ce résumé a été créé avec l'aide de l'IA et peut contenir des inexactitudes. Pour obtenir des informations précises, veuillez vous référer aux documents sources originaux dont les liens figurent ici.
Merci à arxiv pour l'utilisation de son interopérabilité en libre accès.
Liens de référence
- https://github.com/llvm/llvm-project
- https://github.com/rust-lang/rust/issues/9117
- https://github.com/rust-lang/rust/issues/38789
- https://www.overleaf.com/learn/latex/Questions/What_does_%22%5Cpdfendlink_ended_up_in_different_nesting_level_than_%5Cpdfstartlink%22_mean%3F
- https://anonymous.4open.science/status/LLVM-fuzzing-trophies
- https://www.phoronix.com/news/MTY5ODk