オルタナティブ・ブログ > Mostly Harmless >

IT技術についてのトレンドや、ベンダーの戦略についての考察などを書いていきます。

CPU脆弱性の仕組みを図解してみる

»

今年のお正月、お屠蘇気分を吹き飛ばした最初のニュースは、これでした。

Intelのプロセッサチップに根本的な設計上の欠陥が発覚、各OSにアップデートの必要性

この後Intelから「この脆弱性はIntelだけのものではなく、他のプロセッサにも存在する」と発表され、さらに混乱に拍車がかかりました。これは業界にとって相当に深刻な問題なのですが、今日はその話ではなく、仕組みについて図解してみたいと思います。先日ソリューション塾でこの話をしたときに作った図を使っています。

まずは基礎知識

この脆弱性には3種類あり、Spectre/Meltdownという名前が付けられていますが、このうち説明のしやすいMeltdownについて説明しますが、いくつかマイクロプロセッサについての基礎知識が必要です。まずはそれから説明します。

CPUの特権モード

現代のプロセッサには特権モードというのがあり、プロセスに優先度を付けています。OSやデバイスドライバなど、優先的に実行させたいプロセスに与えられるのが最高特権であるカーネルモード、それよりも優先度が落ちるのがユーザーモードです。カーネルモードがプロテクトしているメモリエリアには通常ユーザーモードのプロセスはアクセスできませんが、今回の脆弱性はそれを可能にしてしまうというものです。

パイプライン処理

現代のプロセッサでは命令の処理を同時並行して行うパイプライン処理が主流になっています。昔のプロセッサは、命令をひとつずつ読み込んで実行し、処理が終ると次の命令にとりかかる、というやり方をしていました。

180331-1.png各々の命令はプロセッサの中でさらに細分化されます。例えば、①命令を解読(デコード)する②レジスタを参照する③足し算をする、といった形です。そうすると、命令をデコードした後で他の処理に移行した場合、次の命令が来るまでデコードするための回路は遊んでしまうことになります。プロセッサは様々な回路の集合体ですが、ある時点でその一部しか稼働していないということです。

これは勿体ない、ということで、各命令を整理して細分化し、前の命令の処理が終らないうちに次の命令を始めるようになりました。ハードウェアをなるべく遊ばせない、ということですね。これがパイプライン処理です。最近では数十のステージに細分化されているそうです。

アウトオブオーダー実行

ところがここで問題が出てきます。命令によっては、前の命令で計算した結果を使うことがあります。そうすると、前の命令の実行が終るまで次の命令を始められません。そういった場合に、プログラム上の順序に関係なく、依存関係にない命令を先に実行してしまうことをアウトオブオーダー(順序を守らない)といい、パイプラインを効率よく実行させるために必要な仕組みです。

投機的実行

また、プログラムにはループや条件分岐が付きものですが、分岐するかどうかはその命令を終えて条件が確定しないと判断できません。

180331-2.pngそうすると、この場合も前の命令が終るまで次の命令を開始できないことになります。特に科学技術計算ではループを多用しますから、処理速度に大きな影響を与えます。そこで考え出されたのが投機的実行です。条件が確定する前にとにかく次の命令を実行してしまい、もし駄目だったらそれまでの結果は破棄して正しい命令にとりかかるということです。イチかバチか、ということで「投機的」なのですね。もちろん、失敗が続くと処理速度が遅くなってしまいますから、様々な手段を使って予測精度をあげる工夫がされています。分岐予測などもそのひとつです。

キャッシュ

パイプライン処理や半導体技術の進化によって、プロセッサ内部での処理は高速化していきますが、メインメモリであるDRAMへのアクセス速度は上がっていません。このため、メモリからのデータを待つためにプロセッサのパイプラインが止ってしまうことになります。そこで、メインメモリよりも高速なメモリを間に配置し、データアクセスを高速化しようとするのがキャッシュメモリです。プロセッサがメインメモリからデータを読み込むとき、ひとまとまり(数十~数百バイト)のデータがキャッシュに読み込まれます。データはまとまって置かれていることが多いため、プロセッサが次のデータを読もうとしたときにキャッシュにデータがある可能性が高いのです。キャッシュに目的のデータがあれば、メインメモリまで読みに行かずともそのデータを読み込むことができ、処理の高速化に繋がります。(キャッシュにもいろいろな種類がありますが、これはリードスルーキャッシュですね)

180331-3.png全てのメモリを高速化すれば良さそうなものですが、高速なメモリはコストがかかるのです。現代のプロセッサはキャッシュメモリをプロセッサ内部にもっており、パイプラインと同期して動作させることができます。ここで大事なのが、当面プロセッサが要求していないデータもキャッシュに読み込まれること、そのデータが使われなくても特に操作をしない限りデータはキャッシュに残ることです。(その後もデータの読み込みが続いてキャッシュが足りなくなれば、古いデータは上書きされていきます)

やっとMeltdownの説明

さて、やっとMeltdownの説明ができる準備が整いました。ある不正なプログラムが、不正な命令(本来ユーザープロセスからアクセス不可能なメモリエリアからのデータ読み出し)を発行したとしましょう。

180331-4.pngこの不正な命令自身は、プロセッサが命令を実行する過程で不正なメモリアクセスであることが認識され、命令の実行はキャンセルされます。しかし、不正な命令であることが認識されないステージでメモリアクセスが行われた場合、メモリからキャッシュへのデータ読み込みは実行されてしまいます。命令がキャンセルされてもキャッシュ上のデータは残ります。

ここで攻撃者が引き続きメモリをアクセスする命令を絶妙なタイミングで発行した場合、キャッシュに残った(本来アクセスしてはいけない)データを読み取ることが(理論的には)可能になります。

しかし、この脆弱性を悪用した実際の攻撃は現時点で確認されていません。これまで見てきたように、いくつかの命令を絶妙なタイミングで実行させなければならないなど、技術的難易度は相当高いと言われています。しかし、ハードウェアのアーキテクチャレベルで脆弱性が見つかったことは、業界に大きな衝撃を与えています。

Comment(1)