Spectre/Meltdown脆弱性が巷を賑わせているようです。
当初漠然とした情報が飛び交っていましたが、いろいろと詳細が出始めてきたようですが、改めて、「セキュアなCPUを作る」事と、「パフォーマンスの良いCPUを作る」事の間に乖離が大きいことを感じました。
下記に非常にわかりやすい記事を見つけて読んでみました。
http://milestone-of-se.nesuke.com/nw-advanced/nw-security/meltdown-spectre/
なるほど確かに立派にサイドチャネル攻撃が成立してますね。特にMeltdownの方はダイレクトにデータ読めてますね。恐ろしや。
バグの詳細や影響に関しては世の中に詳しい記事が多数あるので置いておいて、CPU設計の観点から考えてみたいと思います。
現在のOS上のコードは、アプリからOSのシステムコールを呼びながら実行されますので、1つのスレッドがユーザー空間とカーネル空間を往復しながら動きます。TSSやSMTによって同じコアで複数プロセスも動き得ます。したがってこれをパフォーマンス良く動かそうとすると、1つのCPUコアからアクセスされるキャッシュ上にさまざまなプロセスレベルのデータが混在して載ったまま、効率よくかつアクセス保護された状態で動くことが求められます。
一方で、キャッシュへのアクセスは、候補データのアクセスと、TLB/MMUなどへのアクセスは並行して進行しますので、現状アーキではデータ読み出し時点でそのデータにアクセス権があるかどうか知るすべが無く、ガードする手が無いわけです。
もちろん、アクセス権の確立を待って、データを利用する作りにすればよいわけですが、そんなことをすればCPUの性能が大幅に落ちるのが簡単に予想されます。「新CPUはセキュアになったけど、旧製品やライバル社より3倍遅くなりました!」では誰も買わないのは目に見えているので、根本対策は非常に難しいわけです。
現状の、「アクセス違反がわかったら、後からキャッシュを削除」という機構もそれ自体複雑怪奇な機構ですが、上記の事情からやむなく至った解なのだと思います。ただやはり根本的な対策では無く、サイドチャネル攻撃をやりにくくするジャミング的な対策だったわけで、今回のように思わぬ回避コードが出てきてしまったわけです。
もっと言うとサイドチャネル攻撃の根本的な原因は、リソースの共有にあります。ものすごく極端な例を挙げると、たとえばあるインターネットのショッピングサイトで、Web上で商品をカートに入れたり出したりを繰り返してその時間を計ったとします。もし他に誰もアクセスが無ければ非常に高速に画面は切り替わるでしょう。ここに他の誰かが何か商品を買うためにアクセスを開始すると同じサーバーの負荷が増えた分処理は遅くなるでしょう。
ほとんどバタフライ効果のような話になりますが、この遅れ具合は、何の商品を買ったかや、送り先の住所やクレジットカードの番号などのデータ内容などと相関を完全にゼロにすることは不可能です。相関がゼロで無い以上、多面的な方向からこういった相関のありそうな情報を集めまくって、統計的に他人の情報を推測できる可能性はゼロではありません。したがってリソースの共有を一切止めて、ユーザの数だけ個別に専用サーバーを置くなどしない限り、100%セキュアなサーバーを作るというのは出来ないわけです。
結局のところ、100%セキュアなサーバーはありえない前提の中で、「限りなく100%に近く、実用上は問題なレベルの安全性」をどう確保するか? という議論に落ち着くしかなく、今後もそういう方向が続かざるを得ないだろうと思います。
話をCPUに戻しますと、現状に対して取れる策は、パフォーマンスを犠牲にしてでもある程度根本的な対策を行うか、パフォーマンス劣化の少ないジャミング処置を追加していくかしかないと思います。
回路設計で取れそうな対策を思いつく範囲で考えてみます。
・ キャッシュ上のデータにアクセス権もつけておいて、不正データは固定値や乱数に置き換える
(ページテーブルについているアクセス権を全キャッシュラインにつけるのでbitが増えますね)
・ アクセス権の無い汚染されたデータに関わるアクセスをすべてロールバックする
(とても大変な回路になりそうです)
・ アクセス権の無いアクセスを見つけたらその場でキャッシュを全フラッシュする
(投機実行の不正アクセスは普通に起こる事象なのでパフォーマンスが大きく落ちます)
・コンテキストごとに別キャッシュを用意する
(リソース膨大になりますね&特権スイッチが重くなりますね)
・コンテキストごとにキーを変えて、ストア/ロードでデータを暗号化/複合化する
(キャッシュ上のbitは増やさずに、違うコンテキストのデータが化けるようにする。でも確実にステージ増えますね。OSの対応も必須だし、コンテキスト間通信も大変)
・厳密な時計を提供するのを止める
(解析の難易度を上げることができますが、正確なタイマの必要なアプリが困る)
・ランダムにキャッシュフラッシュやCPU停止を行い撹乱する
(ただの嫌がらせですね。クラッカーも困るけど、普通のユーザーも困る)
とかでしょうか?私の頭ではイマイチな案しか思いつけません。
あとはOSや重要なデータを扱う専用のアプリ内での処理など、ソフトとあわせての検討で
・ そもそもこの方法でアクセスできるところに重要なデータを置かない
(kernel page-table isolationなどですね)
・ 重要なデータがどのアドレスに存在するか推論しにくくする
(配置をランダムにするとか、時々移動するとか、ASLRの類ですね)
・各種OSのスイッチなどのタイミングやランダムな時間でキャッシュをクリアする
(全方位的ただの嫌がらせ、パート2)
などの対症療法でしょうか?
いずれにせよ、本当に大変そうです。
そうなってくると、最終的にはデータセンターのようなセキュア向けのCPUと、とにかく演算量が欲しいHPC向けとで、CPUが分化する可能性もあるのかもしれません。
今のGPGPUのような、完全な別デバイスに性能の欲しい計算だけをオフロードするのも有効な解に思います。
短期的には性能意落ちるパッチでの対処になると思いますので普通に不便になりそうですが、CPUの進化という意味では、今後どのような対策が出てくるのか、興味深いところです。
コメント