Sutureは、LLVM IRに基づいた静的な点から高次の汚染分析ツール(c)であり、Dr。Checkerに基づいて構築されています(クリエイターのおかげです!)、2つのハイライトは次のとおりです。
私たちは、それが外科的に正確であることを期待して、それを縫合と命名し、複数のシステム/入力関数を一緒に縫い合わせて高次のデータフローを構築できるようにします。詳細については、私たちの論文を参照してください。ACMCCS'21のOSカーネルの高次汚染スタイルの脆弱性を静的に発見してください。
最初にリポジトリをクローンします:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
次に、縫合のLLVM環境をセットアップします。
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
オプション( setup_suture.pyの場合):
-bこのLLVMミラーリポジトリでは、縫合用に設定されるLLVMのブランチ名を指定します。-o suture(llvmなど)に必要なすべてのものをホストするフォルダーを指定し、任意のフォルダーを使用します。ハードウェアに応じて、LLVMのセットアップにはかなりの時間がかかる場合があります。終了した後、 env.shという名前のsrciptファイルが縫合ルートフォルダーの下に生成され、縫合糸で使用される環境変数を設定するコマンドが含まれます。
重要:縫合糸を構築/使用する前に、このenv.sh毎回アクティブにしてください(シェルログイン時に自動アクティベーションのために、含まれるコマンドを.bashrcに追加することもできます)!
~/suture$ source env.sh
次に、縫合を構築します:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
ビルドを成功させると、縫合は使用できます。
縫合は、すぐに装備の脆弱性を発見するために使用できます。このセクションでは、このプロセスを例にとって進みます(例えば、論文のセクション2.1に示すように動機付けの例)。
脆弱性を発見するには、縫合には2種類の入力が必要です。(1)LLVMビットコードにコンパイルされたプログラムモジュール( .bcファイルなど)、および(2)エントリ機能とユーザー制御された引数を示すモジュールの構成ファイル。
まず、やる気を起こさせる例のためにLLVMビットコードを準備しましょう。
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
注:利便性のために、 -O1最適化レベルで、 A .Cから.ll (Human Readable LLVM BitCode)をコンパイルするためにgen.shを提供します。
これで、同じベンチマークフォルダーの下にMotivating_example.bcを使用する必要があります。これが縫合の入力プログラムモジュールです。
その後、構成ファイルになります。動機付けの例を既に準備しています。
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
説明:構成ファイルの各行は、プログラムモジュールの1つのエントリ関数(例えば、通常は外部インターフェイスとして機能するトップレベル関数と通常は外部インターフェイスとして機能する)の情報を説明します。
entry_x MY_IOCTL 0_2などのconfig 'fike configで指定できます。したがって、上記のように、 conf_motivating_exampleは、 mytivating_example.cに3つのエントリ関数があることを指定します: entry0 (パラメーター1はユーザー制御)、 entry1 、およびentry2 (ユーザー制御パラメーターなし)です。これは、やる気のある例のコードと一致します。
プログラムビットコードとエントリ構成ファイルの準備ができたら、縫合を実行して汚染の脆弱性を発見できます。
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
説明: run_nohup.shは、縫合糸のコンパイルされたLLVM分析パスを呼び出す簡単なスクリプトです。
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
開始すると、実際のハードウェアとターゲットプログラムの複雑さに応じて、縫合が分析と脆弱性の発見を完了するために必要な時間は大きく異なります。ただし、やる気のある例のような簡単なプログラムは、通常、即座に終了します。
分析が終了するかどうかを決定します。実行中、Sutureはエントリ構成ファイルの同じディレクトリの下のファイルにログインし続けます。構成ファイルパスが/path/to/conf_programであると仮定します。ログを監視することで分析が終了するかどうかを判断できます。
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
前述のログファイルも縫合の出力であり、縫合はログファイルに発見された潜在的な脆弱性を埋め込み、分析が終了した後に抽出して最終警告レポートに編成できます。
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
説明: ext_warns.shは、指定されたログファイルに埋め込まれたすべての警告(JSON)を抽出し、それらを再編成して最終警告レポートにかなりプリントします。ログファイルの同じパスの下にある警告レポートがフォルダーに配置されます。ログファイルが/path/to/conf_program.logであると仮定します。警告レポートフォルダーは/path/to/warns-conf_program-yyy-mm-ddになります。
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
フォルダーには5つの警告レポートがあります。すべてにデータフロー関係に従ってグループ化されたあらゆるタイプの警告が含まれていますが、他のレポートには特定のタイプの警告のみが含まれています(整数オーバーフロー、汚染されたポインターの繰り返しなど)。通常、統一レポートはすべて使用します。
~/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
説明:高レベルでは、警告レポートにはいくつかの警告グループが含まれており、各グループにはいくつかの警告が含まれており、各警告にはユーザーの入力と同じ機密プログラムステートメントに沈むいくつかの汚染トレースが含まれています。言い換えれば、特定のプログラムステートメントと特定のタイプ(整数オーバーフローなど)に対して1つの警告が提起されますが、グループにはデータフローの観点から複数の密接に関連する警告が含まれています(論文のセクション4を参照)。したがって、グループには複数の警告されたプログラムステートメントがあり、異なる警告タイプが含まれる場合があります。
上記の警告レポートを例として受け取ります。
===GROUP No. (min_order - max_order)===です。ここで、 min_orderは最小注文です(たとえば、簡単に言えば、注文は汚染伝播に必要なエントリ関数のmax_orderの時間です。WARN No.そのグループにローカルであることに注意してください。***Trace No. (order)***に従って、警告の汚染トレースのヘッダーラインは、常に計算できる一意の順序を持っています(範囲ではなく)。警告レポートは、動機付けの例で有効な整数オーバーフローの脆弱性を特定しますが、より正確ではない静的解析ツールが生成する可能性のある潜在的な虚偽アラームを回避する一方で、詳細は論文のセクション2.1に記載されています。
このリポジトリには、便利だと思われる他のツール/スクリプトも含まれています。
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
説明:このスクリプトは、Linuxデバイスドライバーモジュール(例: ioctl() 、 read() 、 write()など)のいくつかの一般的なエントリ関数を識別できます。このユーティリティは、主にいくつかのカーネルドメインの知識(ドライバーのエントリポイントを定義するために使用されるFILE_OPERATIONSなどの特定のデータ構造)に基づいた元のDr. Checkerによって実装され、その後、いくつかの改善を行いました(例えば、ヒューリスティックをより堅牢にします)。
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
説明:私たちの経験から、警告レポートの多くの誤ったアラームは、多くの場合、同じ問題のあるサブ固定トレースを共有しています(論文のセクション6.3を参照)。警告レビュアーが1つの誤報を検査し、FP誘導サブトレースを認識している限り、当然、彼女は同じサブトレースを含む他のすべての同様の誤報を自動的に除外して、レビュアー認識の誤報速度を削減することができます。この目的のために、元の警告レポートとPythonの正規表現を入力として取得するこの単純なflt_warns.pyを提供します。その後、レポートのすべての汚染トレースと一致し、一致すると、汚染トレースは誤報として扱われます。スクリプトは、一致したすべての汚染トレースを除く新しいフィルタリングされた警告レポートを生成します。
縫合糸を汎用の静的分析として使用することに興味があるかもしれません(たとえば、特定のプログラムの場所で変数のポイントツー/汚染セットを取得します)、これは確かに実行可能ですが、脆弱性の発見とは異なり、主要なデータ構造といくつかの重要な機能に慣れているために手を汚し、縫合糸のコードに飛び込む必要があります。次のヒントが役立つことを願っています:
LLVMは、後方互換性を保証することなく、非常に迅速に進化します。そのため、新しいLLVMバージョン(> 9.0)で縫合を構築しようとすると、いくつかのコンピレーションエラーが発生する可能性が非常に高くなります。しかし、幸いなことに、そのようなコンピレーションエラーは通常簡単に解決できます(たとえば、多くの場合、日付外のLLVM APIを新しいものに置き換える必要があります)。基本的に、縫合糸を新しいLLVMバージョンに適応させるには、最初に0x0に新しいLLVMをセットアップする必要があります(たとえば、 setup_suture.pyをアクティブソースからLLVMリポジトリをクローン化し、新しいブランチ名を指定する必要があります)。