
KRF is a Kernelspace Randomized Faulter.
現在、LinuxおよびFreeBSDカーネルをサポートしています。
フォールトインジェクションは、プログラムが呼び出す関数に障害(フォールト)を誘発するソフトウェアテスト技法です。呼び出し先が適切なエラーチェックとハンドリングを怠った場合、これらのフォールトは信頼性の低いアプリケーション動作や悪用可能な脆弱性を引き起こす可能性があります。
多数のユーザー空間フォールトインジェクションシステムとは異なり、KRFはロードされたモジュールを介してカーネル空間で動作します。これにはいくつかの利点があります。
LD_PRELOADに依存しないからです。syscall(3)やインラインアセンブリによる呼び出しにフォールトを注入できます。dlsymをいじるよりも高速でエラーが少ないでしょう。また、いくつかの欠点もあります。
cr0を手動で操作するからです。Linuxにはおそらくアーキテクチャに依存しない方法がどこかにあるでしょう。KRFはLinuxまたはFreeBSDのシステムコールテーブルを書き換えます:krfctlで設定された場合、KRFはフォールト可能なシステムコールを薄いラッパーに置き換えます。
各ラッパーは、設定可能なターゲティングシステムを使用して、特定のpersonality(2)、PID、UID、および/またはGIDを対象にフォールトすべきかどうかをチェックします。プロセスがフォールトされるべきでない場合は、元のシステムコールが呼び出されます。
最後に、ターゲットの呼び出しはランダムな失敗関数によってフォールトされます。例えば、read(2)呼び出しはEBADF、EINTR、EIOなどのいずれかを受け取る可能性があります。
KRFの実装の詳細はブログ記事をご覧ください。
注記: Vagrantをお持ちの場合は、Vagrantfileを使用してビルド手順に進んでください。
KRFはCONFIG_KALLSYMS=1が有効な比較的新しい(4.15+)Linuxカーネルで動作するはずです。
これにはUbuntu 18.04のデフォルトカーネルや、おそらく他の多くの最近のディストリビューションが含まれます。
注記: Vagrantを使用している場合は、これを無視してください。
Cツールチェーン(LinuxではおそらくGCCが必要)の他に、KRFの依存関係はlibelf、カーネルヘッダ、Ruby(>=2.4、コード生成用)のみです。
すべてのプラットフォームでGNU Makeが必要です;FreeBSDはさらにBSD Makeが必要です。
aptを使用するシステムの場合:
sudo apt install gcc make libelf-dev ruby linux-headers-$(uname -r)
git clone https://github.com/trailofbits/krf && cd krf
make -j$(nproc)
sudo make install # モジュールを /lib/modules に、ユーティリティを /usr/local/bin にインストール
sudo make insmod # モジュールをロード
または、Vagrantを使用している場合:
git clone https://github.com/trailofbits/krf && cd krf
vagrant up linux && vagrant ssh linux
# 仮想マシン内
cd /vagrant
make -j$(nproc)
sudo make install # モジュールを /lib/modules に、ユーティリティを /usr/local/bin にインストール
sudo make insmod # モジュールをロード
または、FreeBSDの場合:
git clone https://github.com/trailofbits/krf && cd krf
cd vagrant up freebsd && vagrant ssh freebsd
# 仮想マシン内
cd /vagrant
gmake # make ではなく!
gmake install-module # モジュールを /boot/modules/ にインストール
sudo gmake install-utils # ユーティリティを /usr/local/bin にインストール
gmake insmod # モジュールをロード
KRFには3つのコンポーネントがあります:
krfx)krfexec)krfctl)krfmesg)カーネルモジュールをロードするには、make insmod を実行します。アンロードするには、make rmmod を実行します。
初めて使用する場合は、別のターミナルで sudo krfmesg を起動すると、krfx からのメッセージを表示できるので便利です。
KRFはニュートラルな状態で起動します:ユーザーが krfctl で動作を指定するまで、システムコールはインターセプトまたはフォールトされません。
# 誘発されたフォールトはなし、KRFがロードされていても
ls
# read(2) と write(2) の呼び出しをフォールトするよう指示
# krfctl はルート権限が必要
sudo krfctl -F 'read,write'
# krfexec で起動されたプログラム(personality 28)をフォールトするよう指示
sudo krfctl -T personality=28
# フォールトする可能性あり!
krfexec ls
# 1/100(1%)の確率でフォールトするよう指示
# この値は逆数で表されるため、例えば 1 はフォールト可能なすべてのシステムコールがフォールトすることを意味し、
# 500 は平均して500のシステムコールに1回(1/500 = 0.2%)フォールトすることを意味します
sudo krfctl -p 100
# `io` プロファイル(つまりI/O関連のシステムコール)をフォールトするよう指示
sudo krfctl -P io
# krfexec はオプションも正しく渡します
krfexec echo -n 'no newline'
# フォールト指定をクリア
sudo krfctl -c
# ターゲット指定をクリア
sudo krfctl -C
# フォールトされているシステムコールがないため、誘発されたフォールトはなし
krfexec firefox
注記: ほとんどのユーザーはこれらのファイルを手動で操作する代わりに krfctl を使用すべきです。FreeBSDでは、これらの値は procfs の代わりに sysctl krf.whatever でアクセスできます。
/proc/krf/rng_stateこのファイルを使用すると、KRFのPRNGの内部状態を読み取りおよび変更できます。
例えば、以下のコマンドは状態を正しく更新します:
echo "1234" | sudo tee /proc/krf/rng_state
echo "0777" | sudo tee /proc/krf/rng_state
echo "0xFF" | sudo tee /proc/krf/rng_state
状態は32ビットの符号なし整数です;それを超えて変更しようとすると失敗します。
/proc/krf/targetingこのファイルを使用すると、KRFがシステムコールターゲティングに使用する値を設定できます。
注記: KRFはデフォルトではLinuxカーネルが通常使用しない personality を使用します。これを変更する場合は、Linuxが気にする値にしないように注意してください。詳細は man 2 personality を参照してください。
echo "0 28" | sudo tee /proc/krf/targeting
personality 28 は krfexec にハードコードされており、krfexec で実行されたものがフォールトされるように設定する必要があります。
/proc/krf/probabilityこのファイルを使用すると、特定の(フォールト可能な)システムコールのフォールト確率を読み取りおよび書き込みできます。
確率は逆数で表されます。例えば、1000 は平均でフォールト可能なシステムコールの 0.1% がフォールトされることを意味します。
echo "100000" | sudo tee /proc/krf/probability
/proc/krf/controlこのファイルは、KRFがフォールトするシステムコールを制御します。
注記: ほとんどのユーザーは直接このファイルを操作する代わりに krfctl を使用すべきです。krfctl はシステムコール名から番号への変換を自動的に行い、問題が発生した場合により明確なエラーメッセージを提供します。
# スロット0(通常はSYS_read)のシステムコールをフォールトラッパーに置き換える
echo "0" | sudo tee /proc/krf/control
KRF_NR_SYSCALLS より大きい数を渡すと、KRFはシステムコールテーブル全体をフラッシュし、ニュートラル状態に戻します。KRF_NR_SYSCALLS はLinuxカーネルのバージョンによって予測可能ではないため、大きな数(例えば65535)を選んでも構いません。
フォールトインジェクションラッパーがない有効なシステムコール番号を渡すと、ファイルへの write(2) が EOPNOTSUPP で失敗します。
/proc/krf/log_faultsこのファイルは、フォールトされたシステムコールについてKRFがカーネルログを出力するかどうかを制御します。デフォルトでは、ログメッセージは出力されません。
注記: ほとんどのユーザーは直接このファイルを操作する代わりに krfctl を使用すべきです。
# フォールトログを有効化
echo "1" | sudo tee /proc/krf/log_faults
# フォールトログを無効化
echo "0" | sudo tee /proc/krf/log_faults
# ログ状態を読み取り
cat /proc/krf/log_faults
ENOMEM))を指定できるようにする。
personality(2) 値にさらにビットを追加することで実現可能だろう。KRFのFreeBSDへの初期移植をしてくれたAndrew Reiterに感謝します。Andrewの作業はVeracodeのApplied Research Groupに代わって行われました。
KRFはGNU GPLv3の条件の下でライセンスされています。
正確な条件はLICENSEファイルを参照してください。