web-dev-qa-db-ja.com

すべてのページフォールトでフォールトアドレスをチェックしてメルトダウンを軽減しますか?

短い質問

すべてのページフォールトのフォールトアドレスがカーネルメモリをポイントしているかどうかを確認すると、Intel TSXが不足している(したがって例外を抑制できない)システムで、試行されたMeltdownエクスプロイトが確実に検出されますか? Linuxカーネルdo_page_fault()関数は、すべてのページフォールトで呼び出され、フォールトメモリアクセスのアドレスはその関数で使用できるため、そのアドレスが特定のメモリ範囲を指しているかどうかを確認できるはずです。カーネル。 KPTIがオプションではなく、機密性と可用性(非特権DoS)のトレードオフが許容される脅威モデルの場合、この考え方は正しいですか?


長い質問

最近開示されたIntelプロセッサのMeltdown脆弱性は、すべての最新のプロセッサのアウトオブオーダー実行プロパティを利用して、任意の物理メモリを読み取ります。これは、アクセスの試行が失敗するという事実にもかかわらず、カーネルメモリへのアクセスを繰り返し試行できることに依存しています。これらのアクセス試行の失敗は、_#PF_、またはページフォールトをトリガーし、カーネルメモリへのアクセス試行のために、ユーザー空間プロセスにSIGSEGVが送信されます。 Meltdown攻撃は、アクセスが拒否されているにもかかわらず、キャッシュに特権メモリが引き続き投入されるという事実を利用します。攻撃の次の段階は、タイミング攻撃を使用してキャッシュの内容を取得することです。ただし、TSXのサポートがなければ、これらのページフォールトを抑制することは(私の知る限り)不可能であるようです。そのようなシステムでは、Meltdownは必然的にカーネルメモリへのアクセスの試行によって引き起こされる多数のページフォールトをトリガーします。これはカーネルによって検出できます。

論文 から、攻撃を実行するための3つのステップが説明されています:

メルトダウンは、セクション4で説明した2つのビルディングブロックを組み合わせます
。最初に、攻撃者はCPUを実行させます
不正確な
秘密を使用する一時的な命令シーケンス物理メモリ
のどこかに格納されている値(セクション4.1を参照)。一時的な命令シーケンスは、
秘密チャネルの送信機として機能し(セクション4.2を参照)、
最終的に秘密の値を攻撃者に漏らします。
 
メルトダウンは、 3ステップの:
 
ステップ1  攻撃者が選択したメモリの場所(攻撃者がアクセスできない場所)の内容は、レジスタにロードされます
。
 
ステップ2  一時的な命令は、レジスタの秘密の内容に基づいてキャッシュラインにアクセスします。
 
 
ステップ3  攻撃者はFlush + Reloadを使用して、
にアクセスしたキャッシュラインを決定し、
で選択したメモリの場所に保存されているシークレットを特定します。場所、
攻撃者は、
全体の物理メモリを含むカーネルメモリをダンプできます。

カーネルトレースサブシステムを利用して 想定される緩和策 について読んだ後、カーネルメモリへのアクセスによる異常に多数のページフォールトを検出すると、メルトダウンを確実に検出できるようになります。私の考えは正しいですか?このような軽減策は、_CR2_(フォールトアドレスを保持するレジスタ)が_0xffff000000000000_よりも大きいかどうかを各ページフォールトで単にチェックします。これは、カーネルメモリにアクセスしようとしたことを示します。その後、システムはカーネルパニックを引き起こし、攻撃が続行されないようにします。

カーネルソース から、do_page_fault()関数は次のように定義されます。

_dotraplinkage void notrace
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
    unsigned long address = read_cr2(); /* Get the faulting address */
    enum ctx_state prev_state;

    prev_state = exception_enter();
    if (trace_pagefault_enabled())
        trace_page_fault_entries(address, regs, error_code);

    __do_page_fault(regs, error_code, address);
    exception_exit(prev_state);
}
NOKPROBE_SYMBOL(do_page_fault);
_

この関数は、ページフォールトが発生するたびに呼び出され、フォールトアドレスがaddressに保存されます。 TSXのサポートがなければ、私の知る限り、攻撃がこの関数に入ることを回避することは不可能です。アドレスが危険な範囲にあるかどうかを確認する簡単なチェックを追加したいので、BUG_ON(address > 0xffff000000000000)の行に沿った何かがこれらの制約の下でメルトダウン攻撃の100%を確実に検出します。これは、十分な数の違反が発生した場合にのみパニックをトリガーし、addressが_mmap_min_addr_より小さい場合に違反を無視することで、信頼性を高めることができます(誤検知をトリガーする可能性が低くなります)。良性のNULLポインター逆参照)が、特定のワークロードが誤検知をトリガーする場合にのみ必要です。

次のいずれかに該当する場合、この緩和策は機能しません。

  • ページ違反を引き起こさないSpectreは、eBPFを悪用することなくMeltdownを実行できます。
  • TSXのないシステムでは、ページフォールトをトリガーせずにMeltdownを使用する別の方法があります。
  • do_page_fault()関数は、ページ違反が発生したときに回避できます。

論文を再読するとき、それはTSX以外の方法を使用した例外抑制に言及していますが、私には完全に明確ではありません。次のようにページ違反を回避できるかのように聞こえます。

_if (condition_mispredicted_as_false)
    access_kernel_memory();
_

これが真の場合、この検出メカニズム(およびCapsule8による検出メカニズム)は機能しません。

この緩和策は、TSXのないシステムで機能しますか?自然な誤検知は問題ではないと想定し、非特権のDoSバグを開くという事実を無視しますか?

8
forest

これにより、メルトダウン攻撃を実行する3つの方法のうち2つを防ぐことができます。残念ながら、3つ目は何もしません。

Meltdown攻撃を行う最も簡単な方法は、ページフォールトがトリガーされる前にCPUが読み取りに投機的に作用するように十分に長いパイプライン遅延で不正な読み取りを実行してから、障害をキャッチすることです。攻撃者が数回以上の読み取りを実行できるようになる前に、提案はそれを見つけて停止します。

より高速な方法は、TSXを使用して障害を抑制することですが、TSXがシステムに存在しないことを指定しました。

3番目の方法は、MeltdownをSpectreの分岐予測ミスと組み合わせる方法です。無害なアドレスで「メモリの読み取り」分岐を行うように分岐予測子をトレーニングし、保護されたアドレスを指定しながら別の方法で分岐します。これは、保護されたメモリを読み取る他の方法よりもはるかに低速ですが、ブランチの予測ミスが発見されると、不正な読み取りが破棄されるため、ページフォールトは発生しません。その結果、読み取りは提案されたコードから完全に見えなくなります。

5
Mark