Spectre/Meltdownとその派生
SCAIS2019 2019/1/21
光成滋生(サイボウズ・ラボ)
• x64の命令実行・メモリアクセスの仕組み
• Meltdown/Spectreの概要
• ソフトウェア・CPUでの対策
• 宣伝 SCIS2019
• 2A2-4 準同型暗号の平文空間を制限する
コンパクトなゼロ知識証明
スライドの目的
2 / 32
• rax, rbx, rcx, ... ; レジスタ(64bit整数)
• al, bl, cl, ... ; 8bit整数レジスタ
• mov ; メモリとレジスタ間の値設定命令
• mov al, [addr] ; addrが指すメモリの値をalに読む
• mov [addr], al ; alの値をaddrが指すメモリに書く
• test x, y / je label
• xとyを比較して等しい(jmp if equal)ならならジャンプ
x64アセンブリ言語(以下asm)
mov al, [mem] ; memから値をalに読み
test al, 1 ; 1と比較して
je Leq ; 等しいならLeqにjmp
jmp .Lexit ; そうでなければLexitにjmp
Leq: mov [user], al ; alの値をuserに書く
...
Lexit: 3 / 32
• asm命令を複数のμ命令(μ-op)に分解
• 例:add [rcx], rax
• load r1 ←[rcx] ; r1←r1 + rax ; store [rcx]←r1 (イメージ)
• Out-of-order実行(OOO)
• 依存関係を考慮しつつ複数のμ-opを複数のport上でOOO
asm命令の処理
Intel Architectures Optimization Reference Manual 2.3
4 / 32
• μ-opの状態を管理するROB(reorder buffer)
• ある命令に対する分解された全てのμ-opの処理が完了すると
その結果が実際のCPUの状態に反映される
• 実行中に例外や割り込みが発生すると結果は破棄される
• その途中の命令を一時的命令と呼ぶ(ここだけの用語)
処理の完了
5 / 32
• メモリは遅い
• DRAMに1回アクセスすると数十nsec
• addは0.1nsecぐらい(0.3nsecに3回ぐらい可能)
• キャッシュメモリ
• 小容量だが高速(1nsec~)に読める補助メモリ
• あるアドレスの値を読むと次回そのアドレスは
(キャッシュにあれば)高速に読める
• CPUに近い方からL1, L2, L3と階層構造
• できれば速いキャッシュメモリを使い回したい
• 効率化のための様々な仕組み
• シーケンシャルにメモリを読んでいれば
次読みそうな部分を先読みしておく
メモリから値を読むまで
6 / 32
• 分岐やデータの読み書きは遅延する
• その結果を予測したパスに沿って実行
• 予測が正解
• 事前計算結果を実際に反映
• 予測が不正解
• 事前計算結果を破棄して元の状態にロールバック
• 処理が確定するまでの一時的命令の実行中の結果は
CPUの状態に副作用をもたらしてはいけないはず
• メモリキャッシュに副作用があった
• もちろんCPUのレジスタやメモリの値は書き換わっていない
投機実行
7 / 32
• メモリの読み込み速度差を利用した攻撃
• clflush ; キャッシュの全レベルの内容を無効化
• テーブルのどこか一カ所をアクセスしてキャッシュに入れる
• テーブルの各要素のメモリアクセス時間を調べる
Flush+Reload
x1 x2 x3 x4 x5 x6x0
テーブルx
空
キャッシュ
4番目
を読む
x4
テーブルxを順次読みその速度を測定
アクセス
時間
index
キャッシュに
入っている
4番目だけ速い
clflush
8 / 32
• 一時的命令がメモリを読んだときの
キャッシュの副作用を悪用
• secretを読む権限の無いアプリ
• (try)一時命令がsecretを読みuserのメモリのraxをアクセス
• (err)その後secretが読めないことが判明し例外発生で巻き戻し
• (cache)しかしuserを読んだキャッシュはクリアされない
• (probe)後でuserの領域で速く読めた場所(x)があれば
secretの値はxだったと判明
• 4096倍するのは(probe)で先読み機構の影響をなくすため
https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html
Meltdownの基本アイデア
mov rax, byte [secret]; secretから値を1byte読む
shl rax, 12 ; 12bit左シフト(4096倍)
mov rax, [user+rax] ; userのrax番目のメモリを読む
9 / 32
• 複数プロセスによる並列処理時の
トランザクション処理(TX)をサポートする命令群
• TX開始(txbegin) - 実際の処理 - TX終了(txend)をatomicに行う
• 途中で失敗すれば全て巻き戻されてabortしてやり直す
• Meltdownではエラーは1回
• (try)のコードをTSXに行う
• 例外発生でscretの値が判明してabortするので再度tryできる
• secretをずらしながら何度も(try)可能
TSX (transactional synchronization extensions)
10 / 32
• 要件
• 不用意に他のプロセスのメモリ領域にアクセスできない
• 仮想メモリ
• プロセスごとに独立したメモリ空間を割り当てる
• ページング方式
• 仮想メモリを固定長(4KiB)のページに分割
• ページテーブルで管理
• 各ページが実際の物理メモリのどこに位置するかの情報
• アクセス権などの付加情報
• メモリにアクセスするとき
• プロセスがアクセスする仮想アドレスに対応する物理メモリ
を決定してアクセス
メモリの抽象化
11 / 32
• 多段のツリー構造を持ったページテーブルの参照
• メモリ空間(48bit=256TiB)を9+9+9+9+12 bitに分割
x64における参照方法
Intel Architectures Software Developer's Manual 4-20 Vol.3A
12 / 32
• 仮想アドレスから物理アドレスへの変換
• プロセスのCR3レジスタから
PML4E(Page Map Level 4 Entry)を参照
• PML4EからPDPTE(Page Directory Pointer Table)を参照
• PDPTEからPDE(Page Directory)を参照
• PDEからPTE(Page Table)を参照
• PTEから物理アドレスを参照
• 補足
• 1ページ4KiBは数十~数百GBのメモリで扱うには小さすぎる
• 1ページ2MiB(下位9+12bit), 1GiB(下位9+9+12bit)にする方式
• 段数が3段、2段に減る / テーブルに必要なメモリも減る
4段の参照
13 / 32
• 毎回このテーブル参照は遅すぎる
• TLB
• 変換結果をキャッシュして高速化するためのバッファ
• 初回は通常のテーブル参照しそのアドレスを記録
• 次回からはそこを再利用
• プロセスが切り替わるとそのエントリは無効化される
TLB(Translation Lookaside Buffer)
14 / 32
• 最近のCPUは沢山のコアを持っている
• 複数のOSを起動しているVMMがいる(OSの仮想化)
• VMM(virtual machine monitor)
• ゲストOSで仮想アドレスから物理アドレスに変換しても
それは本当の物理アドレスではない
• 更にもう一度変換する必要がある
• Intel VT(virtualization technology)
• 仮想化支援技術
• EPT(extended page table)
• 通常の4段の参照の後にEPTを参照する
物理アドレスの仮想化
15 / 32
• MPX (memory protection extension) ; Skylake
• BND命令
• bnd0, ..., bnd3 ; チェック用レジスタ
• 配列などのメモリ境界を設定し範囲をチェックする機構
• 範囲外なら#BR例外
• PK (protection keys) ; Skylake-SP(scalable processor)
• ユーザ空間でページ単位の保護を行う
• 従来はkernelにお願いして設定する(mprotect)しかない
• 読み書きの設定
• PKRU ; 保護用レジスタ
• rdpkru, wdpkru
• 設定外のアクセスは#PF例外
Intelの特殊なメモリ保護機能
16 / 32
• 重要なコードや情報をenclave(隔離領域)に分離
• CPUのみ信頼
• enclaveはシステムと独立でOSからも読めない
• EPC(enclave page cache)
• 隔離領域ページキャッシュ
• 物理メモリの一部がenclaveとして予約される
• EPCM(EPC map)で管理
• 許可されていなければ例外が発生
• 同様の機構:SMM(system management mode)
• OS起動前のBIOSでのみ利用可能
• 制限されたメモリアクセス
SGX(software guard extensions)
17 / 32
• https://foreshadowattack.eu/
• Intel CPUのL1キャッシュの挙動
• SGXのenclaveなメモリがL1キャッシュにあり、そのマッピン
グが破棄されたときに攻撃者がキャッシュ内容を解析できた
• SMMやVMMの内容をL1キャッシュ経由で取得できる可能性
L1TF(L1 terminal fault) ; Foreshadow-(NG)
Foreshadow-NG.pdf p.2 Figure 1 18 / 32
• 範囲チェックを超えた領域のアクセス
• (trained)正常パスでコードを繰り返し実行させて
CPUに分岐しないと予測させる
• (try)範囲外のxで実行
• (err)一時命令がsecretを超えた別のメモリを参照
• (cache)しかしuserを読んだキャッシュはクリアされない
• (probe)後でuserの領域で速く読めた場所(x)を探索
Spectreの基本アイデア
if (x < secret.size()) {
y = probe[secret[x] * 4096];
}
19 / 32
• 分岐系
• PHT(pattern history table), BHB(branch history buffer)
• 分岐命令ごとに「分岐した・しなかった」の履歴を保持
• Intelでは20回程度
• BTB(branch target buffer)
• 分岐命令ごとに分岐先アドレスを予測
• RSB(return stack buffer)
• call命令のリターンアドレス(関数の呼出元)を予測
• メモリ系
• STLF(store to load forwarding)
• memory disambiguation ; Intel SDM 2-34
• storeの後のloadを予測して先読み
• x1 = a[0]; b[0] = y; x2 = a[0];
さまざまな予測機構
20 / 32
• A Systematic Evaluation of Transient Execution Attacks
and Defenses, C.Canella, et.al., Nov. 2018
• https://arxiv.org/abs/1811.05441
• Spectre
• アプリがアクセスできるデータに一時的命令が作用する
• 一時的命令はアプリの通常フローで実行可能
• Meltdown
• アプリがアクセスできないデータに一時的命令が作用する
• 例外命令に続く一時的命令が例外命令のデータにアクセスで
きる性質を利用する
SpectreとMeltdownの網羅的論文
21 / 32
• same-address-space / cross-address-space
• 攻撃者と犠牲者のアドレス空間が同じか否か
• in-place / out-of-place
• 同じ分岐アドレスか異なる分岐アドレスか
• 予測表を小さくするためにハッシュ化して保持
• 異なる分岐先でも同じエントリを参照することがある
メモリレイアウトによるSpectreの分類
A Systematic Evaluation... p.4 Figure 3 22 / 32
• ブラウザはJavaScriptを実行するVMを持っている
• たくさんのユーザのプログラムを同一プロセスで動かす
• Spectreで使える機能
• SharedArrayBuffer
• 複数のワーカーでメモリを共有するための機能
• Performance.Now
• 高性能タイマー
• これらの機能が無効化・タイマーの精度をあえて下げた
• Chrome(2018/8)
• Site Isolation ; ドメインごとに別のプロセスで実行させる
ブラウザへの影響
23 / 32
• 例外
• GP ; general protection
• NM ; device-not-available ; FPUが無い
• BR ; bound range exceeded exception ; メモリ保護拡張MPX
• PF ; page fault
• 許可タイプ
• U/S ; user/supervisor
• P ; present(そのページが存在する / swapされてない)
• R/W ;
• RSVD ; reserved
• XD ; non executable
• PK ; protection key
例外種別によるMeltdownの分類
24 / 32
• p.3 Figure 1
A Systematic Evaluation...による分類
25 / 32
• KPTI(kernel page table isolation) + invpcid
• カーネル空間(Ks)とユーザ空間(Us)のページテーブルを分離
• 従来:Ksは常にマップされていた
• Usから直接アクセス不可なので大丈夫と思っていた
• 一般ユーザ権限から任意のメモリを読める可能性
• コンテナ貸しサービスで危険
• PCID(process contexst identifier)
• プロセス識別タグ
• 特定のプロセスのTLBを無効化
• カーネル実行時以外はKsを切り離す
• pros. 見えないので安全
• cons. User⇔Kernel時にPT切り換え. 場合によってTLB無効化
ソフトによる対策
26 / 32
• 配列チェックのテクニック
• 範囲を超えたindexは常に0になるのでSpectreが成功しない
• 対策が必要な部分を全てこのようにしないといけない
array_index_nospec
array_index_nospec(size_t index, size_t size) {
// maskはsize <= indexなら0そうでなければ-1
mask = int64_t(size - index) >> 63;
// 範囲内ならindex そうでなければ0
return index & mask;
}
27 / 32
• 間接分岐(call [eax])を使わないコードに変換
• 予測がかからないので遅くなる(悲しいジレンマ)
retpoline
retpoline(addr):
call .L ; ***
.T: ; callの次の命令が投機実行されても無限ループさせる
pause
lfence
jmp .T
.L:
[stack] <- addr
ret ; ***には戻らずaddrに戻る(=addrにジャンプする)
28 / 32
• 関数テーブルを使うコード
• 通常はjmpテーブルを生成
コンパイラサポート
int f(int x, int y) {
static int (*const p[])(int) = {
f0, f1, f2, f3, f4 // 関数ポインタテーブル
};
return p[x](y);
}
movsxd rax, x
mov rdx,<pointer to table>
jmp QWORD PTR [rdx+rax*8] ; p[x]
...
29 / 32
• retpolineコードを生成する
-mindirect-branch=thunk
f:
lea rdx,[rip+0x0]
movsxd rax,edi
mov edi,esi
mov rax,QWORD PTR [rdx+rax*8]
jmp __x86_indirect_thunk_rax
__x86_indirect_thunk_rax:
call c <__x86_indirect_thunk_rax+0xc>
pause
lfence
jmp 5 <__x86_indirect_thunk_rax+0x5>
mov QWORD PTR [rsp],rax
ret
30 / 32
• IBRS(Indirect Branch Restricted Speculation)
• 低い権限のモードでの間接分岐予測結果を
高い権限のモードが使わないようにする
• Linux 4.19からretpolineの代わりにenhanced IBRSを利用
• STIBP(Single Thread Indirect Branch Predictors)
• 一つの物理コアのある論理コアが
別の論理コアでの間接分岐予測を使わないようにする
• IBPB(Indirect Branch Predictor Barrier)
• バリアに続く間接分岐予測の影響を
バリアの前の実行が影響を受けないようにする
• プロセスやVMの切り替え時にBTBをフラッシュさせる
CPUの改善による対策
31 / 32
• x86/x64最適化勉強会での発表
• 図解でわかるSpectreとMeltdown;@satoru_takeuchi
• https://speakerdeck.com/sat/tu-jie-dewakaruspectretomeltdown
• SpectreBustersあるいはLinuxにおけるSpectre対策;@mhiramat
• https://www.slideshare.net/mhiramat/spectrebusterslinuxspectre
• Software guidance for security advisories;Intel
• https://software.intel.com/security-software-guidance/
• https://software.intel.com/security-software-
guidance/insights/deep-dive-managed-runtime-speculative-
execution-side-channel-mitigations
• C++ Developer Guidance for Speculative Execution
Side Channels;Microsoft
• https://docs.microsoft.com/en-us/cpp/security/developer-guidance-speculative-execution
参考文献(スライド内以外)
32 / 32

Spectre/Meltdownとその派生

  • 1.
  • 2.
    • x64の命令実行・メモリアクセスの仕組み • Meltdown/Spectreの概要 •ソフトウェア・CPUでの対策 • 宣伝 SCIS2019 • 2A2-4 準同型暗号の平文空間を制限する コンパクトなゼロ知識証明 スライドの目的 2 / 32
  • 3.
    • rax, rbx,rcx, ... ; レジスタ(64bit整数) • al, bl, cl, ... ; 8bit整数レジスタ • mov ; メモリとレジスタ間の値設定命令 • mov al, [addr] ; addrが指すメモリの値をalに読む • mov [addr], al ; alの値をaddrが指すメモリに書く • test x, y / je label • xとyを比較して等しい(jmp if equal)ならならジャンプ x64アセンブリ言語(以下asm) mov al, [mem] ; memから値をalに読み test al, 1 ; 1と比較して je Leq ; 等しいならLeqにjmp jmp .Lexit ; そうでなければLexitにjmp Leq: mov [user], al ; alの値をuserに書く ... Lexit: 3 / 32
  • 4.
    • asm命令を複数のμ命令(μ-op)に分解 • 例:add[rcx], rax • load r1 ←[rcx] ; r1←r1 + rax ; store [rcx]←r1 (イメージ) • Out-of-order実行(OOO) • 依存関係を考慮しつつ複数のμ-opを複数のport上でOOO asm命令の処理 Intel Architectures Optimization Reference Manual 2.3 4 / 32
  • 5.
    • μ-opの状態を管理するROB(reorder buffer) •ある命令に対する分解された全てのμ-opの処理が完了すると その結果が実際のCPUの状態に反映される • 実行中に例外や割り込みが発生すると結果は破棄される • その途中の命令を一時的命令と呼ぶ(ここだけの用語) 処理の完了 5 / 32
  • 6.
    • メモリは遅い • DRAMに1回アクセスすると数十nsec •addは0.1nsecぐらい(0.3nsecに3回ぐらい可能) • キャッシュメモリ • 小容量だが高速(1nsec~)に読める補助メモリ • あるアドレスの値を読むと次回そのアドレスは (キャッシュにあれば)高速に読める • CPUに近い方からL1, L2, L3と階層構造 • できれば速いキャッシュメモリを使い回したい • 効率化のための様々な仕組み • シーケンシャルにメモリを読んでいれば 次読みそうな部分を先読みしておく メモリから値を読むまで 6 / 32
  • 7.
    • 分岐やデータの読み書きは遅延する • その結果を予測したパスに沿って実行 •予測が正解 • 事前計算結果を実際に反映 • 予測が不正解 • 事前計算結果を破棄して元の状態にロールバック • 処理が確定するまでの一時的命令の実行中の結果は CPUの状態に副作用をもたらしてはいけないはず • メモリキャッシュに副作用があった • もちろんCPUのレジスタやメモリの値は書き換わっていない 投機実行 7 / 32
  • 8.
    • メモリの読み込み速度差を利用した攻撃 • clflush; キャッシュの全レベルの内容を無効化 • テーブルのどこか一カ所をアクセスしてキャッシュに入れる • テーブルの各要素のメモリアクセス時間を調べる Flush+Reload x1 x2 x3 x4 x5 x6x0 テーブルx 空 キャッシュ 4番目 を読む x4 テーブルxを順次読みその速度を測定 アクセス 時間 index キャッシュに 入っている 4番目だけ速い clflush 8 / 32
  • 9.
    • 一時的命令がメモリを読んだときの キャッシュの副作用を悪用 • secretを読む権限の無いアプリ •(try)一時命令がsecretを読みuserのメモリのraxをアクセス • (err)その後secretが読めないことが判明し例外発生で巻き戻し • (cache)しかしuserを読んだキャッシュはクリアされない • (probe)後でuserの領域で速く読めた場所(x)があれば secretの値はxだったと判明 • 4096倍するのは(probe)で先読み機構の影響をなくすため https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html Meltdownの基本アイデア mov rax, byte [secret]; secretから値を1byte読む shl rax, 12 ; 12bit左シフト(4096倍) mov rax, [user+rax] ; userのrax番目のメモリを読む 9 / 32
  • 10.
    • 複数プロセスによる並列処理時の トランザクション処理(TX)をサポートする命令群 • TX開始(txbegin)- 実際の処理 - TX終了(txend)をatomicに行う • 途中で失敗すれば全て巻き戻されてabortしてやり直す • Meltdownではエラーは1回 • (try)のコードをTSXに行う • 例外発生でscretの値が判明してabortするので再度tryできる • secretをずらしながら何度も(try)可能 TSX (transactional synchronization extensions) 10 / 32
  • 11.
    • 要件 • 不用意に他のプロセスのメモリ領域にアクセスできない •仮想メモリ • プロセスごとに独立したメモリ空間を割り当てる • ページング方式 • 仮想メモリを固定長(4KiB)のページに分割 • ページテーブルで管理 • 各ページが実際の物理メモリのどこに位置するかの情報 • アクセス権などの付加情報 • メモリにアクセスするとき • プロセスがアクセスする仮想アドレスに対応する物理メモリ を決定してアクセス メモリの抽象化 11 / 32
  • 12.
    • 多段のツリー構造を持ったページテーブルの参照 • メモリ空間(48bit=256TiB)を9+9+9+9+12bitに分割 x64における参照方法 Intel Architectures Software Developer's Manual 4-20 Vol.3A 12 / 32
  • 13.
    • 仮想アドレスから物理アドレスへの変換 • プロセスのCR3レジスタから PML4E(PageMap Level 4 Entry)を参照 • PML4EからPDPTE(Page Directory Pointer Table)を参照 • PDPTEからPDE(Page Directory)を参照 • PDEからPTE(Page Table)を参照 • PTEから物理アドレスを参照 • 補足 • 1ページ4KiBは数十~数百GBのメモリで扱うには小さすぎる • 1ページ2MiB(下位9+12bit), 1GiB(下位9+9+12bit)にする方式 • 段数が3段、2段に減る / テーブルに必要なメモリも減る 4段の参照 13 / 32
  • 14.
    • 毎回このテーブル参照は遅すぎる • TLB •変換結果をキャッシュして高速化するためのバッファ • 初回は通常のテーブル参照しそのアドレスを記録 • 次回からはそこを再利用 • プロセスが切り替わるとそのエントリは無効化される TLB(Translation Lookaside Buffer) 14 / 32
  • 15.
    • 最近のCPUは沢山のコアを持っている • 複数のOSを起動しているVMMがいる(OSの仮想化) •VMM(virtual machine monitor) • ゲストOSで仮想アドレスから物理アドレスに変換しても それは本当の物理アドレスではない • 更にもう一度変換する必要がある • Intel VT(virtualization technology) • 仮想化支援技術 • EPT(extended page table) • 通常の4段の参照の後にEPTを参照する 物理アドレスの仮想化 15 / 32
  • 16.
    • MPX (memoryprotection extension) ; Skylake • BND命令 • bnd0, ..., bnd3 ; チェック用レジスタ • 配列などのメモリ境界を設定し範囲をチェックする機構 • 範囲外なら#BR例外 • PK (protection keys) ; Skylake-SP(scalable processor) • ユーザ空間でページ単位の保護を行う • 従来はkernelにお願いして設定する(mprotect)しかない • 読み書きの設定 • PKRU ; 保護用レジスタ • rdpkru, wdpkru • 設定外のアクセスは#PF例外 Intelの特殊なメモリ保護機能 16 / 32
  • 17.
    • 重要なコードや情報をenclave(隔離領域)に分離 • CPUのみ信頼 •enclaveはシステムと独立でOSからも読めない • EPC(enclave page cache) • 隔離領域ページキャッシュ • 物理メモリの一部がenclaveとして予約される • EPCM(EPC map)で管理 • 許可されていなければ例外が発生 • 同様の機構:SMM(system management mode) • OS起動前のBIOSでのみ利用可能 • 制限されたメモリアクセス SGX(software guard extensions) 17 / 32
  • 18.
    • https://foreshadowattack.eu/ • IntelCPUのL1キャッシュの挙動 • SGXのenclaveなメモリがL1キャッシュにあり、そのマッピン グが破棄されたときに攻撃者がキャッシュ内容を解析できた • SMMやVMMの内容をL1キャッシュ経由で取得できる可能性 L1TF(L1 terminal fault) ; Foreshadow-(NG) Foreshadow-NG.pdf p.2 Figure 1 18 / 32
  • 19.
    • 範囲チェックを超えた領域のアクセス • (trained)正常パスでコードを繰り返し実行させて CPUに分岐しないと予測させる •(try)範囲外のxで実行 • (err)一時命令がsecretを超えた別のメモリを参照 • (cache)しかしuserを読んだキャッシュはクリアされない • (probe)後でuserの領域で速く読めた場所(x)を探索 Spectreの基本アイデア if (x < secret.size()) { y = probe[secret[x] * 4096]; } 19 / 32
  • 20.
    • 分岐系 • PHT(patternhistory table), BHB(branch history buffer) • 分岐命令ごとに「分岐した・しなかった」の履歴を保持 • Intelでは20回程度 • BTB(branch target buffer) • 分岐命令ごとに分岐先アドレスを予測 • RSB(return stack buffer) • call命令のリターンアドレス(関数の呼出元)を予測 • メモリ系 • STLF(store to load forwarding) • memory disambiguation ; Intel SDM 2-34 • storeの後のloadを予測して先読み • x1 = a[0]; b[0] = y; x2 = a[0]; さまざまな予測機構 20 / 32
  • 21.
    • A SystematicEvaluation of Transient Execution Attacks and Defenses, C.Canella, et.al., Nov. 2018 • https://arxiv.org/abs/1811.05441 • Spectre • アプリがアクセスできるデータに一時的命令が作用する • 一時的命令はアプリの通常フローで実行可能 • Meltdown • アプリがアクセスできないデータに一時的命令が作用する • 例外命令に続く一時的命令が例外命令のデータにアクセスで きる性質を利用する SpectreとMeltdownの網羅的論文 21 / 32
  • 22.
    • same-address-space /cross-address-space • 攻撃者と犠牲者のアドレス空間が同じか否か • in-place / out-of-place • 同じ分岐アドレスか異なる分岐アドレスか • 予測表を小さくするためにハッシュ化して保持 • 異なる分岐先でも同じエントリを参照することがある メモリレイアウトによるSpectreの分類 A Systematic Evaluation... p.4 Figure 3 22 / 32
  • 23.
    • ブラウザはJavaScriptを実行するVMを持っている • たくさんのユーザのプログラムを同一プロセスで動かす •Spectreで使える機能 • SharedArrayBuffer • 複数のワーカーでメモリを共有するための機能 • Performance.Now • 高性能タイマー • これらの機能が無効化・タイマーの精度をあえて下げた • Chrome(2018/8) • Site Isolation ; ドメインごとに別のプロセスで実行させる ブラウザへの影響 23 / 32
  • 24.
    • 例外 • GP; general protection • NM ; device-not-available ; FPUが無い • BR ; bound range exceeded exception ; メモリ保護拡張MPX • PF ; page fault • 許可タイプ • U/S ; user/supervisor • P ; present(そのページが存在する / swapされてない) • R/W ; • RSVD ; reserved • XD ; non executable • PK ; protection key 例外種別によるMeltdownの分類 24 / 32
  • 25.
    • p.3 Figure1 A Systematic Evaluation...による分類 25 / 32
  • 26.
    • KPTI(kernel pagetable isolation) + invpcid • カーネル空間(Ks)とユーザ空間(Us)のページテーブルを分離 • 従来:Ksは常にマップされていた • Usから直接アクセス不可なので大丈夫と思っていた • 一般ユーザ権限から任意のメモリを読める可能性 • コンテナ貸しサービスで危険 • PCID(process contexst identifier) • プロセス識別タグ • 特定のプロセスのTLBを無効化 • カーネル実行時以外はKsを切り離す • pros. 見えないので安全 • cons. User⇔Kernel時にPT切り換え. 場合によってTLB無効化 ソフトによる対策 26 / 32
  • 27.
    • 配列チェックのテクニック • 範囲を超えたindexは常に0になるのでSpectreが成功しない •対策が必要な部分を全てこのようにしないといけない array_index_nospec array_index_nospec(size_t index, size_t size) { // maskはsize <= indexなら0そうでなければ-1 mask = int64_t(size - index) >> 63; // 範囲内ならindex そうでなければ0 return index & mask; } 27 / 32
  • 28.
    • 間接分岐(call [eax])を使わないコードに変換 •予測がかからないので遅くなる(悲しいジレンマ) retpoline retpoline(addr): call .L ; *** .T: ; callの次の命令が投機実行されても無限ループさせる pause lfence jmp .T .L: [stack] <- addr ret ; ***には戻らずaddrに戻る(=addrにジャンプする) 28 / 32
  • 29.
    • 関数テーブルを使うコード • 通常はjmpテーブルを生成 コンパイラサポート intf(int x, int y) { static int (*const p[])(int) = { f0, f1, f2, f3, f4 // 関数ポインタテーブル }; return p[x](y); } movsxd rax, x mov rdx,<pointer to table> jmp QWORD PTR [rdx+rax*8] ; p[x] ... 29 / 32
  • 30.
    • retpolineコードを生成する -mindirect-branch=thunk f: lea rdx,[rip+0x0] movsxdrax,edi mov edi,esi mov rax,QWORD PTR [rdx+rax*8] jmp __x86_indirect_thunk_rax __x86_indirect_thunk_rax: call c <__x86_indirect_thunk_rax+0xc> pause lfence jmp 5 <__x86_indirect_thunk_rax+0x5> mov QWORD PTR [rsp],rax ret 30 / 32
  • 31.
    • IBRS(Indirect BranchRestricted Speculation) • 低い権限のモードでの間接分岐予測結果を 高い権限のモードが使わないようにする • Linux 4.19からretpolineの代わりにenhanced IBRSを利用 • STIBP(Single Thread Indirect Branch Predictors) • 一つの物理コアのある論理コアが 別の論理コアでの間接分岐予測を使わないようにする • IBPB(Indirect Branch Predictor Barrier) • バリアに続く間接分岐予測の影響を バリアの前の実行が影響を受けないようにする • プロセスやVMの切り替え時にBTBをフラッシュさせる CPUの改善による対策 31 / 32
  • 32.
    • x86/x64最適化勉強会での発表 • 図解でわかるSpectreとMeltdown;@satoru_takeuchi •https://speakerdeck.com/sat/tu-jie-dewakaruspectretomeltdown • SpectreBustersあるいはLinuxにおけるSpectre対策;@mhiramat • https://www.slideshare.net/mhiramat/spectrebusterslinuxspectre • Software guidance for security advisories;Intel • https://software.intel.com/security-software-guidance/ • https://software.intel.com/security-software- guidance/insights/deep-dive-managed-runtime-speculative- execution-side-channel-mitigations • C++ Developer Guidance for Speculative Execution Side Channels;Microsoft • https://docs.microsoft.com/en-us/cpp/security/developer-guidance-speculative-execution 参考文献(スライド内以外) 32 / 32