La suture est un outil d'analyse de souillure de points à haut niveau statique (pour C) basé sur LLVM IR et construit sur le Dr Checker (merci beaucoup à ses créateurs!), Deux faits saillants sont:
Nous le nommons suture dans l'espoir qu'il peut être précis sur le plan chirurgicalement, tout en étant en mesure de coudre plusieurs systèmes / fonctions d'entrée pour construire des flux de données d'ordre élevé. Pour plus de détails, veuillez vous référer à notre article: Découvrant statiquement les vulnérabilités de style de souillure de haut niveau dans les noyaux OS dans ACM CCS'21 .
Premier cloner le repo:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
Puis configurez l'environnement LLVM pour la suture:
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
Options (pour setup_suture.py ):
-b Spécifie le nom de branche de LLVM à configurer pour SUture, il est par défaut "release_90" (c'est-à-dire LLVM 9.0) dans ce repos miroir llvm.-o Spécifie le dossier pour héberger toutes les choses requises par Suture (par exemple, LLVM), utilisez n'importe quel dossier que vous préférez. Selon votre matériel, la configuration LLVM peut prendre un certain temps. Une fois la fin, un fichier SRCIPT nommé env.sh sera généré sous le dossier racine de suture, il contient des commandes pour définir les variables d'environnement utilisées par suture.
IMPORTANT : Assurez-vous d'activer ce env.sh à chaque fois avant de construire / utiliser une suture (vous pouvez également ajouter ses commandes contenues à .Bashrc pour l'activation automatique lors de la connexion de la coquille)!
~/suture$ source env.sh
Ensuite, nous allons construire une suture:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
Sur une construction réussie, la suture est prête à l'emploi.
La suture peut être utilisée pour découvrir les vulnérabilités de souillure de haut niveau, dans cette section, nous parcourons ce processus avec exemple (par exemple, l'exemple de motivation comme indiqué dans la section 2.1 dans notre article).
Pour découvrir que la suture des vulnérabilités nécessite deux types d'entrée: (1) un module de programme compilé sur LLVM Bitcode (par exemple, un fichier .bc ), et (2) un fichier de configuration pour le module qui manifeste ses fonctions d'entrée et ses arguments contrôlés par l'utilisateur.
Préplions d'abord le Bitcode LLVM pour notre exemple de motivation:
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
Remarque : Pour plus de commodité, nous fournissons gen.sh pour compiler A .C à .BC et .LL (Bitcode Bitcode LLVM lisible par l'homme), avec le niveau d'optimisation -O1 .
Maintenant, nous devrions avoir le motivation_example.bc dans le même dossier de référence , c'est le module de programme d'entrée pour suture.
Ensuite, il arrive dans le fichier de configuration, nous en avons déjà préparé un pour l'exemple de motivation:
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
Explication : Chaque ligne du fichier de configuration décrit les informations d'une fonction d'entrée (par exemple, la fonction de niveau supérieur sans appelants et sert généralement d'interface externe) dans le module de programme, il contient jusqu'à 3 jetons séparés dans l'espace:
entry_x MY_IOCTL 0_2 .Donc, comme indiqué ci-dessus, conf_motivating_example spécifie qu'il existe trois fonctions d'entrée dans motiving_example.c : entrée (Paramètre 1 est contrôlée par l'utilisateur), Entry1 et Entry2 (aucun paramètre contrôlé par l'utilisateur). Cela correspond au code de l'exemple de motivation.
Une fois que le Bitcode du programme et le fichier de configuration d'entrée sont prêts, nous pouvons exécuter la suture pour découvrir les vulnérabilités de souillure:
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
Explication : run_nohup.sh est un script simple invoquant les passes d'analyse LLVM compilées de suture:
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
Une fois commencé, selon le matériel réel et la complexité du programme cible, le temps requis pour la suture pour terminer l'analyse et la découverte de vulnérabilité varie beaucoup. Un programme simple comme notre exemple de motivation se termine généralement instantanément, cependant.
Décidez si l'analyse se termine : lors de l'exécution, SUTURE continue de se connecter à un fichier sous le même répertoire du fichier de configuration de la saisie , supposons que le chemin du fichier de configuration soit / path / vers / conf_program , le fichier journal sera /path/to/conf_program.log . Nous pouvons décider si l'analyse se termine en surveillant le journal:
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
Le fichier journal susmentionné est également la sortie de Suture, Suture intégrera ses vulnérabilités potentielles découvertes dans le fichier journal, qui peut être extraite et organisée dans un rapport d'avertissement final une fois l'analyse terminée:
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
Explication : EXT_WARNS.SH extrait tous les avertissements (en JSON) intégrés dans le fichier journal donné, les réorganiser et les imprimer dans les rapports d'avertissement finaux. Les rapports d'avertissement seront placés dans un dossier sous le même chemin du fichier journal, supposons que le fichier journal soit /path/to/conf_program.log , le dossier du rapport d'avertissement sera / path / to / warns-conf_program-yyyy-mm-dd .
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
Dans le dossier, il y a 5 rapports d'avertissement, tous contient tous les types d'avertissements regroupés en fonction de leur relation de flux de données, tandis que d'autres rapports ne contiennent que des types d'avertissements spécifiques (par exemple, le débordement entier, la déréférence du pointeur contaminé, etc.), plus de détails sur la façon dont nous regroupons des avertissements dans notre article (section 4). Nous n'utilisons généralement que le rapport unifié .
~/suture$ cat -n benchmark/warns-conf_motivating_example-2021-11-10/all
1 =========================GROUP 0 (2 - 2)=========================
2 #####Warned Insts#####
3 (u'motivating_example.c', 30, [u'IntegerOverflowDetector'])
4 ######################
5
6 ++++++++++++++++WARN 0 (2 - 2)++++++++++++++++
7 IntegerOverflowDetector says: motivating_example.c@30 (bar : %add = add i8 %0, -16, !dbg !31)
8 ********Trace 0(2)********
9 #####CTX##### entry0
10 entry0 (motivating_example.c@18)
11 #####INSTS#####
12 >>>>>>>>>>>>>>>>>>tag: 0x55b206570420 tf: 0x55b20695b1b0 (2)>>>>>>>>>>>>>>>>>>
13 motivating_example.c@18 ( %cond = icmp eq i32 %cmd, 0, !dbg !31)
14 motivating_example.c@21 ( store i8 %user_input, i8* getelementptr inbounds (%struct.data, %struct.data* @d, i64 0, i32 1, i64 0), align 4, !dbg !32, !tbaa !34)
15 #####CTX##### entry1 -> bar
16 entry1 (motivating_example.c@35)
17 ----> (motivating_example.c@35 : %call = tail call i32 @bar(i8* bitcast (%struct.data* @d to i8*)), !dbg !27)
18 bar (motivating_example.c@30)
19 #####INSTS#####
20 >>>>>>>>>>>>>>>>>>tag: 0x55b2065e7050 tf: 0x55b2068174f0 (1)>>>>>>>>>>>>>>>>>>
21 motivating_example.c@30 ( %0 = load i8, i8* %add.ptr, align 1, !dbg !31, !tbaa !32)
22 motivating_example.c@30 ( %add = add i8 %0, -16, !dbg !31)
23
Explication : À un niveau élevé, le rapport d'avertissement contient certains groupes d'avertissement, chaque groupe contient plusieurs avertissements et chaque avertissement contient plusieurs traces de souillure provenant d'une entrée et d'un puits d'utilisateur à une même déclaration de programme sensible. En d'autres termes, un avertissement est soulevé pour une certaine déclaration de programme et d'un type spécifique (par exemple, un débordement entier), tandis qu'un groupe contient plusieurs avertissements étroitement liés du point de vue du flux de données (voir la section 4 de notre article), donc un groupe peut avoir plusieurs déclarations de programme averties et inclure différents types d'avertissement.
Prenez le rapport d'avertissement ci-dessus comme exemple:
===GROUP No. (min_order - max_order)=== , où min_order est l'ordre minimal (par exemple, mettre simplement, l'ordre est le temps des invocations de la fonction d'entrée requises dans la propagation de la souillure, voir la section 3.2 dans notre article pour une définition plus formelle.) Du taint trace dans ce groupe et max_order le max.WARN No. est local à son groupe.***Trace No. (order)*** , une trace de souillure a toujours un ordre unique qui peut être calculé (par exemple, pas une plage).Le rapport d'avertissement indique une vulnérabilité de débordement entier valide dans l'exemple de motivation, tout en évitant les fausses alarmes potentielles qu'un outil d'analyse statique moins précis peut générer, des détails peuvent être trouvés dans la section 2.1 de notre article.
Ce dépôt contient également d'autres outils / scripts que vous pouvez trouver utiles.
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
Explication : Ce script peut identifier certaines fonctions d'entrée courantes dans un module de pilote de périphérique Linux (par exemple, ioctl () , read () , write () , etc.), qui aide la construction du fichier de configuration d'entrée comme entrée à suture. Cet utilitaire est principalement mis en œuvre par le Dr Checker d'origine sur la base de certaines connaissances du domaine du noyau (par exemple, des structures de données spécifiques comme File_Operations utilisées pour définir les points d'entrée du pilote), nous avons ensuite apporté quelques améliorations (par exemple, rendre l'heuristique plus robuste).
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
Explication : D'après notre expérience, de nombreuses fausses alarmes dans le rapport d'avertissement partagent souvent une même sous-forme problématique (voir la section 6.3 dans notre article). Tant que le réviseur d'avertissement inspecte une fausse alarme et reconnaît le sous-trace induisant FP, naturellement, elle peut essayer d'exclure automatiquement toutes les autres fausses alarmes similaires contenant le même sous-trace, réduisant le taux de fausses alarmes perçu par le critique. À cette fin, nous fournissons ce simple FLT_WARNS.PY qui prend le rapport d'avertissement d'origine et une expression régulière Python en entrées, il correspondra ensuite à chaque trace de souillure du rapport, une fois apparié, la trace de souillure sera traitée comme une fausse alarme. Le script générera un nouveau rapport d'avertissement filtré à l'exclusion de toutes les traces de souillure correspondantes.
Vous pourriez être intéressé à utiliser la suture comme analyse statique à usage général (par exemple, obtenir l'ensemble de points à souillure d'une variable à un certain emplacement du programme), cela est certainement faisable, mais contrairement à la découverte de vulnérabilité, vous devez vous salir et plonger dans le code de Suture pour être familiarisé avec les principales structures de données qu'il utilise et certaines fonctions importantes. J'espère que les conseils suivants pourront aider:
LLVM évolue très rapidement, sans garantie sur la compatiabilité vers l'arrière. Donc, très probablement, vous rencontrerez des erreurs de compilation lorsque vous essayez de construire une suture avec une version LLVM plus récente (par exemple,> 9.0). Mais heureusement, de telles erreurs de compilation sont généralement faciles à résoudre (par exemple, souvent le cas, nous avons juste besoin de remplacer les API LLVM obsolètes par les plus récentes). Donc, en gros, pour adapter la suture à une version LLVM plus récente, nous devons d'abord configurer un LLVM plus récent dans 0x0 (par exemple, devoir modifier le nom de la branche setup_suture.py pour cloner la suture contre cela, en résolvant les erreurs de compilation décrites.