これは、rb_per_cpu_empty におけるロジックバグを実証するための概念実証プログラムです。このバグを踏むと、プログラムは tracing_read_pipe 内でカーネル空間のビジーデッドループにハングアップし、あらゆる UNIX シグナル(SIGKILL を含む)では停止または終了できなくなります。
Linux 4.5 で修正された seq_buf_used 計算のバグと同様の動作(デッドループ & CPU 消費)を示しますが、このプログラムは、まったく異なる原因を持ち、バージョン 3.10 から 5.14-rc1 のカーネルに存在すると考えられる別のバグの存在を証明するためのものです(POC 実行結果も参照)。
免責事項: この概念実証プログラムは、あなたの Linux をフリーズさせ、大量の電力を消費し、ヒットした場合は UNIX シグナルでは終了できなくなる可能性があります。自己責任で使用してください。
概念実証スクリプトを実行する前に、以下のパッケージまたはコマンドがインストールされている必要があります。
gcc
realpath
nm
また、awk や grep などの Bash および文字列処理コマンドも必要ですが、おそらくディストリビューションに同梱されています。
Bash スクリプトですが、uprobe を指定するコード部分はプラットフォーム依存です(uprobe で $argN は使用できません)。i386、x86_64、arm、aarch64 をサポートしています。ご自身のプラットフォームのサポートを自由に追加してください。
概念実証を実行するには、root 権限で 以下のコマンドを実行するだけです。
./rbdetonate

バグが概念実証によってトリガーされると、CPU コア全体を消費する dd プロセスが生成され、SIGKILL のような UNIX シグナルでは kill できなくなります。
rbdetonate スクリプトの bash プロセスは kill できますが、SIGINT シグナルを送信すると、bash の実装によって終了する場合としない場合があります。新しいバージョンの bash では、生成された dd プロセスが実行中の場合にのみ SIGINT で kill できます。

rbdetonate は、数回の再試行後に dd プロセスを作成できない場合、終了して Nothing buggy has been detected と表示することがあります。ただし、8192 回の再試行を行うため、これには時間がかかる場合があります。
| バージョン | 再現 | スクリーンショット |
|---|---|---|
| 5.14.0-rc2-00479-g86020194bc7e (Fix version) | N | 5.14.0-rc2-00479-g86020194bc7e.png |
| 5.14.0-rc2-00478-g2734d6c1b1a0 (5.14.0-rc2) | Y | 5.14.0-rc2-00478-g2734d6c1b1a0.png |
| 5.4.0-77-generic | Y | 5.4.0-77-generic.png |
| 4.4.0-142-generic | Y | 4.4.0-142-generic.png |
コメント: このバグは、理論上はユーザー空間トレース機能(>=3.10)を持つすべてのバージョンに存在しますが、古いカーネルバージョンでは uprobe が多くの点で適切に動作していません。動作の修正にご協力いただけると幸いです。
A: root 権限で以下のコマンドを実行してください。
echo > /sys/kernel/debug/tracing/instances/rbdetonate/trace
これでプログラムをデッドループから抜け出させることができます。
A: いいえ。ここで使用されているビルドツールは rbwrite プログラムをビルドするためのもので、CPU#0 のリングバッファページに設計された手順で書き込むだけで決定的な結果を生成します。
この概念実証では、コンパイル済みの rbwrite プログラム(コードのようなもの)も使用でき、その後にトレースポイントのアドレスを取得できます。
Linux トレースを使用する場合、アプリケーションによるノイズを気にしないのであれば、kprobe トレースポイントをシステムコールやカーネル関数に追加してもイベントが生成されます。しかし、概念実証では非決定論が生じる可能性があるため、推奨しません。