$30 off During Our Annual Pro Sale. View Details »

図解でわかるSpectreとMeltdown

 図解でわかるSpectreとMeltdown

A brief explanation of spectre(variant 1) and Meltdown(variant 3)

Satoru Takeuchi
PRO

February 17, 2018
Tweet

More Decks by Satoru Takeuchi

Other Decks in Technology

Transcript

  1. 図解でわかる
    SpectreとMeltdown
    Feb. 17. 2018
    Satoru Takeuchi
    Twitter ID: satoru_takeuchi
    1

    View Slide

  2. はじめに
    ● 脆弱性の種類と、この資料の説明範囲
    ● キャッシュを使ったサイドチャネルアタックによる不正なデータ読み出し
    ● ソフトウェアではなくCPUの高速化機能にまつわる脆弱性
    ○ それぞれ脆弱性のある CPUのリストが公開されている
    2
    コードネーム 別名 しくみ 対策
    Spectre
    Variant 1: Bounds Check Bypass ✔
    Variant 2: Branch Target Injection
    Meltdown Variant 3: Rogue data cache load ✔ ✔

    View Slide

  3. もくじ
    ● 前提知識
    ● Variant 1のしくみ
    ● Variant 3のしくみ
    ● Variant 3の対策
    3

    View Slide

  4. 前提知識
    ● サイドチャネルアタック
    ● Flush+Reload攻撃
    ● アウトオブオーダー実行
    ● 分岐予測
    4

    View Slide

  5. サイドチャネルアタック
    ● 暗号化されたデータを当該データ処理時に発生する物理的な現象の観測によって
    読み出す攻撃方法
    ○ 処理時間の違い
    ○ 消費電力の違い
    ○ 電磁波の違い
    ● Variant 1-3によって読み出すのは暗号化されたデータではなく、コード上は論理的
    にアクセスできないデータ(例: 攻撃対象のメモリ、カーネルのメモリ)
    5

    View Slide

  6. Flush+Reload攻撃
    ● キャッシュメモリを使ったサイドチャネルアタック
    a. 初期化
    b. 抜き取り
    c. 復元
    6

    View Slide

  7. Flush+Reload攻撃: 初期化と抜き取り
    7
    #define PAGE_SIZE 4096
    char probe[256 * PAGE_SIZE]; # データ抜き取り用領域
    Char init_and_snoop(char *p) {
    Probe[]のキャッシュをフラッシュ (*1) # 初期化
    Dont_use = probe[(*p) * PAGE_SIZE]; # 抜き取り
    }
    *1) clflush命令などを使う

    View Slide

  8. Flush+Reload攻撃の実行例: 初期化
    ● (*p) == 2とすると…
    8
    #define PAGE_SIZE 4096
    char probe[256 * PAGE_SIZE];
    Char init_and_snoop(char *p) {
    probe[]のキャッシュをフラッシュ
    Dont_use = probe[(*p) * PAGE_SIZE];
    }

    View Slide

  9. Flush+Reload攻撃: 初期化直後のprobe[]
    9
    PAGE_SIZE


    0 * PAGE_SIZE
    1* PAGE_SIZE


    2* PAGE_SIZE
    255 * PAGE_SIZE
    … … On cache
    Not on cache

    全部 not on cache

    View Slide

  10. Flush+Reload攻撃の実行例: 抜き取り
    ● (*p) = 2とすると…
    10
    #define PAGE_SIZE 4096
    char probe[256 * PAGE_SIZE];
    Char init_and_snoop(char *p) {
    probe[]のキャッシュをフラッシュ
    Dont_use = probe[(*p) * PAGE_SIZE];
    }

    View Slide

  11. Flush+Reload攻撃: 抜き取り直後のprobe[]
    ● 仮定: (*p) == 2
    11
    PAGE_SIZE


    0 * PAGE_SIZE
    1* PAGE_SIZE


    2* PAGE_SIZE
    255 * PAGE_SIZE
    … … On cache
    Not on cache

    1つだけがon cache

    View Slide

  12. Flush+Reload攻撃: 復元コード
    ● “On cache”と”not on cache”のアクセスレイテンシの差を利用して(*a)の値を復元
    12
    int restore() {
    For (int i = 0; i < 256; i++) {
    Begin = 現在時刻測定(*1)
    Dont_use = probe[i * PAGE_SIZE];
    End = 現在時刻測定
    If (end - begin < 閾値) # trueならon cache, falseならnot on cache
    Return i;
    }
    Return -1; # 失敗
    }
    *1) rdtsc命令などを使う

    View Slide

  13. アクセスレイテンシの概念図
    13
    アクセスレイテンシ
    probe[]のインデックス
    0 (255 * PAGE_SIZE)
    (2 * PAGE_SIZE)
    閾値

    View Slide

  14. probe[]のサイズが256ではない理由
    ● あるデータのキャッシュへのロードが隣のデータも影響を与える
    ● CPUはキャッシュライン(サイズは64バイト, 128バイトなど)単位でメモリを読み出す
    ○ Probe[0]をキャッシュに入れると probe[1]もキャッシュに乗る
    ● キャッシュラインにシーケンシャルアクセスすると次のラインをプリフェッチすること
    がある
    ○ プリフェッチはページをまたがない
    ● probe[256 * PAGE_SIZE]のほうがデータを抜ける可能性が高い
    14

    View Slide

  15. アウトオブオーダー実行
    ● CPUの各命令の所要時間には大きな違いがある
    ○ 例: キャッシュに乗っていないデータのロードは非常に遅い (演算処理の数十倍)
    ● 連続する複数の処理間に依存性が無いことがある
    ● 依存関係が無い命令列の並列実行によって高速化可能
    ● 命令の実行順序が入れ替わりうるからOut-of-Order(あるいはOoO)実行と呼ぶ
    15

    View Slide

  16. OoO実行の流れ: 初期状態
    16
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    Not on cache
    値は3
    On cache
    CPU
    RAX: 0
    作業領域
    レジスタ
    *) 実装詳細が気になる人のための検索ワード : 「リオーダバッファ」「レジスタリネーミング」
    命令実行
    ユニット
    RBX: 1

    View Slide

  17. OoO実行の流れ: 命令読み出し
    17
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    Not on cache
    値は3
    On cache
    CPU
    RAX: 0
    作業領域
    レジスタ
    命令実行
    ユニット Mov rax $(100) Mov RBX $(200)
    RBX: 1

    View Slide

  18. OoO実行の流れ: 作業領域を割り当て
    18
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    Not on cache
    値は3
    On cache
    CPU
    RAX: 0
    作業領域
    レジスタ
    命令実行
    ユニット Mov rax $(100) Mov RBX $(200)
    RBX: 1

    View Slide

  19. OoO実行の流れ: 実行開始
    19
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    Not on cache
    値は3
    On cache
    CPU
    RAX: 0
    作業領域
    レジスタ
    命令実行
    ユニット Mov rax $(100) Mov RBX $(200)
    RBX: 1
    $(100)のデータほ
    しい
    $(200)のデータ
    ほしい

    View Slide

  20. OoO実行の流れ: 後の命令が先に完了
    20
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    Not on cache
    値は3
    On cache
    CPU
    RAX: 0
    作業領域
    レジスタ
    命令実行
    ユニット Mov rax $(100) Mov RBX $(200)
    RBX: 1
    3
    $(100)のデータま
    だ?
    $(200)のデータ
    来た

    View Slide

  21. OoO実行の流れ: 先の命令が後に完了
    21
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    on cache
    値は3
    On cache
    CPU
    2
    RAX: 0
    作業領域
    レジスタ
    命令実行
    ユニット Mov rax $(100)
    RBX: 1
    3
    $(100)のデータ
    来た

    View Slide

  22. OoO実行の流れ: 前から順番に反映(リタイア)
    22
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    on cache
    値は3
    On cache
    CPU
    2
    RAX: 2
    作業領域
    レジスタ
    命令実行
    ユニット
    RBX: 1
    3

    View Slide

  23. OoO実行の流れ: 前から順番に反映(リタイア)
    23
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    on cache
    値は3
    On cache
    CPU
    RAX: 2
    作業領域
    レジスタ
    命令実行
    ユニット
    RBX: 3
    3

    View Slide

  24. OoO実行の流れ: 完了
    24
    Mov RAX, ($100)
    Mov RBX, ($200)
    コード
    値は2
    on cache
    値は3
    On cache
    CPU
    RAX: 2
    作業領域
    レジスタ
    命令実行
    ユニット
    RBX: 3

    View Slide

  25. 分岐予測
    ● 分岐命令発生時、分岐先を予測して投機的に実行
    ○ 予測成功: 投機実行の結果をそのまま利用。高速
    ○ 予測失敗: 作業領域の結果を捨てて正しい分岐先からやり直し。低速
    ● 予測方法の例
    ○ 過去数回の分岐結果をもとに、最頻ルートを予想
    25

    View Slide

  26. 分岐予測の流れ: 初期状態
    26
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) … (a)
    ret = a[x]; … (b)
    Return ret;
    }
    コード
    ● 内部的には以下2つの流れを並列実行
    a. Lenをロード -> (x < len)の評価 -> 分岐先決定
    b. A[x]をロード -> retにa[x]をストア # 投機的実行
    CPUはx < lenをtrueと予測

    View Slide

  27. ● foo(x)を呼ぶと…
    分岐予測の流れ: 分岐予測成功の場合
    27
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) … (a)
    ret = a[x]; .. (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. len(not on cache)をロード中…
    b. A[x](on cache)をロード

    View Slide

  28. ● foo(x)を呼ぶと…
    分岐予測の流れ: 分岐予測成功の場合
    28
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) … (a)
    ret = a[x]; .. (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. len(not on cache)をロード中…
    b. A[x](on cache)をロード完了
    2. 流れaが完了。分岐予測成功
    a. Lenをロード完了 -> “x(=10) < len(=100)”がtrue
    b. retにa[x]をストア
    3. a, bの順にリタイア

    View Slide

  29. ● foo(x)を呼ぶと…
    分岐予測の流れ: 分岐予測成功の場合
    29
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) … (a)
    ret = a[x]; .. (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. len(not on cache)をロード中…
    b. A[x](on cache)をロード完了
    2. 流れaが完了。分岐予測成功
    a. Lenをロード完了 -> “x(=10) < len(=100)”がtrue
    b. retにa[x]をストア完了
    3. a, bの順にリタイアしてから先に進む

    View Slide

  30. 分岐予測が効く典型的なコード
    30
    For (i = 0; i < 1000; i++)
    Sum += i;
    ● 1000回の評価中999回はtrue
    ● i < 1000 == trueという予測はほぼ成功

    View Slide

  31. ● X = 1000とすると…
    分岐予測の流れ: 分岐予測失敗の場合
    31
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) ... (a)
    ret = a[x]; … (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. lenをロード中…
    b. A[x]をロード

    View Slide

  32. ● X = 1000とすると…
    分岐予測の流れ: 分岐予測失敗の場合
    32
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) ... (a)
    ret = a[x]; … (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. lenをロード中…
    b. A[x]をロード完了
    2. 流れaが完了。分岐予測失敗を検出
    a. Lenをロード -> “x(=1000) < len(=100)”がfalse
    b. retにa[x]をストア中…

    View Slide

  33. ● X = 1000とすると…
    分岐予測の流れ: 分岐予測失敗の場合
    33
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) ... (a)
    ret = a[x]; … (b)
    Return ret;
    }
    コード
    1. 流れbが先行
    a. lenをロード中…
    b. A[x]をロード完了
    2. 流れaが完了。分岐予測失敗を検出
    a. Lenをロード完了 -> “x(=1000) < len(=100)”がfalse
    b. retにa[x]をストア中…
    3. 流れbの実行を捨てて先に進む

    View Slide

  34. Variant 1のしくみ
    ● 脆弱性
    ● 攻撃方法
    34

    View Slide

  35. 問題のあるコード
    35
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) … (a)
    ret = probe[a[x] * PAGE_SIZE]; …(b)
    Return ret;
    }
    ● 以下2つの流れが並列実行
    a. Lenをロード -> (x < len)の評価 -> 分

    b. A[x]をロード -> probe[a[x] *
    PAGE_SIZE]をロード -> retに
    probe[...]をストア
    CPUはx < len == trueと予想

    View Slide

  36. ● foo(1000)を呼ぶと…
    分岐予測が外れた場合
    36
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) …(a)
    ret = probe[a[x] * PAGE_SIZE]; …(b)
    Return ret;
    }
    1. 流れbが先行
    a. Lenをロード中…
    b. A[x]をロード -> Probe[a[x] *
    PAGE_SIZE]をロード

    View Slide

  37. ● foo(1000)を呼ぶと…
    分岐予測が外れた場合
    37
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) …(a)
    ret = probe[a[x] * PAGE_SIZE]; …(b)
    Return ret;
    }
    1. 流れbが先行
    a. Lenをロード中…
    b. A[x]をロード -> Probe[a[x] * PAGE_SIZE]
    をロード
    2. 流れaにおいて分岐予測失敗を検出
    a. Lenをロード -> “x(=1000) < len(=100)”は
    false
    b. ret にprobe[...]をストア中…

    View Slide

  38. ● foo(1000)を呼ぶと…
    分岐予測が外れた場合
    38
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) …(a)
    ret = probe[a[x] * PAGE_SIZE]; …(b)
    Return ret;
    }
    1. 流れbが先行
    a. Lenをロード中…
    b. A[x]をロード -> Probe[a[x] * PAGE_SIZE]
    をロード
    2. 流れaにおいて分岐予測失敗を検出
    a. Lenをロード -> “x(=1000) < len(=100)”は
    false
    b. ret にprobe[...]をストア中…
    3. 流れaをリタイア。流れbの実行結果は捨てる

    View Slide

  39. ● foo(1000)を呼ぶと…
    分岐予測が外れた場合
    39
    Char a[100];
    Int len = 100;
    Void foo(x) {
    Int ret = -1;
    If (x < len) …(a)
    ret = probe[a[x] * PAGE_SIZE]; …(b)
    Return ret;
    }
    1. 流れbが先行
    a. Lenをロード中…
    b. A[x]をロード -> Probe[a[x] * PAGE_SIZE]
    をロード
    2. 流れaにおいて分岐予測失敗を検出
    a. Lenをロード -> “x(=1000) < len(=100)”は
    false
    b. ret にprobe[...]をストア中…
    3. 流れaをリタイア。流れbの実行結果は捨てる
    論理的に読んでないはずの
    A[1000]をprobe[]から復元可能

    View Slide

  40. Variant 1を利用したFlush+Reload攻撃
    ● できること
    a. Fooの引数変更によって、攻撃対象プロセスがアクセス可能な任意のメモリを読み出せる
    b. カーネル内で実行すればカーネル内のメモリも読み出せる
    ● 処理の流れ
    a. 初期化: Probe[]をキャッシュフラッシュ
    b. 教育: foo()を何度も呼び出して if文におけるCPUの分岐予測先をtrueにする
    c. 抜き取り: foo()を実行してif文の分岐予測を失敗させる -> 取りたいデータをprobe[]に抜く
    d. 復元
    40

    View Slide

  41. 現実的な攻撃方法
    ● 攻撃対象バイナリ上に元々存在する or 動的生成したコードをgadgetとして利用し
    て、ROPなどの他の方法と合わせて攻撃
    ● 現実世界で使うのは大変
    41

    View Slide

  42. Variant 3のしくみ
    ● 脆弱性
    ● 攻撃方法
    42

    View Slide

  43. linuxの仮想アドレス空間
    ● 各プロセスの仮想アドレス空間に全物理メモリをマップしている(*1)
    ○ 目的は実装の単純化と高速化
    ○ マップした領域をカーネル領域と呼ぶ
    43
    仮想アドレス空間
    物理アドレス空間
    物理メモリ
    プロセスAのメモリ
    カーネル領域
    *1) 実際のメモリマップはもっと複雑です

    View Slide

  44. アクセス権限
    ● 権限チェック: プロセスからカーネル領域にアクセスすると例外発生
    ● カーネル動作中(システムコール実行中、割込み処理中)のみアクセス可能
    44
    仮想アドレス空間
    物理アドレス空間
    プロセスAのメモリ
    OK
    NG

    View Slide

  45. プロセスとカーネルの仮想アドレス空間
    45
    OK
    NG
    OK
    OK
    syscall発行/割込・例外発生
    復帰
    プロセス
    カーネル

    View Slide

  46. 問題のあるコード
    46
    Char *p = SOME_KERNEL_ADDRESS;
    Char *probe[256 * PAGE_SIZE];
    Dont_use = probe[(*p) * PAGE_SIZE];
    ● 内部的には以下2つの流れを並列実行
    a. pへのアクセス権限チェック -> 無ければ流
    れbの実行結果を捨てる -> 例外発生
    b. (*p)をロード -> probe[(*p) * PAGE_SIZE]
    をロード

    View Slide

  47. 問題のあるコードの実行過程
    47
    Char *p = SOME_KERNEL_ADDRESS;
    Char *probe[256 * PAGE_SIZE];
    Dont_use = probe[(*p) * PAGE_SIZE];
    1. 流れbが先に完了
    a. pへのアクセス権限チェック中 …
    b. (*p)をロード-> probe[(*p) * PAGE_SIZE]
    をロード

    View Slide

  48. 問題のあるコードの実行過程
    48
    Char *p = SOME_KERNEL_ADDRESS;
    Char *probe[256 * PAGE_SIZE];
    Dont_use = probe[(*p) * PAGE_SIZE];
    1. 流れbが先に完了
    a. pへのアクセス権限チェック中 …
    b. (*p)をロード-> probe[(*p) * PAGE_SIZE]を
    ロード
    2. 流れaが後で終了
    a. 権限がないことがわかる -> 流れbの実行
    結果を捨てる -> 例外発生
    b. 流れaの完了待ち

    View Slide

  49. 問題のあるコードの実行過程
    49
    Char *p = SOME_KERNEL_ADDRESS;
    Char *probe[256 * PAGE_SIZE];
    Dont_use = probe[(*p) * PAGE_SIZE];
    1. 流れbが先に完了
    a. pへのアクセス権限チェック中 …
    b. (*p)をロード-> probe[(*p) * PAGE_SIZE]を
    ロード
    2. 流れaが後で終了
    a. 権限がないことがわかる -> 流れbの実行
    結果を捨てる -> 例外発生
    b. 流れaの完了待ち
    論理的に読んでいないはずの
    (*p)をprobe[]から復元可能

    View Slide

  50. Variant 3を利用したFlush+Reload攻撃の例
    ● メインルーチン
    a. SIGSEGVのシグナルハンドラを登録
    b. setjmp()。登録時は処理cへ。longjmp()による復帰時は処理 eへ
    c. 初期化: probe[]をnot on cacheへ
    d. 抜き取り。SIGSEGV発生
    e. 復元
    ● SIGSEGVハンドラ
    a. longjmp()でメインルーチンの処理 bへ
    50

    View Slide

  51. 現実的な攻撃方法
    ● 攻撃対象システムから一般ユーザ権限でプロセスを実行できればOK
    ● 任意の物理メモリを読み出せる
    ○ ファイルの中身
    ○ 他のユーザのメモリ
    ● 激ヤバ
    ● ユーザ貸し、コンテナ貸しのようなマルチテナントシステムでとくにヤバい
    51

    View Slide

  52. Variant 3への対策
    ● Kernel Page Table Isolation(KPTI)
    ● KPTIの有無によるカーネル処理の違い
    ● 性能劣化要因
    ● PCID
    52

    View Slide

  53. Kernel Page Table Isolation (KPTI)
    ● プロセスのアドレス空間にカーネルのメモリをマップしない
    ● Linux v4.15に取り込まれた & 各種distroのカーネルにもバックポートされた
    53
    仮想アドレス空間
    物理アドレス空間
    プロセスAのメモリ
    OK
    NG(マップされてないので触りようがない )

    View Slide

  54. プロセスとカーネルの仮想アドレス空間(KPTIあり)
    54
    カーネルの仮想アドレス空間
    プロセスの仮想アドレス空間
    カーネル領域
    syscall発行/割込発生
    復帰

    View Slide

  55. KPTIが無い場合
    ● ユーザ→カーネルへの遷移: syscall発行時, 割込/例外発生時
    ○ ページテーブルを切り替えない
    ○ TLBはフラッシュしない
    ● コンテキストスイッチ
    ○ ページテーブルを切り替える
    ○ TLBはフラッシュしない
    ● カーネル→ユーザへの遷移
    ○ ページテーブルを切り替えない
    ○ コンテキストスイッチ (これ以降CSと記載)したときはユーザ空間の TLBをフラッシュ
    55

    View Slide

  56. KPTIがある場合
    ● ユーザ→カーネルへの遷移: syscall発行時, 割込/例外発生時
    ○ ページテーブルを切り替えない => 切り替える
    ○ TLBはフラッシュしない => する
    ● コンテキストスイッチ
    ○ ページテーブルを切り替える
    ○ TLBはフラッシュしない => する
    ● カーネル→ユーザへの遷移
    ○ ページテーブルを切り替えない => 切り替える
    ○ CSしたときはユーザ空間の TLBをフラッシュ => CSしたときは全TLBをフラッシュ
    56

    View Slide

  57. 性能劣化要因
    ● ページテーブル切り替え増加 => sysが増加
    ● TLBフラッシュ増加(とくにコンテキストスイッチせずカーネル空間からユーザ空間に
    復帰した場合) => TLBミス増加 =>ユーザ空間で起きればuser増加、カーネル空
    間で起きればsys増加)
    ● その他諸々の追加処理の実行によるコスト => sys増加
    ● 上記一連の処理によるキャッシュ使用量増加 = キャッシュミス増加 => ユーザ空間
    で起きればuser増加、カーネル空間で起きればsys増加)
    57

    View Slide

  58. Process Context IDentifier(PCID)
    ● TLBエントリごとに存在するコンテキスト(通常はプロセス)識別用タグ
    ● 特定プロセス用のTLBエントリのみフラッシュ可能
    ○ コンテキストスイッチごとの TLB全フラッシュが不要に
    ● Sandy Bridge(2011年)から追加
    ○ Haswell(2013年)より前はINVPCID命令が無いため、あまり役に立たない
    58

    View Slide

  59. PCIDを使ったKPTIによる性能劣化の緩和
    ● ユーザ→カーネルへの遷移: syscall発行時, 割込/例外発生時
    ○ ページテーブルを切り替ない => 切り替える
    ○ TLBはフラッシュしない => する => しない
    ● コンテキストスイッチ
    ○ ページテーブルを切り替える
    ○ TLBはフラッシュしない => する => しない
    ● カーネル→ユーザへの遷移
    ○ ページテーブルを切り替えない => 切り替える
    ○ CSしたときはユーザ空間の TLBをフラッシュ => CSしたときは全TLBをフラッシュ => CSしたときは
    切り替え前のプロセス用 TLBエントリをフラッシュ
    59

    View Slide

  60. みなさんのマシンでの具体的な性能インパクト
    ● 個々のシステムにおける各処理の性能を要計測
    ● マイクロベンチを取って個々の要因によってどれだけ劣化しうるかの基礎データを
    持っていると分析しやすい
    ○ カーネルブートパラメタ ”pti”によって有効/無効を切り替えられる
    ○ マイクロベンチだけ採取して「最大ナントカ %性能劣化!以上!」と騒ぐのはナンセンス
    ● Intel曰く、新しい石ほど影響は小さい
    60

    View Slide

  61. おしまい
    61

    View Slide

  62. 参考文献1: 概要を掴むために
    ● Reading privileged memory with a side-channel
    ○ Google Project ZeroによるSpectreとMeltdownの概要。まずはこれを読むといい
    ○ https://googleprojectzero.blogspot.jp/2018/01/reading-privileged-memory-with-side.html
    ● Exploiting modern microarchitectures: Meltdown, Spectre, and other attacks
    ○ SpectreとMeltdownの概要説明。ハードの実装について若干書いてくれている
    ○ https://fosdem.org/2018/schedule/event/closing_keynote/attachments/slides/2597/export/event
    s/attachments/closing_keynote/slides/2597/FOSDEM_2018_Closing_Keynote.pdf
    ● KPTI/KAISER Meltdown Initial Performance Regressions, Brendan Gregg
    ○ Meltdownの性能影響についてのマイクロベンチ採取例
    ○ http://www.brendangregg.com/blog/2018-02-09/kpti-kaiser-meltdown-performance.html
    62

    View Slide

  63. 参考文献: 深く知るために
    ● Spectre Attacks: Exploiting Speculative Execution
    ○ Spectreの原著論文。完全理解したければこれを読みましょう
    ○ https://spectreattack.com/spectre.pdf
    ● Meltdown
    ○ Meltdownの原著論文。完全理解したければこれを
    ○ https://meltdownattack.com/meltdown.pdf
    ● linuxカーネルソースのDocumentation/x86/pti.txt
    ○ KPTIの目的、実装、性能インパクトについて書いている
    63

    View Slide