web-dev-qa-db-ja.com

レトポリンとは何ですか?

カーネルやプロセス間のメモリ漏洩( Spectre 攻撃)を軽減するために、 Linuxカーネル)1 いわゆる retpoline を介して間接的な呼び出しを実行するためにgccに導入された新しいオプションでコンパイルされます-mindirect-branch=thunk-extern

これは、Googleの検索がごく最近になって使用されるようになったために新しく発明された用語のように思われます(一般的にはすべて2018年)。

Retpolineとは何ですか?また最近のカーネル情報漏えい攻撃をどのように防ぎますか?


1 しかし、これはLinux特有のものではありません - 他のOSでは 緩和戦略 の一部として類似または同一の構成が使用されているようです。

221
BeeOnRope

GoogleのPaul Turnerが書いたコメントの中でsgbjが述べた記事 は、以下のことをもっと詳しく説明していますが、私はそれを一撃します。

今のところ限られた情報からこれをまとめることができる限り、retpolineは return trampoline です。無限ループを使用し、CPUが間接ジャンプのターゲットを推測するのを防ぐために実行されることはありません。 。

基本的なアプローチは Andi Kleenのカーネルブランチにあります この問題への対処:

これは、メモリアドレス(これをADDRと呼びます)がスタックの最上位に格納されている呼び出し先をロードし、RET命令を使用してジャンプを実行する新しい __x86.indirect_thunk callを紹介します。サンク自体は、 NOSPEC_JMP/CALL マクロを使用して呼び出されます。これは、(すべてではないにしても)多くの間接呼び出しとジャンプを置き換えるために使用されていました。マクロは単に呼び出し先をスタックに置き、必要に応じてリターンアドレスを正しく設定します(非線形制御フローに注意してください)。

.macro NOSPEC_CALL target
    jmp     1221f            /* jumps to the end of the macro */
1222:
    Push    \target          /* pushes ADDR to the stack */
    jmp __x86.indirect_thunk /* executes the indirect jump */
1221:
    call    1222b            /* pushes the return address to the stack */
.endm

最後のcallの配置は、間接呼び出しが終了したときに制御フローがNOSPEC_CALLマクロの使用の背後で継続するように必要であるため、通常のcallの代わりに使用できます。

さんく自体は次のようになります。

    call retpoline_call_target
2:
    lfence /* stop speculation */
    jmp 2b
retpoline_call_target:
    lea 8(%rsp), %rsp 
    ret

ここでは制御フローが少し混乱しやすいので、明確にしておきます。

  • callは現在の命令ポインタ(ラベル2)をスタックにプッシュします。
  • leastack pointerに8を加えて、最後に返された(ラベル2への)最後のクワッドワードを事実上破棄します。この後、スタックの先頭は再び実際のリターンアドレスADDRを指します。
  • ret*ADDRにジャンプし、スタックポインタを呼び出しスタックの先頭にリセットします。

結局、この振る舞い全体は、*ADDRに直接ジャンプするのと実質的に同等です。 1つの利点は、call命令を実行するときにreturnステートメントに使用される分岐予測子(Return Stack Buffer、RSB)が、対応するretステートメントがラベル2にジャンプすることを前提としていることです。

ラベル2の後の部分は実際には決して実行されません。それは理論的には命令パイプラインをJMP命令で満たす無限ループです。 LFENCEPAUSE、またはより一般的には命令パイプラインを停止させる命令を使用することによって、CPUがこの投機的実行のための電力と時間を無駄にすることを防ぎます。これは、retpoline_call_targetの呼び出しが正常に終了した場合、LFENCEが次に実行される命令になるためです。これは、分岐予測子が元の戻りアドレス(ラベル2)に基づいて予測するものでもあります。

Intelのアーキテクチャマニュアルから引用するには:

LFENCEに続く命令は、LFENCEより前にメモリからフェッチされますが、LFENCEが完了するまで実行されません。

ただし、仕様ではLFENCEとPAUSEによってパイプラインが停止することについては言及されていないため、ここでは行間を少し読みます。

さて、元の質問に戻ります。カーネルメモリ情報の開示は、2つのアイデアの組み合わせによって可能になります。

  • 投機が間違っていたときに投機的実行は副作用がないはずですが、投機的実行は依然としてキャッシュ階層に影響を与えます。これは、メモリロードが投機的に実行されるとき、それでもキャッシュラインが追い出された可能性があることを意味します。キャッシュ階層のこの変化は、同じキャッシュセットにマップされているメモリへのアクセス時間を慎重に測定することによって識別できます。
    読み込んだメモリのソースアドレスがカーネルメモリから読み込まれたものである場合、任意のメモリの一部のビットをリークすることさえあります。

  • Intel CPUの間接分岐予測子は、ソース命令の最下位12ビットしか使用しないため、2 ^ 12の可能性のある予測履歴すべてをユーザー制御のメモリアドレスで汚染するのは簡単です。間接ジャンプがカーネル内で予測されるとき、これらはカーネル特権で投機的に実行される可能性があります。したがって、キャッシュタイミングサイドチャネルを使用すると、任意のカーネルメモリをリークする可能性があります。

更新: カーネルメーリングリスト で、リターンスタックバッファ(RSB)が空になったときのように、retpolinesが分岐予測の問題を完全には軽減しないと信じるように私に導く進行中の議論があります。インテルのアーキテクチャー(Skylake +)は、脆弱なBranch Target Buffer(BTB)にフォールバックします。

緩和戦略としてのレトポリンは、BTBから来る予測が攻撃者によって害される可能性があるため、間接分岐をリターンと交換します。 Skylake +の問題は、RSBアンダーフローがBTB予測の使用にフォールバックすることです。これにより、攻撃者は投機を制御することができます。

145
Tobias Ribizel

retpolineブランチターゲットインジェクションから保護するように設計されています(CVE-2017-5715) exploit。これは、カーネル内の間接分岐命令を使用して任意のコードチャンクを強制的に実行する攻撃です。選択されたコードは攻撃者にとってどういうわけか役に立つ "ガジェット"です。たとえば、キャッシュへの影響によってカーネルデータがリークするようにコードを選択できます。 retpolineは単にすべての間接分岐命令をreturn命令で置き換えることによってこの悪用を防ぎます。

Retpolineについて重要なのは単に "ret"の部分だと思います。それは間接分岐をreturn命令に置き換えて、CPUが悪用可能な分岐予測子の代わりにreturn stack予測子を使用するようにすることです。単純なPushとreturn命令を代わりに使用した場合、投機的に実行されるコードは、関数が最終的にとにかく戻るコードであり、攻撃者にとって有用なガジェットではありません。トランポリン部分の主な利点は、関数が実際にその呼び出し元に戻ったときにこれが正しく予測されるように、リターンスタックを維持することにあるようです。

分岐ターゲット注入の背後にある基本的な考え方は単純です。これは、CPUがその分岐先バッファに分岐元と宛先のフルアドレスを記録しないという事実を利用しています。そのため、攻撃者は、特定の間接ジャンプがカーネルアドレス空間で実行されたときに予測ヒットする結果となる、自身のアドレス空間でのジャンプを使用してバッファを埋めることができます。

Retpolineはカーネル情報の開示を直接妨げるのではなく、間接的な分岐命令が情報を開示するガジェットを投機的に実行するために使われるのを防ぐだけです。攻撃者がガジェットを投機的に実行するための他の手段を見つけることができれば、retpolineは攻撃を阻止しません。

論文 幽霊攻撃:投機的実行の利用 Paul Kocher、Daniel Genkin、Daniel Gruss、Werner Haas、Moritz Lipp、Stefan Mangard、Thomas Prescher、Michael Schwarz、およびYuval Yaromによる間接的な方法の概要ブランチは悪用される可能性があります。

間接分岐を利用する。 リターン指向プログラミング(ROP)から引き出す、この方法では、攻撃者は被害者のアドレス空間からガジェットを選択し、被害者にガジェットを投機的に実行させる。 ROPとは異なり、攻撃者は被害者のコードの脆弱性に依存しません。代わりに、攻撃者は間接ターゲット命令からガジェットのアドレスへの分岐を誤って予測するようにBranch Target Buffer(BTB)を訓練し、その結果、ガジェットが投機的に実行されます。投機的に実行された命令は破棄されますが、キャッシュへの影響は元に戻されません。これらの効果は、機密情報を漏らすためにガジェットによって使用される可能性があります。ガジェットを慎重に選択して、このメソッドを使用して被害者から任意のメモリを読み取る方法を示します。

BTBを誤解させるために、攻撃者は被害者のアドレス空間でガジェットの仮想アドレスを見つけ、このアドレスへの間接分岐を実行します。このトレーニングは攻撃者のアドレススペースから行われます。攻撃者のアドレススペースのガジェットアドレスにあるものは関係ありません。必要なのは、ブランチのトレーニングに使用されたブランチが同じ宛先仮想アドレスを使用することだけです。 (実際、攻撃者が例外を処理している限り、攻撃者のアドレス空間のガジェットの仮想アドレスにコードがマッピングされていなくても攻撃は可能です。)送信元アドレスの完全一致も必要ありません。トレーニングに使用されたブランチのアドレスとターゲットブランチのアドレス。したがって、攻撃者はトレーニングを設定する際に大きな柔軟性を持っています。

GoogleのProject Zeroチームによる サイドチャネルによる特権メモリの読み取り というブログエントリに、ブランチターゲットインジェクションを使用して実用的なエクスプロイトを作成する方法の別の例が掲載されています。

42
Ross Ridge

この質問は少し前に尋ねられたもので、新しい答えに値します。

エグゼクティブサマリー

「Retpoline」シーケンスは、間接分岐を投機的実行から分離できるソフトウェア構成体です。これは、敏感なバイナリ(オペレーティングシステムやハイパーバイザーの実装など)を、間接的なブランチに対するブランチターゲットインジェクション攻撃から保護するために適用できます。

単語「 retpoline 」は、単語「return」および「trampoline」の portmantea "、改善とよく似ています" relpoline "は、「相対呼び出し」と「トランポリン」から作られました。これは、関連する投機的実行が無限に「バウンス」することを比fig的に保証するリターン操作を使用して構築されたトランポリン構造です。

カーネルまたはプロセスにまたがるメモリの開示(Specter攻撃)を緩和するために、Linuxカーネル [1] 新しいオプションでコンパイルされます。-mindirect-branch=thunk-externはgccに導入され、いわゆるretpolineを介して間接呼び出しを実行します。

[1]ただし、Linux固有ではありません-他のOSの緩和戦略の一部として、類似または同一の構造が使用されているようです。

このコンパイラー・オプションonlyを使用すると、CVE-2017-に必要なマイクロコード更新がある影響を受けるプロセッサーで Spectre V2 から保護されます5715。どのコード(カーネルだけでなく)でも「work」になりますが、攻撃する価値があるのは「秘密」を含むコードのみです。

Google検索ではごく最近の使用(一般的にはすべて2018年)が判明したため、これは新しく考案された用語のようです。

LLVMコンパイラ には 2018年1月4日以前 以降、-mretpolineスイッチがあります。その日は、脆弱性が 最初に公表された であった日です。 GCC パッチを利用可能にしました 2018年1月7日。

CVE日付は、この脆弱性が2017年に「discovered」であったことを示唆していますが、過去20年間に製造されたプロセッサーの一部に影響を及ぼします(したがって、かなり前に発見された可能性があります)。

レトポリンとは何ですか?最近のカーネル情報漏えい攻撃をどのように防ぐのですか?

まず、いくつかの定義:

  • トランポリン -間接ジャンプベクトルと呼ばれることもありますトランポリンは、割り込みサービスルーチン、I/Oルーチンなどを指すアドレスを保持しているメモリの場所です。用語トランポリン。 GCCは伝統的に ネストされた関数のアドレスが取得されたときに実行時に実行可能なトランポリンを作成することにより、ネストされた関数をサポートしました。これは、通常、スタックを含む関数のスタックフレームにある小さなコードです。トランポリンは、静的チェーンレジスタをロードし、ネストされた関数の実際のアドレスにジャンプします。

  • サンク -サンクは、別のサブルーチンに追加の計算を注入するために使用されるサブルーチンです。サンクは主に、結果が必要になるまで計算を遅らせるため、または他のサブルーチンの最初または最後に操作を挿入するために使用されます

  • メモ化 -メモ化された関数は、特定の入力セットに対応する結果を「記憶」します。記憶された入力を使用した後続の呼び出しは、再計算ではなく記憶された結果を返すため、これらのパラメーターを使用して関数に対して行われる最初の呼び出し以外のすべてのパラメーターからの呼び出しの主なコストを排除します。

大体、retpolineはaトランポリンreturnwiththunk、to 'spoil'memoization間接ブランチ予測子。

ソース :IntelのPAUSE命令が含まれていますが、AMDにはLFENCE命令が必要です。これは、そのプロセッサではPAUSE命令がシリアル化命令ではないため、pause/jmpループが次のように過剰電力を使用するためです正しいターゲットへの予測ミスへの復帰を待機していると推測されます。

Arstechnica には問題の簡単な説明があります。

「各プロセッサには、アーキテクチャの動作(命令の動作とプログラマがプログラムの作成に依存することを説明する文書化された動作)とマイクロアーキテクチャの動作(アーキテクチャの実際の実装の動作)があります。これらは微妙に異なる場合があります。たとえば、アーキテクチャ上、メモリ内の特定のアドレスから値をロードするプログラムは、ロードが実行される前にアドレスがわかるまで待機しますが、マイクロアーキテクチャ的には、プロセッサはアドレスを推測的に推測し、開始できる場合があります使用するアドレスが完全に特定される前であっても、メモリから値をロードします(低速です)。

プロセッサが間違って推測した場合、推測された値を無視し、今回は正しいアドレスで再度ロードを実行します。したがって、アーキテクチャ的に定義された動作が保持されます。しかし、その誤った推測は、プロセッサの他の部分、特にキャッシュの内容を妨害します。これらのマイクロアーキテクチャの障害は、キャッシュにあるべき(またはすべきでない)データにアクセスするのにかかる時間を計ることで検出および測定でき、悪意のあるプログラムがメモリに格納されている値について推測することができます。」.

Intelの論文から: " Retpoline:A Branch Target Injection Mitigation "( 。PDF ):

「レトポリンシーケンスは、プロセッサの投機的実行が「間接分岐予測」(プログラムフローを予測する1つの方法)を使用して、悪用(分岐ターゲットインジェクションの5つの要素の満足な要素4(スペクターバリアント2) )上記の構成を活用してください。」。

注、要素4は次のとおりです。「エクスプロイトは、この間接ブランチに影響を与えて、ガジェットを推測的に予測および実行する必要があります。エクスプロイトによって選択されたこのガジェットは、通常、キャッシュタイミングによってサイドチャネルを介して秘密データを漏らします。」.

7
Rob