Kernel Electric-Fence (KFENCE) は、オンライン環境で有効にできる組み込みのLinuxカーネルツールです。 KFENCEは、カーネルモジュールとカーネルモジュールのメモリ汚染問題を検出します。 KFENCEがメモリ汚染の問題を検出すると、KFENCEは問題の詳細を含むエラーメッセージを生成します。 Alibaba Cloud Linux 3で強化されたKFENCE。 KFENCEを柔軟かつ動的に有効または無効にし、KFENCEを使用してメモリ汚染の問題を包括的に検出し、オンライン検出とオフラインデバッグの要件を満たすことができます。
オペレーティングシステムの制限
x86アーキテクチャ
カーネルバージョンが
5.10.84-10
以降のAlibaba Cloud Linux 3アームアーキテクチャ
カーネルバージョンが
5.10.134-16
以降のAlibaba Cloud Linux 3
カーネルモジュールまたはカーネルモジュールの開発者であれば、KFENCEを使用して、カーネルモジュールまたはカーネルモジュールでメモリ汚染が発生しているかどうかを確認できます。
通常のユーザーでカーネルクラッシュが発生した場合、KFENCEを使用して、Alibaba Cloudまたはサードパーティのドライバー開発者がカーネルクラッシュに関する詳細情報を収集できるようにすることができます。
用語
期間 | 説明 |
メモリ汚染 | プログラムの実行中にメモリ領域が誤って変更または破損し、プログラムで例外またはクラッシュが発生するという問題。 メモリ汚染は、プログラミングエラー、ソフトウェアの脆弱性、マルウェア、またはハードウェア障害によって引き起こされる可能性があります。 |
スラブ | スラブ割り当ては、Linuxカーネルの効率的なメモリ割り当てメカニズムです。 カーネルは、スラブを使用して、メモリキャッシュプール内の特定の数のメモリオブジェクトを事前に割り当てて、メモリの割り当てと解放を迅速に行います。 スラブを使用して、頻繁なメモリ割り当てとリリース操作を防ぎ、メモリ割り当ての効率を向上させることができます。 |
注文-0ページ | Order-0ページ割り当ては、Linuxカーネルのメモリ割り当てメカニズムです。 メモリは、ページフレームと呼ばれる固定サイズのブロックに分割される。 ほとんどの場合、オーダー0ページフレームのサイズは4 KiBである。 オーダー0ページは、4 − KiBページフレームであり、メモリ割り当ての基本単位である。 アプリケーションまたはカーネルがメモリの小さなブロックを必要とする場合、メモリは0次ページによって割り当てられます。 |
KFENCEの有効化
KFENCEは、次のビジネスシナリオで使用されます。
オンライン検出シナリオ
シナリオ1: KFENCEを使用してメモリ汚染の問題が発生したかどうかを検出する
次の例では、KFENCEは最大2 MiBのメモリを消費し、パフォーマンスには影響しません。
kfence.sample_interval
パラメーターを追加してKFENCEを有効にします。<kfence.sample_interval> を指定する値に置き換えます。 たとえば、値が100の場合、次回のシステム起動時にKFENCEデバッグツールが自動的に有効になり、サンプリング間隔が100イベントに設定されることを指定します。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.sample_interval=<kfence.sample_interval>"
kfence.booting_max
パラメーターを追加して、メモリ仕様に基づいてKFENCEが消費できるメモリの最大量を制限します。説明カーネルバージョン
5.10.134-17
以降では、デフォルト設定kfence.booting_max=0-2G:0,2G-32G:2M,32G-:32M
がboot commandline
パラメーターリストに追加されます。 上記の既定の設定は、num_objects
パラメーターの既定値 (255) と組み合わせて使用し、KFENCEのメモリオーバーヘッドがすべてのメモリ仕様の合計メモリの1 ‰ を超えないようにします。 上記のデフォルトの設定と値を使用すると、KFENCEは、標準の4-KiBメモリページを使用する場合は最大2 MiBのメモリを消費し、64-KiBの巨大ページを使用する場合は最大32 MiBのメモリを消費します。kfence.booting_maxパラメーターは、KFENCEが消費できるメモリの最大量のみを制限します。 このパラメータはnum_objectsパラメータの制約であり、実際のメモリオーバーヘッドを表すものではありません。 実際のメモリオーバーヘッドは、kfence.booting_maxパラメーターの値以下です。
<kfence.booting_max>
を、指定する値 (0-128M:0,128M-256M:1M、256M-:2M
など) に置き換えます。サンプル値のセグメントの説明:0-128 M:0: 使用するマシンの合計メモリのサイズが128 MiB未満の場合、KFENCEは無効になります。
128 M-256 M:1 M: 使用するマシンの合計メモリのサイズが128 MiB以上256 MiB以下の場合、KFENCEは最大1 MiBのメモリを消費できます。 num_objectsパラメーターの値は127を超えることはできません。
256 M-:2 M: 使用するマシンの合計メモリのサイズが256 MiBより大きい場合、KFENCEは最大2 MiBのメモリを消費する可能性があります。 num_objectsパラメーターの値は255を超えることはできません。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.booting_max=<kfence.booting_max>"
上記の構成は、システムの起動時にパラメーターをboot commandlineパラメーターリストに追加することでKFENCEを起動するシナリオにのみ適用されます。 システム起動後にKFENCEを設定するシナリオ2では、設定は有効になりません。
この設定は、次回システムの起動時に自動的に有効になります。
シナリオ2: KFENCEを使用してメモリ汚染の問題が発生したかどうかを検出する
このシナリオでは、GiBレベルで大量のメモリが消費されます。 小さなメモリマシンを使用するときは注意してください。
メモリ割り当てスクリプトを作成し、次の内容を追加します。 次の例では、スクリプトの名前はkfence.shで、監視対象のスラブタイプは
kmalloc-64
です。#!/bin/bash # usage: ./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 #check whether slab exists for i in $@; do slab_path=$SLAB_PREFIX/$i if [ ! -d $slab_path ]; then echo "err: slab $i not exist!" exit 1 fi done #calculate 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" #check kfence stats 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 #disable all slabs catching for file in $SLAB_PREFIX/* do (echo 0 > $file/kfence_enable) 2>/dev/null || echo 1 > $file/skip_kfence done #disable order0 page catching echo 0 > $MODULE_PREFIX/order0_page #enable setting slabs catching for i in $@; do (echo 1 > $SLAB_PREFIX/$i/kfence_enable) 2>/dev/null || echo 0 > $SLAB_PREFIX/$i/skip_kfence done #setting num_objects and node mode echo $sumobj > $MODULE_PREFIX/num_objects echo node > $MODULE_PREFIX/pool_mode #start kfence echo -1 > $MODULE_PREFIX/sample_interval if [ $? -ne 0 ]; then echo "err: kfence enable fail!" exit 1 fi echo "kfence enabled!"
スクリプトは、スラブのアクティブなオブジェクトの数を検出し、その数に基づいて適切なKFENCEプールサイズを推定し、その後、KFENCEがすべてのスラブのメモリ割り当てに関する情報を取得できるようにするために使用されます。
説明スラブは、メモリの割り当てと解放操作を最適化するためにメモリ管理で一般的に使用されます。 これにより、システムのパフォーマンスと効率が向上します。 KFENCEはスラブを監視し、0ページを注文できます。
次のコマンドを実行して、スクリプトを実行し、メモリ汚染検出を開始します。
sudo bash ./kfence.sh kmalloc-64
オフラインデバッグシナリオ
x86アーキテクチャのパラメーターを指定してKFENCEを有効にする
次のコマンドを実行してKFENCEを有効にします。
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"
num_objects
: KFENCEプールのサイズ。KFENCEが監視できるスラブオブジェクトの最大数です。num_objectsパラメーターの値が131071以下の場合、KFENCEが消費できる最大メモリ量は、(num_objects + 1) × 8 KiBの式で計算されます。
num_objectsパラメーターの値が131071より大きい場合、KFENCEが消費できる最大メモリ量は、次の式を使用して計算されます。⌈ num_objects/131071 ⌉ GiB。 ⌈⌉ 記号は、計算結果を最も近い整数に切り上げることを指定します。
説明num_objectsパラメーターは、使用可能な最大メモリの10% に設定することを推奨します。 たとえば、パラメーター
num_objects
を1,000,000に設定すると、KFENCEは最大8 GiBのメモリを消費できます。これは、次の式を使用して計算されます。⌈ 1,000,000 131071 GiB = 8 GiB。
sample_interval
: メモリが監視される間隔。 有効な値:0: KFENCEは無効で、メモリを監視しません。
正の数: ミリ秒単位のサンプリング間隔。 たとえば、値100は、KFENCEが100ミリ秒ごとに割り当てられたメモリを監視することを指定します。
負の番号: フルモード。 KFENCEは、特定のスラブタイプなど、特定の条件を満たすすべてのメモリを監視します。
fault
: このパラメーターはカーネルバージョン5.10.134-16
で導入されています。 デフォルト値:report
。 faultパラメーターをpanic
に設定すると、問題が検出されたインスタンスでダウンタイムが発生し、問題発生時に生成されたコアダンプファイルが保持されます。
オペレーティングシステムを再起動して、設定を有効にします。
詳細は、「インスタンスの再起動」 をご参照ください。
スクリプトを使用してKFENCEを有効にするx86またはArmアーキテクチャ
スクリプトを実行してKFENCEを有効にすると、KFENCEはカーネルの起動中に発生する可能性のあるメモリ汚染の問題を検出できません。
KFENCEを有効にした後に
num_objects
またはsample_interval
パラメーターの値を変更する場合は、まずKFENCEを無効にする必要があります。
次のコマンドを実行して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'
num_objects
: KFENCEプールのサイズ。KFENCEが監視できるスラブオブジェクトの最大数です。 KFENCEが消費できるメモリの最大量は、次の式を使用して計算されます。⌈ num_objects/131071 ⌉ GiB。 ⌈⌉ 記号は、計算結果を最も近い整数に切り上げることを指定します。説明num_objectsパラメーターは、使用可能な最大メモリの10% に設定することを推奨します。 たとえば、パラメーター
num_objects
を1,000,000に設定すると、KFENCEは最大8 GiBのメモリを消費できます。これは、次の式を使用して計算されます。⌈ 1,000,000 131071 GiB = 8 GiB。sample_interval
: メモリが監視される間隔。 有効な値:0: KFENCEは無効で、メモリを監視しません。
正の数: ミリ秒単位のサンプリング間隔。 たとえば、値100は、KFENCEが100ミリ秒ごとに割り当てられたメモリを監視することを指定します。
負の番号: フルモード。 KFENCEは、特定のスラブタイプなど、特定の条件を満たすすべてのメモリを監視します。
fault
: このパラメーターはカーネルバージョン5.10.134-16
で導入されています。 デフォルト値:report
。 faultパラメーターをpanic
に設定すると、問題が検出されたインスタンスでダウンタイムが発生し、問題発生時に生成されたコアダンプファイルが保持されます。説明カーネルのバージョンが
5.10.134-16
より前の場合、上記のコマンドを実行するとエラーメッセージが報告されます。 このエラーはKFENCEには影響しません。 エラーメッセージは無視できます。
結果の表示
KFENCEがメモリ汚染の問題を検出した後、問題の数と詳細なエラーメッセージを表示できます。
検出されたメモリ汚染の問題の数を表示します。
sudo cat /sys/kernel/debug/kfence/stats
次の図は、
合計バグ
数が増加したことを示すコマンド出力を示しています。エラーメッセージの詳細を表示します。
dmesg | grep -i kfence
次の図は、1つのエラーメッセージが返されたことを示すコマンド出力を示しています。
KFENCEの無効化
次のコマンドを実行してKFENCEを無効にします。
sudo bash -c 'echo 0 > /sys/module/kfence/parameters/sample_interval'
KFENCEを無効にすると、メモリ割り当ての問題が検出されなくなります。 プール内のすべての監視対象メモリが解放されると、KFENCEは1 GiBの粒度でメモリをカーネルバディシステムに返します。
ブートコマンドラインパラメータリストにパラメータを追加してKFENCEを起動するシナリオでは、次のコマンドを実行してパラメータを削除できます。 そのため、次回のシステム起動時にKFENCEは自動的に有効になりません。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --remove-args="kfence.sample_interval"