KFENCE (Kernel Electric-Fence) は、カーネルコードとモジュール内のメモリ破損を検出し、詳細なエラーレポートを生成する低オーバーヘッドの Linux カーネルツールです。
Alibaba Cloud Linux 3 は、動的な有効化/無効化、スラブ単位のモニタリング、メモリを考慮したプールサイズ設定によって KFENCE を強化し、本番環境とオフラインの両方での使用に対応します。
KFENCE の使用シナリオ
KFENCE は、CPU への影響を最小限に抑えるためにメモリを消費し、2 つの使用シナリオをサポートします。
本番環境でのモニタリング:フリート全体でサンプリングモードを有効にします。十分なアップタイムがあれば、KFENCE はテストワークロードではほとんど実行されないコードパスのバグを検出します。パフォーマンスへの影響は無視でき、最大 2 MiB を消費します。
オフラインデバッグ:フルモードを有効にして、特定のスラブタイプのすべての割り当てをモニタリングします。GiB レベルのメモリを消費しますが、スコープ内のすべての割り当てを検出します。既知の問題を再現するのに最適です。
カーネルおよびモジュールの開発者は、KFENCE を使用してコード内のメモリ破損を検出できます。クラッシュが発生したユーザーは、KFENCE を有効にして、Alibaba Cloud またはサードパーティのドライバー開発者向けにクラッシュデータを収集できます。
前提条件
KFENCE には、Alibaba Cloud Linux 3 の次の最小カーネルバージョンが必要です。
アーキテクチャ | 最小カーネルバージョン |
x86 |
|
Arm |
|
KFENCE と Kernel Address Sanitizer (KASAN) の比較
どちらも、Linux カーネルに組み込まれているメモリ破損検出機能です。Alibaba Cloud は、カーネル 5.10 で KFENCE を強化しました。
比較項目 | KFENCE | KASAN |
監視範囲 | 最大 4 KiB のスラブ (例: | すべてのスラブタイプ、ページメモリ、スタックメモリ、グローバルメモリ |
検出率 | 監視範囲内での成功率が高い | -- |
メモリオーバーヘッド | 低い | 高い |
パフォーマンスへの影響 | 低い (本番環境に適しています) | 高い (通常はテスト環境で使用されます) |
KFENCE と KASAN を同時に有効にしないでください。KFENCE は KASAN の監視オブジェクトを引き継ぎます。
基本概念
用語 | 説明 |
メモリ汚染 | プログラムの実行中に意図しないメモリの変更や破損が発生し、例外やクラッシュを引き起こすこと。一般的な原因として、プログラミングエラー、ソフトウェアの脆弱性、マルウェア、ハードウェアの故障などがあります。 |
スラブ | 頻繁なメモリオペレーションのオーバーヘッドを削減するために、キャッシュプールにオブジェクトを事前割り当てし、高速な割り当てと解放を実現するカーネルのメモリアロケーションメカニズム。 |
オーダー 0 ページ | Linux カーネルにおけるメモリアロケーションの最小単位である 4 KiB のページフレーム。 |
KFENCE の有効化
本番環境でのモニタリング
ライブ環境でメモリ破損を最小限のオーバーヘッドで検出します。
シナリオ 1:ブートパラメーターによるサンプリングモード
KFENCE は、一定の間隔でメモリアロケーションをサンプリングします。メモリ消費量は最大 2 MiB で、測定可能なパフォーマンスへの影響はありません。
ブートパラメーター
kfence.sample_intervalを追加します。<sample-interval>をサンプリング間隔 (ミリ秒単位) に置き換えます。例:100= 100 ms ごと。sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.sample_interval=<sample-interval>"(オプション) パラメーター
kfence.booting_maxを追加して、合計システムメモリに基づいて KFENCE のメモリを制限します。<booting-max>を0-128M:0,128M-256M:1M,256M-:2Mのようなセグメント表記文字列に置き換えます。sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.booting_max=<booting-max>"設定を有効にするには、インスタンスを再起動してください。
シナリオ 2:スクリプトによる特定スラブのフルモード
このモードでは、指定されたスラブタイプのすべての割り当てをモニタリングします。GiB レベルのメモリを消費するため、メモリが限られているマシンでは注意して使用してください。
kfence.shという名前のスクリプトを作成します。このスクリプトは、アクティブなスラブオブジェクトをカウントし、プールのサイズを決定し、他のスラブとオーダー 0 ページのモニタリングを無効にした後、指定されたスラブのフルモードモニタリングを有効にします。説明KFENCE はスラブとオーダー 0 ページの両方をモニタリングします。スラブは、頻繁に使用されるオブジェクトに対するカーネルの最適化された割り当てメカニズムです。
#!/bin/bash # 使用方法:./kfence.sh kmalloc-64 SLAB_PREFIX=/sys/kernel/slab MODULE_PREFIX=/sys/module/kfence/parameters if [ $# -eq 0 ]; then echo "err: please input slabs" exit 1 fi # スラブが存在するかどうかを確認します for i in $@; do slab_path=$SLAB_PREFIX/$i if [ ! -d $slab_path ]; then echo "err: slab $i not exist!" exit 1 fi done # num_objects を計算します sumobj=0 for i in $@; do objects=($(cat $SLAB_PREFIX/$i/objects)) maxobj=1 for ((j=1; j<${#objects[@]}; j++)); do nodeobj=$(echo ${objects[$j]} | awk -F= '{print $2}') [ $maxobj -lt $nodeobj ] && maxobj=$nodeobj done ((sumobj += maxobj)) done echo "recommend num_objects per node: $sumobj" # kfence のステータスを確認します if [ $(cat $MODULE_PREFIX/sample_interval) -ne 0 ]; then echo "kfence is running, disable it and wait..." echo 0 > $MODULE_PREFIX/sample_interval sleep 1 fi # すべてのスラブのモニタリングを無効化します for file in $SLAB_PREFIX/* do (echo 0 > $file/kfence_enable) 2>/dev/null || echo 1 > $file/skip_kfence done # order0 ページのモニタリングを無効化します echo 0 > $MODULE_PREFIX/order0_page # 設定したスラブのモニタリングを有効化します for i in $@; do (echo 1 > $SLAB_PREFIX/$i/kfence_enable) 2>/dev/null || echo 0 > $SLAB_PREFIX/$i/skip_kfence done # num_objects とノードモードを設定します echo $sumobj > $MODULE_PREFIX/num_objects echo node > $MODULE_PREFIX/pool_mode # kfence を開始します echo -1 > $MODULE_PREFIX/sample_interval if [ $? -ne 0 ]; then echo "err: kfence enable fail!" exit 1 fi echo "kfence enabled!"監視するスラブタイプを指定してスクリプトを実行します。
sudo bash ./kfence.sh kmalloc-64
オフラインデバッグ
広範なスコープですべてのメモリアロケーションをキャプチャします。メモリ消費量は多くなりますが、検出カバレッジは最大になります。
ブートパラメーター (x86)
次のブートパラメーターを追加します。
パラメーター
この例での値
効果
num_objects1000000プールは最大 1,000,000 個のスラブオブジェクトをモニタリングでき、最大で ceil(1,000,000 / 131,071) = 8 GiB を消費します。利用可能なメモリの約 10% に設定します。
sample_interval-1フルモード:設定されたスコープに一致するすべてのメモリをモニタリングします。
faultpanic問題が検出されるとカーネルパニックをトリガーし、分析用のコアダンプを保持します。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.num_objects=1000000" sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.sample_interval=-1" sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.fault=panic"設定を有効にするには、インスタンスを再起動してください。
ランタイムパラメーター (x86 または Arm)
ランタイムで有効化された KFENCE は、カーネル起動中のメモリ破損を検出できません。
KFENCE を有効にした後で
num_objectsまたはsample_intervalを変更するには、まず KFENCE を無効にしてください。num_objectsへの変更は、次に KFENCE が有効になったときに反映されます。
次のコマンドを実行します。
sudo sh -c 'echo 1000000 > /sys/module/kfence/parameters/num_objects'
sudo sh -c 'echo -1 > /sys/module/kfence/parameters/sample_interval'
sudo sh -c 'echo panic > /sys/module/kfence/parameters/fault'パラメーターは、上記の「ブートパラメーター (x86)」セクションで説明されている値と同じです。
カーネルバージョンが 5.10.134-16 より前の場合、fault パラメーターは利用できません。このパラメーターに書き込もうとしたときのエラーメッセージは、無視しても問題ありません。
結果の確認
KFENCE を有効にした後、検出された問題を確認します。
検出統計の表示
sudo cat /sys/kernel/debug/kfence/stats問題が検出された場合、total bugs のカウントは 0 より大きくなります。
エラー詳細の表示
dmesg | grep -i kfenceカーネルメッセージをフィルタリングして、KFENCE のエラーレポートを表示します。
KFENCE の無効化
KFENCE は、Alibaba Cloud Linux カーネルイメージに組み込まれた標準コンポーネントです (カーネル設定 CONFIG_KFENCE=y)。カーネルパッチ (kpatch)、ホットアップデート、またはソフトウェアパッケージでは無効にできません。無効にするには、次のコマンドを手動で実行します。
KFENCE のモニタリングを停止します。KFENCE は新しい割り当てのモニタリングを停止します。プール内の監視対象メモリがすべて解放されると、KFENCE はそのメモリを 1 GiB 単位でカーネルのバディシステムに返します。
sudo bash -c 'echo 0 > /sys/module/kfence/parameters/sample_interval'(オプション) KFENCE がブートパラメーターで有効化されていた場合は、そのパラメーターを削除して次回の起動時に KFENCE が開始されないようにします。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --remove-args="kfence.sample_interval"
パラメーターリファレンス
KFENCE は、ブート引数またはランタイム時に /sys/module/kfence/parameters/ を介して設定します。
パラメーター | 説明 | 有効な値 | デフォルト |
| メモリモニタリングのサンプリング間隔 |
| -- |
| KFENCE プールがモニタリングできるスラブオブジェクトの最大数。プールのサイズとメモリ消費量を決定します。 | 正の整数。オフラインデバッグでは、利用可能な最大メモリの約 10% に設定します。 |
|
| メモリ破損が検出されたときのアクション。カーネル |
|
|
| 合計システムメモリに基づく KFENCE のメモリ制限。カーネル | セグメント表記。例: |
|
| オーダー 0 ページのモニタリングの有効化または無効化 |
| -- |
| プール割り当て戦略 |
| -- |
メモリ消費量の計算式
最大メモリ消費量は num_objects に依存します。
num_objectsが 131,071 以下の場合:(num_objects + 1) x 8 KiBnum_objectsが 131,071 より大きい場合:ceil(num_objects / 131,071) GiB
例えば、num_objects を 1,000,000 に設定すると、最大消費量は ceil(1,000,000 / 131,071) = 8 GiB となります。
booting_max パラメーター
kfence.booting_max パラメーターは、合計システムメモリに基づいて KFENCE のメモリを制限します。各セグメントは、メモリ範囲を KFENCE の制限にマッピングします。
デフォルト設定 (カーネル 5.10.134-17 以降):
kfence.booting_max=0-2G:0,2G-32G:2M,32G-:32M
セグメント | 意味 |
| 合計メモリが 2 GiB 未満:KFENCE は無効 |
| 合計メモリが 2 GiB から 32 GiB の間:KFENCE は最大 2 MiB を消費可能 |
| 合計メモリが 32 GiB 超:KFENCE は最大 32 MiB を消費可能 |
デフォルトの num_objects である 255 を使用すると、KFENCE のメモリオーバーヘッドは合計メモリの 1 パーミル未満に留まります。標準の 4 KiB ページでは、最大消費量は 2 MiB です。64 KiB のヒュージページでは、32 MiB です。
booting_max パラメーターは、起動時にのみ num_objects を制約します。実際のメモリ消費量は、この制限よりも少なくなる場合があります。このパラメーターは、KFENCE がランタイムで有効化された場合には適用されません。
カスタム例: 0-128M:0,128M-256M:1M,256M-:2M
セグメント | 意味 |
| 合計メモリが 128 MiB 未満:KFENCE は無効 |
| 合計メモリが 128 MiB から 256 MiB の間:KFENCE は最大 1 MiB を消費可能 ( |
| 合計メモリが 256 MiB 超:KFENCE は最大 2 MiB を消費可能 ( |