web-dev-qa-db-ja.com

GCCとClang(または一般的にLLVM)でスペクターを軽減する方法

Microsoftは、便利な/QspectreをMSVCコンパイラに追加しました(ただし、現時点ではSpectre v1を軽減しようとしているだけのようです)。これは、ユーザーの観点からは非常に優れています。そのフラグを有効にするだけで、ユーザーが保管している最新かつ最大の緩和策を得ることができます。

LLVMとGCCでは、外観が少し異なります。彼らの緩和策はまだ正式に発表されていないと思います。

LLVMは、間接呼び出しのリターントランポリンを介してSpectrev2を軽減する-mretpolineコンパイラフラグを取得することになっています。

一方、GCCには、Spectrev2を軽減するための3つのコンパイラオプションを追加するパッチがあります。

  • thunkに設定できる-mindirect-branch。私の理解では、これはすべての間接呼び出しに対してretpolinesを作成します。
  • thunkに設定できる-mfunction-return。これらのプロセッサはリターンも予測できるため、Skylakeで必要になる可能性がある、関数のリターンごとにこれらのレトポリンを使用していると思いますか?
  • -mindirect-branch-registerこれは、スタックの代わりにレジスタを使用して、間接呼び出しのアドレスを格納しますか?

だから私はかなり混乱しています。どのコンパイラオプションが、ユーザースペースアプリケーションに必要なものとシナリオを軽減しますか?

一般的にそれらをオンにするのは良い考えですか?投機的実行さえも行わないプロセッサアーキテクチャ(マイクロプロセッサなど)用にコンパイルされた場合、これらのレトポリンも生成されますか?

Spectre v1はどうですか?

更新:

もっと正確な質問をさせてください:

  • コンパイラオプションが正しく機能することを理解していますか?
  • GCCオプションはどこにでも適用されますか、それとも投機的実行のあるプロセッサーにのみ適用されますか?
  • LLVMオプションはどこにでも適用されますか、それとも投機的実行のあるプロセッサーにのみ適用されますか?
  • これらのオプションは正確に何を軽減しますか(スペクターv2を完全に軽減しますか)?
  • 私が尋ねた他のすべてを、知っておくとよいが私の質問に不可欠ではない追加の「ボーナス」質問であると考えてみましょう。
14
FSMaxB

コンパイラオプションが正しく機能することを理解していますか?

私はそう思う。

GCCオプションはどこにでも適用されますか、それとも投機的実行のあるプロセッサにのみ適用されますか?

これまでのところ、オプションはx86固有です。同等のARMパッチがあるかどうかは確認しませんでしたが、いずれの場合でも、これらのオプションは少なくとも部分的にプロセッサアーキテクチャに依存します。

patches の一部だけを見ましたが、追加のランタイムチェックが課されているようには見えません。むしろ、オプションが設定されている場合にバックエンドが不要な間接ジャンプをまったく発行しないように、命令の選択が変更されます。

したがって、このオプションは完全に無関係なアーキテクチャには適用されませんが、特定のCPUが実行時に脆弱であるかどうかを検出する試みは行われません。約から販売されている最もよく知られているx86プロセッサに注意してください。 PentiumProは投機的実行を使用します。

これらのオプションは正確に何を軽減しますか(スペクターv2を完全に軽減しますか)?

ほとんどの場合、それぞれの間接呼び出しで攻撃者が制御する推測が発生しないようにすることで、分岐ターゲットインジェクション(Spectre v2)を軽減します。

Retpolinesは、return命令を使用してターゲットアドレスにジャンプすることでこれを実現します。これは、基本的に最新の呼び出しがどこから来たかを記憶する別の分岐予測子を使用します。これは、return命令の前に呼び出し命令を実行する生成されたコードによって操作されます。これにより、呼び出しの後にmfence命令を配置することにより、推測された実行が行き止まりになります。詳細については、 この回答 を参照してください。

「5.1ディスカッション」の Spectre Paper で説明されているように、攻撃者が悪用するためにマップされたコードがたくさんある可能性があるため、分岐ターゲットインジェクションは問題です。議論はWindowsについて話しますが、Linuxにもマップされた共有ライブラリからのコードが必要だと想像できます。そのコードのアドレスがよりランダム化されている場合、悪用はより困難になる可能性がありますが、私はチェックせずにそれを当てにすることはありません。特に、Linuxカーネルには、攻撃者が任意のブランチターゲットを挿入する能力を持って使用する可能性のある多くのコードが含まれています。

-mfunction-return

一見、より複雑なリターンに置き換えることでリターンを保護するのはばかげているように見えますが、David Woodhouseによる このメッセージ によると、記憶のアンダーフロー時にオプションがLinuxカーネル開発者によって要求されましたリターンアドレス(基本的にはコールスタックに続く隠しスタック)、一部のCPUは再びグローバル分岐予測子をプルしますが、これは攻撃者によって操作される可能性があります。だからあなたの説明は正しかった。同じメッセージによると、このフラグはLinuxカーネルによってすぐには使用されませんでした。リターンは他の間接ブランチよりもはるかに一般的であり、特殊なリターン予測は実際に優れたヒット率を達成するため、パフォーマンスへの影響は大きいと思います。

-mindirect-branch-register

-mindirect-branch-registerが何を軽減するのかよくわかりません。どうやら他のオプションと一緒にテストスイートで必要なようですが、まだ説明が見つかりませんでした。また Xenは このオプションを-mindirect-branch=thunk-externと一緒に使用します。これは、サンクコードを自分で記述し、コンパイラに生成させないことを意味します。私の最初の推測とは反対に、これはアドレスがロードされている間の潜在的な推測とは何の関係もありません。これは、その推測を防ぐレトポリンで使用することを目的としているためです。いくつかの議論では、レジスタではなくスタック上のターゲットアドレスを取得するサンクのバージョンが、最初はIntel Control-flow Enforcement Technology (CET)と競合していると言及されました。 retpolinesが異常な方法でリターンを使用しているので、CETはジャンプを防いだと思います。ただし、 このディスカッション によると、これらの問題は解決されたようであり、CETをサポートするマシンでは、他の緩和策(IBRS_ALL)を使用できます。これにより、レトポリンサンクを再び間接ジャンプに置き換えることができます。このオプションだけではあまり役に立たないと思います。

更新:Spectre Variant 1

最近ChandlerCarruth 提案 LLVMでSpectreV1を軽減する方法。これはまだ進行中の作業であり、まだリリースされていません(2018年3月現在)。基本的な考え方は、脆弱なアドレスまたは誤って推測されたパス上のロードされた値を、副作用で使用する前にマスクすることです。

6
PaulR