HN 日本語サマリー

← 一覧へ戻る
セキュリティ

レースコンディションのテスト

Testing Race Conditions (projectzero.google)

51 pointsby alpaylan2 コメント

要約

マルチスレッド実行におけるレースコンディションは、セキュリティバグの一般的な原因であり、その特定と再現には困難が伴います。この記事では、Linuxカーネル向けに、多スレッドテストケースの可能なインターリービングを自動的にテストするツール、および手動で探索するためのターミナルUIとGUIを紹介しています。これらのツールは、メモリアクセスとスケジューリングのインターリービングを分析し、バグの発見と回帰テストの信頼性向上を目指します。

全文翻訳

メモリアクセス追跡とスタックベースの遅延注入によるレースコンディションのテスト

多くのセキュリティバグはレースコンディションであり、マルチスレッド実行が特定のインターリービングで発生した場合にのみ、悪影響が現れます。これはいくつかのユースケースで課題となります。

  • 手動または静的解析で発見されたバグ候補の確認。
  • 回帰テスト:レースコンディションのバグを修正した後、テストスイートの一部としてバグを確実にトリガーする回帰テストを作成する良い方法がしばしばありません。
  • ファジングのような自動バグ発見:ファザーが並行操作のすべての興味深いインターリービングを実行したり、操作が競合している場合にのみ実行されるコードパスに到達することは困難です。

私は主にコードを読んでバグを発見します。バグを見つけたと思ったら、通常はテストケースを書いてバグの存在を証明または反証します。レースコンディションのバグの場合、どちらの結果を達成するのも難しいことがあります。Linuxカーネルのバグについては、適切な場所に条件付きのmdelay()呼び出し(指定された時間だけスピンループする)を追加してカーネルを再コンパイルすることに頼ることがよくあります。通常、これらの呼び出しは実行中のスレッド名に基づいて条件付けされますが、より複雑な条件が必要な場合もあります。DTraceをサポートするプラットフォーム(macOSやWindowsなど)では、同様の効果を得るためにchill()を呼び出すDTraceプローブを使用できますが、DTraceはインライン関数境界または明示的なトレースポイントでのみトレースできるため、すべての命令ではなく、このユーティリティは限られています。プラットフォームに関係なく、このアプローチは時間がかかり、コードがバグがあるかどうかを確実に判断するために試行錯誤が必要になる場合があります。

さらに、Linuxカーネルでは、レースコンディションのバグの修正には、問題のあるスレッドのインターリービングをコールグラフと関連メモリアクセスとともに示す手書きのASCIIダイアグラムが付属することがよくあります(例:最近のrt_spin_unlock UAF修正や、最近のjbd2デッドロック修正を参照)。潜在的に脆弱なコードを分析し、同様の表現で結果を示す開発者ツールがあると便利でしょう。

要約

Linuxカーネルのマルチスレッドテストケースの可能なインターリービングを探索するためのツールを作成しました。

  • テストケースのすべての可能なA-B-Aインターリービングを自動的にテストするツール。
  • 可能なインターリービングを手動で探索するためのターミナルUI。
  • 可能なインターリービングを手動で探索するためのGUI。

このカーネル部分は、ファジングによるレースコンディションの発見にも使用できることを意図していますが、ユーザー空間ツールはまだ実装が必要です。

これらのツールは、MAccConc("Memory Access Concurrency"の略)という名前でGitHubで利用可能です。インストールと使用方法については、そちらのREADMEを参照してください。

ツールの動作を見たいだけであれば、デモ:自動テストにスキップしてください。

ツールの背後にある理論にのみ興味がある場合は、実行をまたいでメモリアクセスに安定した識別子を付ける:カウント拡張スタックトレースセクションをお読みください。

先行研究

このプロジェクトは、Ned Williamsonとの議論に触発されました。彼のsockfuzzerプロジェクトは、カスタムスケジューラを使用して同期プリミティブで再スケジュールすることでインターリービングを探索することにより、並行性バグの探索を含んでいました。この並行性テストの側面に焦点を当てたカンファレンストークのスライドと録画を参照してください。

私のツールは、主にSKIと同様のアイデアに基づいています。ただし、SKIは異なる実装を使用しています。メモリアクセスを記録し、TCGモードのQEMUのパッチ適用済みバージョンを使用してvCPUのスケジューリングを制御し、VMスナップショットを使用して異なる実行インターリービングを探索します。

レースコンディションに寄与する可能性のあるメモリアクセス(通信ポイント)の発見

SKIの論文で説明されているように、指定されたマルチスレッドテストケースの興味深い実行インターリービングは、すべてのスレッドのメモリアクセスをトレースし、互いに相互作用する可能性のある2つのスレッド上のアクセスのペアを検索することによって発見できます。これは、おおよそ、少なくとも1つが書き込み操作であり、それらが重複するメモリ範囲にアクセスすることを意味します。SKI論文では、このようなメモリアクセスを通信ポイントと呼んでいます。

これには、メモリアクセス範囲を収集するメカニズムが必要です。SKIはQEMUのTCGモードをパッチ適用することでこれを実現しました。私は代わりに、ASANインストルメンテーションを「アウトライン」モード(コンパイラバックエンドフラグasan-instrumentation-with-call-threshold=0、LinuxカーネルのCONFIG_KASAN_OUTLINEで選択)に依存しています。これはメモリアクセス時にヘルパー関数呼び出しを生成します。カーネルがこのデータ収集の適切な場所であると信じています。なぜなら、カーネルはロックの取得/解放イベントなどに関する高レベルの情報も提供できるからです。ただし、現時点ではこれを実装していません。カーネルでこれを実装することは、理論的には仮想マシン内ではなく、ベアメタルハードウェアでテストできることも意味します。

Linuxにはすでに基本的なブロックカーネルカバレッジ情報をユーザー空間にフィードするためのメカニズムとしてKCOVがあるため、メモリアクセスに関する情報を記録するために同じメカニズムを使用することにしました。代替案としては、トレースユースケースを指向するftraceを使用することもできます。ftraceは、fentryフックとシステム全体のデータ収集を含むユースケースを指向するより複雑な出力バッファ管理に基づいた関数グラフトレースモードを含んでいます。KCOVを選択したのは、トレースデータのよりシンプルなインメモリ表現(クラッシュしたVMからトレースデータを回復する際に重要になる可能性がある)のため、無効状態でのオーバーヘッドがほぼゼロのランタイム有効インストルメンテーションではなく、静的に常に有効なインストルメンテーションを使用するため、そしてKCOVがftraceよりも高頻度のトレースイベント用に設計されているという印象のためです。

実装の詳細:ASANとTSAN

ASANは通常、後続のメモリアクセスに対してヘルパー呼び出しをマージします。メモリアクセスごとに1つのコールバックを受け取るために、カーネルはasan-opt-same-tempバックエンドフラグを使用してこのコンパイラ最適化を明示的に無効にします。

ASANはUAF(Use-After-Free)の特定を目的としているため、スタック上のオブジェクトへの直接アクセスでは、境界外アクセスの可能性がある場合を除き、ヘルパー呼び出しを発行しません。これは、待機キューのようなスタック上のオブジェクトを伴う一部のレースコンディションは、これで検出できない可能性があることを意味します。ASANはデフォルトでグローバルへのアクセスに対してヘルパー呼び出しを発行しませんが、この最適化はasan-opt-globalsバックエンドフラグを使用して無効にできます。

代替案としては、データ競合の検出を目的とし、アクセスアトミック性に関する情報も提供するTSANインストルメンテーションを使用することもできます。TSANインストルメンテーションの欠点は、コンパイラがASANフックとTSANフックを同時に発行することをサポートしていないことです。そのため、TSANフックを使用しながらメモリ安全性違反(UAFなど)の検出を機能させるには、カーネルのASAN実装をTSANフックから実行するか、コンパイラを変更する必要があります。

実装の詳細:KCOVとバックグラウンドワーク

一部のレースコンディションはバックグラウンドワークを伴います。例:

  • ループバックネットワークパケットの受信処理
  • RCUコールバック

KCOVは、一部のサブシステムでバックグラウンドワークのリモートカバレッジをオプションで収集できます。しかし、アップストリームLinuxでは、私にとって興味深いほとんどの種類のバックグラウンドワークは、まだこのメカニズムと統合されていません。リモートカバレッジは現在、主にBluetoothやUSBのようなデバイスからの着信データを処理するサブシステムのファジングに使用されています。

これをカーネルの他の部分で有効にすることは比較的簡単であるはずです。RCUコールバックでこれを行うためのドラフトパッチがあります。

実行をまたいでメモリアクセスに安定した識別子を付ける:カウント拡張スタックトレース

メモリアクセスの異なる順序をテストするには、テストケースの実行をまたいで興味深いメモリアクセスを安定して識別する方法が必要です。データアドレスに基づいてメモリアクセスを識別することは、テストケースの実行中にオブジェクトが新しく割り当てられた場合、データアドレスがそのオブジェクト内にあると機能しません。また、命令アドレスのみに基づいてメモリアクセスを識別することは、memcpy()やspin_lock()のような関数内のメモリアクセスではうまく機能しません。

SKIはVM状態のスナップショットを使用してこれを解決します。これにより、各実行は同じグローバル状態から開始されます。

私は代わりに、カウント拡張スタックトレースを使用してメモリアクセスを識別します。各スタックトレース要素は、基本的に呼び出し先関数アドレスと、呼び出し元スタックフレームでこの呼び出し先への呼び出しをいくつスキップする必要があるかを示す数値で構成されます。

カウント拡張スタックトレースのセマンティクスの例は、「このスレッドで、__x64_sys_recvfromの2回目の呼び出し、次にその中の__sys_recvfromの1回目の呼び出し、次にその中のsock_recvmsgの1回目の呼び出し、次にその中のunix_stream_recvmsgの1回目の呼び出し、次にその中のunix_stream_read_genericの1回目の呼び出し、次にその中の_raw_spin_unlockの2回目の呼び出し、そしてその中の命令アドレスXでの最初のメモリアクセス」のようになります。

これは実行トレース内のポイントを一意に識別し、具体的なデータアドレスに依存せず、トレースの無関係な部分の制御フローの変更に対して比較的安定しています。

これを機能させるには、KCOVが関数エントリ/エグジットイベントに関する情報を提供する必要があります。これにより、ユーザー空間がKCOVカバレッジ出力を解析する際に、コールスタックがどのように変化するかを追跡できます。これをうまく行うには、SanitizerCoverageの一部としてコンパイラサポートが必要です。数ヶ月前にLLVM機能パッチを適用しました(ドキュメントを参照)。これはLLVM 23.1.0リリースに搭載されました。

遅延注入による実行順序の強制

KCOVを介して特定の実行順序を強制するために、KCOV_SET_DI ioctlを実装しました。これにより、ユーザー空間は特定のカウント拡張スタックトレースでのアクション(基本的に待機/ウェイク)を要求できます。(私のカーネルブランチのドキュメントを参照してください。)各アクションは、共有フラグ配列内のユーザー空間指定のインデックスでフラグを設定するか、フラグが設定されるのを待機します。可能なアクションタイプは次のとおりです。

  • DI_STACK_WAKE_PRE:メモリアクセス前にフラグNを設定
  • DI_STACK_WAIT:メモリアクセス前にフラグNが設定されるまでスピン待機
  • DI_STACK_WAKE_POST:メモリアクセス後にフラグNを設定

同じioctlで、ユーザー空間はスピン待機イテレーションの上限も設定します。

さらに、ユーザー空間が同じフラグと直接対話するためのioctlもあります。

このAPIは、遅延注入の2つの異なる使用方法を可能にします:制約スタイルの遅延注入と完全に指定された順序付け。

制約スタイルの遅延注入(AはBより前に発生)

ユーザー空間は、一連のAはBより前に発生する制約を設定できます。各制約は、同じフラグを操作する異なるスレッドの2つのアクションのペアとして実装されます。

  • 最初に発生する必要があるアクセスに対するDI_STACK_WAKE_POST
  • 2番目に発生する必要があるアクセスに対するDI_STACK_WAIT

このアプローチでは、実行順序は部分的に非決定論的になります。これは、GUIおよびターミナルUIツールが現在実装しているものです。

利点は、単純なケースではある程度直感的であることですが、イベントがどのくらいの順序で発生したかをユーザーに示すためにタイミング情報を記録する必要があり、実行トレースをより複雑にする可能性があります。また、完全に指定された順序付けよりも多くの制約が必要になることが多く、推論するのがより複雑です。

完全に指定された順序付け(コンテキストスイッチスタイル)

ユーザー空間は、実行がコンテキスト間で転送されるポイントを選択することにより、イベントが発生する特定の順序を決定できます。2つの実行コンテキストの単純なケースでは、スレッドAがシステムコールを実行し始め、スレッドBがフラグのスピニング待機から開始する必要があります。次に、スレッドAがカウント拡張スタックトレースのあるポイントに到達すると、スレッドAはDI_STACK_WAKE_PREとDI_STACK_WAITの組み合わせを使用して自身の実行を一時停止し、スレッドBを続行させます。その後、スレッドBも同様に、スレッドAに戻すことができます。

これは、自動A-B-Aインターリービングテスターに使用したアプローチです。

デモ:自動テスト

以下でさらに背景を説明しますが、まずは玩具の例で2つの派手なデモをご覧ください!

これは、並行するdup(5)とclose(5)呼び出しを含むこのテストケースで、自動A-B-Aインターリービングテスターを使用した例です。

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int test_fd;
static int dup_res, dup_errno;

void test_setup(void) {
  test_fd = open("/", O_PATH);
}

void test_thread1(void) {
  dup_res = dup(test_fd);
  dup_errno = errno;
}

void test_thread2(void) {
  close(test_fd);
}

void test_end(void) {
  printf("dup(%d) = %d (%s)\n",
      test_fd,
      dup_res,
      dup_res == -1 ? strerror(dup_errno) : "success");
}

これは、dup(5)が5を返す1つの順序を発見します。これは意図通りに動作していますが、やや驚くべき結果かもしれません。

sh-5.3# ./kcov-autorace testcase/demo-dup-vs-close.so
loading kallsyms
RCU state (excluded): base=ffffffff82970100 len=500
loading testcase
initializing kcov
collecting A-B coverage
dup(5) = 6 (success)
testing candidates
dup(5) = -1 (Bad file descriptor)
dup(5) = -1 (Bad file descriptor)
dup(5) = -1 (Bad file descriptor)
dup(5) = 5 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
stats:  injection-failed:0  wait-timeout:7  reordered:4
sh-5.3#

デモ:GUI

そして、これは同じテストケースでGUIを使用して、dup(7)が7を返す順序を手動で強制する例です。

まず、GUIを起動し、次にゲストでテストケースを一度実行します。

sh-5.3# ./kcov-vsock-client testcase/demo-dup-vs-close.so
dup(7) = 8 (success)

この時点では、まだ順序制約は強制されていません。dup()とclose()はランダムに競合しています。GUIは実行がどの順序で発生したかを示します。

[画像:GUIのスクリーンショット]

現在のビューは、両方のスレッドの関数呼び出しグラフ(スレッド1は黒いインデント、スレッド2は赤いインデント)を示しているだけです。close()システムコールはこの時dup()の後に実行されました。通常の関数は黒で表示されます。インライン関数は緑で表示されますが、通常の関数を呼び出した場合のみ表示されます(「すべてのインライン関数」がチェックされていないため)。

「通信ポイントにフィルタリング」をチェックすると、多くのメモリアクセスが青色で表示されます。これらは通信ポイントです(上記で定義したように、簡単に言うと、他のスレッドが書き込む場所に読み取る、または他のスレッドがアクセスする場所に書き込む操作。kfree()は書き込み操作としてカウントされます)。各メモリアクセス行には、アクセスタイプ(Read/Write/Free)、データアドレス、アクセスサイズ、およびアクセス前のメモリ値が表示されます。アクセスにカーソルを合わせると、重複するすべてのアクセスが黄色でハイライトされます。

[画像:GUIのスクリーンショット、通信ポイントにフィルタリング]

メモリアクセスに左クリックすると、選択したアクセスと重複するメモリアクセスのみを表示するようにフィルタリングされたビューが表示されます。これは、通信ポイントとして識別されなかった読み取り(書き込みがすべて同じスレッドで発生するため)を示すことができることに注意してください。

[画像:GUIのスクリーンショット、重複するアクセスにフィルタリング]

関数名に左クリックすると、右側にソースコードビューが表示され、トレースデータが挿入されます。メモリ読み取りによってロードされたデータ値は赤色で表示されます(コンパイラがアクセスを属性付けるソース行と列の下)。データ書き込みは同様に赤い「WRITE」でマークされます。通信ポイントであるメモリアクセスには、オレンジ色で「INTERFERENCE」がプレフィックスとして付けられます。関数呼び出しは青色で表示されます。

[画像:GUIのスクリーンショット、ソースコードビューとトレースデータ]

呼び出しグラフビューで2つのメモリアクセスを右クリックすることにより、それらのアクセス間に順序制約を作成できます。これにより、カーネルは最初の選択されたアクセスが2番目の選択されたアクセスより前に発生するように試みます。各順序制約は右側に表示され、2つのカウント拡張スタックトレースとして表されます。ここのスタックの最後の最下位要素は実際には特定の命令を識別しますが、UIはこれを実際には表示しません。また、ここで表示されるカウント拡張スタックトレースにはインライン関数は含まれていません。

この場合、__fget_files_rcu()(__fget_files()にインライン化されている)の2番目のファイルディスクリプタテーブルアクセスを、file_close_fd_locked()(file_close_fd()にインライン化されている)のファイルディスクリプタテーブルエントリ削除より前に発生させる順序制約を作成しました。これにより、dup()のファイルディスクリプタテーブル検索が、並行するclose()によってクリアされる前にファイルディスクリプタテーブルエントリを正常に検索できるようになります。

file_close_fd()のspin_unlock(&files->file_lock)を、alloc_fd()のspin_lock(&files->file_lock)より前に発生させる別の順序制約を作成しました。これにより、dup()が未使用のエントリを検索する時点で、ファイルディスクリプタテーブルエントリが解放されています。

このビューでは、順序制約が指定されていますが、テストケースはこの指定された順序でまだ実行されていません。

(このビューは、files_struct::file_lockへのアクセスを示すようにフィルタリングされています。)

[画像:GUIのスクリーンショット、順序制約の指定]

テストケースを再実行すると、次のようになります。

sh-5.3# ./kcov-vsock-client testcase/demo-dup-vs-close.so
dup(7) = 7 (success)

そして、新しいトレースがUIに表示され、順序制約がどのように適用されたかを示す茶色の「DELAY INJECTION」線が挿入されます。

UIはタイミング情報に基づいてイベントの順序を示していることに注意してください。このタイミング情報はメモリアクセスにのみ関連付けられており、メモリアクセス以外のイベントの配置はそのタイミングに基づいて推測されます。データアクセスでフィルタリングされたビューでは、関数エントリイベントは、表示される最初の関数エントリ以外のイベントの時点で追加で表示されるだけです。たとえば、次のスクリーンショットでは、file_close_fd()がspin_unlock()を呼び出した時点で、最初のスレッドはすでにget_unused_fd_flags()に入っていた可能性がありますが、イベントは逆の順序で表示されています。ただし、メモリアクセスはほぼ正しい順序で表示されるはずです。ただし、イベントが同じクロック値で発生した場合、メモリアクセスの順序が間違っている可能性があり、タイミング情報は実際のアクセス直前に実行されるインストルメンテーションによって記録されるという注意点があります。(代わりに完全に指定された順序付けに基づいてツールを構築すると、このような注意点が回避されます。)

(このビューは、ファイルディスクリプタテーブルエントリへのアクセスを示すようにフィルタリングされています。)

[画像:GUIのスクリーンショット、順序付けられたトレース]

GUI内でさらにドキュメントが利用可能です。

実装状況

LLVMについて:必要なパッチはLLVM 23.1.0に搭載されました。

Linuxカーネルについて:必要なパッチはまだアップストリームカーネルには含まれていません。このブログ投稿とほぼ同時に、アップストリームレビューのためにLinuxカーネルパッチシリーズを投稿しています。私のパッチを含むgitブランチもgithubで利用可能です(まだアップストリーム化の準備ができていないパッチがいくつかあります)。このツールをテストしたい場合は、現時点では私のカーネルブランチを使用する必要があります。(ビルド手順については、ツールのリポジトリのREADMEを参照してください。)

私のカーネルパッチはクリーンな状態です。ユーザー空間ツールは、特にGUIの実装は、もう少しハック的な状態です。

コマンドラインツールは2つの並行スレッドしか扱えませんが、GUIは追加の実行コンテキストを扱えます(kcov-vsock-clientハーネス:スレッドAによって起動されるバックグラウンドワーク)。

これが他の人にも役立つかどうか、そして他の人がこれの上にどのようなツールを構築できるかを聞くのを楽しみにしています!私に連絡することを自由にしてください(例えば、maccconc-tooling@google.comへのメールで)。

将来の作業

手動ツールで制約スタイルではなく、完全に指定された順序付けを使用する

非自動ツールは現在制約スタイルの遅延注入を使用していますが、上記で説明したように、完全に指定された順序付けには、より決定論的な動作を含むいくつかの利点があります。将来的にGUI実装を完全に指定された順序付けを使用するように変更するかもしれません。

人間が読めるメモリアクセストレースのための型情報

人間がメモリアクセストレースを読むために、アクセスされているオブジェクトの型に関する情報を提供すると役立つかもしれません。これを行う1つの方法は、MicrosoftのデバッグツールがCodeViewデバッグ情報でできることに従い、デバッグ情報を使用してメモリ割り当て関数呼び出しサイトを型情報に関連付け、次にアロケータがオブジェクトが割り当てられた呼び出しサイトを追跡できるようにすることです。

私はDWARF標準にそのような機能を追加することを提案しました。これは受け入れられ、現在のDWARF 6ドラフトに含まれています(DW_AT_alloc_typeを検索)。そしてLLVMに十分なサポートを追加しました。これは、CodeViewですでに機能していたのと同じケースで機能しますが、今のところC++ new呼び出しにのみ機能します。mallocで機能するために必要な変更はまだ適用されていません。

カーネルでこれを機能させるには、すべてのメモリアクセスレコードに対してアロケータメタデータをクエリするか、システム全体のヒープアロケータメタデータの初期スナップショットと後続のメモリ割り当てに関するメタデータを提供するインフラストラクチャが必要になります。

より高レベルのメモリアクセスフィードバック

私の現在のプロトタイプの非効率性の1つは、ユーザー空間がロック操作のセマンティクスに関する情報を受け取らないことです。2つのスレッドが、オブジェクトを保護するロックを保持しながら、オブジェクトに対する多数のメモリアクセスを実行すると、多数の潜在的な通信ポイントが生成されますが、実際にはロックされたセクションは1つの大きな通信ポイントを表すだけです。カーネルが「ロック取得」および「ロック解放直前」イベントを提供すると役立つかもしれません。

しかし、ロックによって引き起こされる不可能な順序付けは、オブジェクトがグローバルポインタに公開される前に初期化されるなどのことによって引き起こされる不可能な順序付けとそれほど異ならないため、これは非常に一般的なアプローチではないかもしれません。

不可能な順序付けの検出を高速化:デッドロック検出

私の現在の実装では、遅延注入によって不可能な順序付けを強制しようとすると、一方のスレッドがロックでスピン/待機し、もう一方のスレッドが遅延注入タイムアウトに達する結果となり、非効率的です。単純なケースでこのような半デッドロックを検出し、テストケースをより迅速に中止できるロックデバッグインフラストラクチャとの統合が役立つかもしれません。

ファジング:Snowboardのような潜在的な通信ポイントを持つテストケースの構築

Snowboard(ファザー生成の単一スレッドテストケース間の相互作用によって引き起こされる並行性バグを検索するプロジェクト)は、単一スレッドテストケースでのメモリアクセスの記録情報を使用して、並列実行時に興味深い通信ポイントを持つ可能性のあるテストケースを特定しました。このKCOVベースのインストルメンテーションの上に同様のものを構築するのは興味深いでしょう。

単一スレッドテストケースの作成にもこれを使用するのは興味深いかもしれません。まず個々のシステムコールのメモリアクセス範囲を収集し、それを使用してどのシステムコールがシーケンスで実行されたときに互いに興味深い方法で相互作用する可能性があるかを判断し、このようにしてより長いシステムコールシーケンスを構築します。

私のアプローチはテストケース実行間で安定したデータアドレスをもたらさないため、VMスナップショット(SKIのような)を使用するとこれが容易になります。しかし、テストケースごとに割り当てられるすべてのオブジェクトに対して割り当てサイト情報が利用可能であれば、割り当てサイトに基づいて、テストケース間で異なるメモリ位置を抽象的に識別することでおそらく可能でしょう。

KCOV出力をホスト共有メモリに

私の現在のツールは、テスト中のカーネルがパニックした場合にKCOV出力を失うため、カーネルクラッシュが発生したときに何が起こったかを表示するために使用できません。

テスト中のカーネルがKVMゲストであるユースケースでは、ホストがKCOV出力バッファに直接アクセスできるようにすると役立つかもしれません。これを行う1つの方法は、virtiofsとDAX上のファイル内のページをKCOV出力バッファとして使用し、ユーザー空間が提供するページにKCOV出力を書き込めるようにすることです。