私たちは
、偉大な10月... ARM TrustZoneの
100周年に捧げる一連の記事を続けます。
今日は、セキュアワールド、ノーマルワールドとは何か、2つのOSがソフトウェアレベルでどのように相互作用するか(信頼(TEE)とゲスト)を理解します。 必要なものとSecure Monitorの仕組み、デバイスからの割り込みの処理方法について説明します。
準備ができたら-猫へようこそ。
前の記事で、ハードウェアの実装について説明しました。 世界のハードウェア部門、信頼できるメモリや周辺機器からゲストOSを防ぐ方法など、すべてがあります。 そこから一つの考えをバインディングとして考えましょう。
- セキュア/非セキュアはプロセッサモードです。 これは、SCR(セキュアコンフィギュレーションレジスタ)のNS(非セキュア)ビットで指定されます。 NS = 1の場合、非セキュアモードになります。NS= 0の場合、信頼できる、つまりセキュアモードになります。
ソフトウェア実装の観点から見ると、必要なのはそれだけです。 ハードウェアは抽象化の反対側にあり、NSのみを監視し、ソフトウェアはNS = 0および1で異なる方法で実行されるだけでなく、このビットを変更することもできます。
両方のモード(NS = 0およびNS = 1)で、プロセッサは完全に動作できるため、各モードで独自のOSを使用できます。
- NS = 0:トラステッドOSまたはトラステッドOS、またはトラステッド実行環境(TEE)。
- NS = 1:ゲストOS、またはリッチOS、またはノーマルワールドOS。
各OSには、独自の仮想メモリカード、独自のアプリケーション、割り込み、ドライバーなどがあります。
もちろん、ARMで常に2つのOSが実行されているわけではありません。 信頼できるコードは、本格的なOSではなく、ある種の小さなセキュリティモニターである場合があります。 または完全に不在の場合があります。 しかし、スマートフォンやタブレットでは、信頼できるOSが存在しないことはめったにありません。主にTEE(信頼できるOS)と通常のOS(Androidなど)があります。
額面どおり、TEE(Trusted Execution Environment)という名前を付けないでください。 TEEがトラステッドと呼ばれる場合、コードはその目標の達成につながるため、誰かがそのコードを信頼することを意味します。 たぶん、彼の目標は宇宙を破壊することだと思いますか? ソースコードは表示されません。
起動プロセス
プロセッサは常にセキュアモードで起動します。 セキュリティ拡張機能が無効になっている多くのARMv7Aプロセッサがあります。 そして、彼らは常にセキュアとして動作します。 たとえば、みんなのお気に入りのシタラ。
ただし、いずれにしても、プロセッサは常にセキュアモードで起動します。
ブートローダーはブートプロセスに最初に参加します。TrustZoneの場合、トラステッドブートアイデアの実装の1つが使用されます。これは、起動前にイメージの署名を検証するメカニズムです。 ここでの一般的なアルゴリズムは次のとおりです。
- SD、eMMC、NAND、QSPIなどの外部メディアからブートローダーイメージを読み取ります。
- 製品の生産段階でプロセッサにフラッシュされた公開鍵で署名を検証します。
- 署名が正しい場合、制御をブートローダーに転送します。
プロセッサ内の署名を検証する公開キーが1回フラッシュされ、その後、このキーの秘密部分によって署名されたプライマリブートローダーのみを起動できます。 大手メーカーによる悪用の分野もあります。
この記事で ARMロードの詳細を読んで
ください 。
次に、ブートローダーはトラステッドOS(TEE)の署名を検証し、TEEを実行します。 これにより、TrustZoneに必要なすべてが初期化され、セキュアモードが終了し、ゲストOS(Linuxなど)に制御が移ります。
TEEが使用されておらず、制御がブートローダーからLinuxに直接転送される場合、Linuxはセキュアモードで動作します。 ただし、これは安全なOSにはなりません。SecureWorldとNormal Worldの間に障壁がなければ、信頼できるOSはありません。
トラステッドブートがないと、ブートローダーを変更することでTEEセキュリティが置き換えられる可能性があることに注意してください。 バイナリ署名によって提供される認証チェーン全体が重要です。
この記事で理解したいこと
写真は、ダウンロードした2つのOSを示しています。 ゲストOSはTEE関数を呼び出すことができます。そのため、Secure Monitorを使用します。
この記事では、Secure Monitorの種類、使用方法、および動作について説明します。
CPUモード
ARMv7Aには、かなり多くの動作モードがあります。 図では、それらはレベルPL0、PL1、PL2といくつかのレベルのセキュア、およびいくつかのレベル-非セキュアに分けられています。
PL0は、OS上で通常のプログラムが実行される非特権モードです。 各プログラムは、MMUを介して構成された独自のメモリカードで起動されるため、そのような他のプログラムに入ることはできません。 しかし、OS自体はそのように構成されているため、彼女もOSにアクセスできません。 OSにアクセスするために、アプリケーションはシステムコール(Supervisor Call、SVCコマンド)を作成し、プロセッサはスーパーバイザーモードPL1にジャンプします。
すべてのメインOSコードは、PL1レベルでスーパーバイザー(SVC)モードで実行されます。 ここでは、OSカーネルにも独自のMMUテーブルがあり、カーネルはアプリケーションとは異なる方法でメモリを認識します。 ちなみに、カーネルはアプリケーションのメモリのすべてのページを見る必要はなく、安全性が低下します。
非表示のテキストドライバーが間違ったポインターに従って呼び出すことを想像してください-ドライバーはドライバーを書くので、何でも可能です。 カーネルがアプリケーションメモリ全体を認識できる場合、ドライバーは一部のアプリケーションを台無しにする可能性があります。 そうでない場合、それも悪いですが、それが牛乳に入り、単に例外を引き起こす可能性があります。
もう1つの重要なカーネルモードはIRQです。 割り込みがトリガーされるとそこに到達します。 IRQはPL1レベルにあるため、通常のLinuxデバイスドライバーはすべてカーネルレベルで動作します。 ペアのIRQ FIQモードはクイック割り込みです。 Linuxではまったく使用されていませんが、TrustZone実装で使用されていることがわかりました。これについては後で説明します。
Undef、Abortモードがまだあります-これらはプログラムの実行中の例外です。 OSアプリケーション(またはカーネルコード)が無効なコマンドを実行しようとすると、Undefが発生します。禁止されているメモリにアクセスすると、Abortが発生します。 これについては
以前の記事ですでに書いて
います 。 TrustZoneの実装では、AbortをゲストOSで処理するか(Linux)、信頼できるOSにリダイレクトするか(TEE)を選択できます。 後者の場合、たとえば、ゲストOSが信頼されたOS領域に侵入しようとする試みを記録できます。
放棄され忘れられたシステムモードが使用されることはほとんどありません。
上記のモードはすべて、セキュアモードと非セキュアモードの両方で使用できます。 たとえば、セキュアスーパーバイザーと非セキュアスーパーバイザーは別々のモードです。 それらには異なるMMUテーブル、異なるアクセス権(NSビットによる)、データは異なるキャッシュラインなどに保存されます。
2つのOSを起動できるのは、同じコアでセキュアモードと非セキュアモードが重複しているためです。特別なプロセッサモード
上の図には、さらに2つのモードがあります。
- 非セキュアハイパーバイザー(HYP)、PL2;
- セキュアモニター(SMC)、PL1。
HYPモードは、VMWareと同様に、ハードウェアの仮想化に使用されます。 PL2レベルです-ゲストOSカーネルよりもさらに重要であり、TEEのようにすべてを許可および拒否できます。 しかし、この記事では仮想化についてはまったく説明しません。2つの理由があります。1つ目は、ARMv7プロセッサーとそのサポートを備えたソフトウェアがほとんどないことです。 したがって、今のところ仮想化を脇に置いておいたほうがよいでしょう。
ただし、セキュアモニターモードは本当に必要です。セキュアモニターモードと非セキュアOCを切り替えるために作成されます。 すべての側面から見てみましょう。
安全なモニター
本格的なOSが2つあり、NSビットのみがグローバルに異なります。
- セキュアOS(TEE)、NS = 0;
- 非セキュアOS(ゲスト、Linuxなど)、NS = 1。
結局のところ、ゲストOSがNSビットを変更して、セキュリティで保護された特権を取得することはできないのは論理的ですか? 絶対に論理的です。 セキュアOSがこのように非セキュアモードに切り替えて、NSを1に変更することはあまり期待できませんが、これも事実です。
実際、モード間の切り替えは、1ビットを変更するよりも少し複雑であることが判明しました。
- モードを切り替えるには、コンテキストを保存/復元する必要もあります。 セキュアおよび非セキュアのほぼすべてのレジスタは共通であり、保存および復元する必要があります。
- さらに、通常の世界からセキュアな世界への呼び出しは、何らかの操作を行うために必要ですが、操作には通常、パラメーターと戻り値があります。 これも考慮に入れる必要があります。
これが目的であり、セキュアモニターモードを思いつきました。 彼らは、Secure Monitorコールの略である「SMC#0」コールを使用してそこに到達します。 さらに、セキュアコードは「SMC#0」を呼び出して非セキュアに切り替える必要があります。 また、Non-Secureのセキュアジャンプもあります。
非表示のテキスト#0は単なるアタビズムです。最初は、ARMのこのパラメーターを介して呼び出しコードを渡したいと考えていましたが、この考えを捨て、呼び出し番号としてR0を使用しました。
一般に、SMCコールはオペレーティングシステムシステムコール(SVC)に似ています。
- SVCシステムコールにより、OSアプリケーションが非特権モード(PL0)からOS関数(PL1)を呼び出すことができます。
- SMCモニターを呼び出すと、ゲストOSコード(非セキュアPL1)がTEE機能(セキュアPL1)を呼び出すことができます。
違いは、システムコールからの戻りはコール自体と同じではないが、セキュアと非セキュア間の移行はSMC#0を介して対称的であることです。
セキュアモニタモードの3つの機能により、セキュア/非セキュアコンテキストスイッチングを実行できます。
- セキュアメモリ領域に関連する独自のスタックがあります。 スタックは、セキュアモニタモードに入るとすぐにアクセスでき、発呼側のすべてのレジスタ(コンテキスト)をすぐに保存することができます。どのレジスタでもかまいません。
- Secure Monitorモードでは、NSビットを自由に変更できます。
- セキュアモニタモードでNSビットを変更すると、セキュアモードまたは非セキュアモードからレジスタと周辺機器を確認できます。 NSは実際に変化し、これはハードウェア全体の動作に影響します。 ただし、これらはすべて1つの順次サブルーチンのフレームワーク内にあります。 これにより、Secure Monitorはコンテキストの切り替えに必要なすべてを準備できます。
TEE呼び出しの例
たとえば、TEEに何らかの文書に署名してもらいたい。 たとえば、次のようにドキュメントに関するデータをプロセッサレジスタに配置します。
- R0-操作コード:メモリ内のドキュメントに署名します。
- R1-Normal Worldメモリ内のドキュメントの開始アドレス(SecureとNon-Secureのメモリの表現が異なることに注意してください);
- R2はドキュメントの長さです。
- R3-署名が入るバッファーの開始アドレス。 バッファが十分でない場合、これはTEEの問題ではないと考えています。
TEEを呼び出すためにSMC#0を呼び出します。 応答として、操作が成功したかどうかを理解するために、示されたバッファの署名とR0レジスタの結果コードをTEEから期待します。
つまり、ゲストOSとTEEの間には特定の交換プロトコルがあります。 ARMでは、一般的な場合、好きなように動作して、交換の概念を思いつくことができますが、
ARM SMC呼び出し規約で説明されている、広く受け入れられている交換メカニズムがあります。 コマンドコード、データ、戻り値などの送信に使用されるレジスタについて説明します。
Secure Monitorは何をしますか?
まず、TEE初期化コードは、セキュアモニターエントリポイントのアドレス(サブルーチンアドレス)を、MVBARレジスターが指すモニターモード例外ベクトルテーブルに書き込みます。
MVBARレジスタは、セキュアモードでのみ使用でき、セキュアモニターモードに切り替えるときにのみ使用される例外ベクトルの特別なテーブルを指します。
ARMには、SVC、IRQ、FIQなどへのエントリポイントを示す通常のベクターテーブルもあります。 このテーブルはデフォルトでアドレス0x00000000にありますが、アドレスはVBARレジスタで構成できます。
もちろん、2つのOSの操作のために、セキュアVBARと非セキュアVBARの2つのレジスタが用意されています。 どれが利用可能かはNSビットに依存します。
そのため、MVBARはSVC、IRQなどには使用されませんが、SMCおよびモニターモードに入るように構成できるいくつかの例外にのみ使用されます。 たとえば、AbortおよびFIQを構成してSecure Monitorにアクセスし、これらの例外をキャッチできます。
初期化されると、TEEはSecure Monitorのスタックヘッドのアドレスも設定します。海外で言うように、すべて設定されています。
OP-TEEソースコードでSecure Monitorの実装例を見ることができ
ます 。コードは本当に簡単です:
https :
//github.com/OP-TEE/optee_os/blob/master/core/arch/arm/sm/sm_a32.Sここで、ゲストOSからSMC#0コマンドが呼び出されたときに何が起こるかを見てみましょう。
上記のコードのリンクに表示される内容の非常に簡単な説明を次に示します。 そこでは、すべての操作が同じ順序で実行されるわけでもありません。 目標は、一般的な意味を伝えることでした。
実際、これがSecure Monitorが行うことのほとんどすべてです-制御をSecure OSに転送します。 セキュアOSが呼び出しを終了すると、SMC#0も呼び出します。 Secure MonitorはNS = 0によって、現在Secureであると理解し、Non-Secureに戻る必要があり、同じコマンドを実行しますが、その逆も同様です。
コードを理解したなら、ネタバレの下に別のヒントがあります:
非表示のテキストSecure Monitorは、発信者の登録によりコールを判別します。
ARM SMC呼び出し規約で説明されている2つのオプションがあります。
- 標準呼び出し-TEEでストリームを作成して処理する必要がある呼び出し。 たとえば、信頼できるアプリケーション関数の呼び出し、または一般的なTEE関数の起動には、待機、ロック、セマフォなどが必要になります。
- ファーストコール-上記のすべてを必要としないTEEファーストコール。 たとえば、TEEにいくつかのプロセッサコアを追加するように依頼します。
ファーストコールは割り込みのようなもので、確実に制御を十分に迅速に返します。 標準呼び出し-RPCのように、呼び出しTEEが最大限に機能し始めた後、さまざまな操作を実行し、コンテキストを切り替え、操作の結果を待ちます。
原則として、Secure MonitorはこのチェックをTEEのままにしてすぐに切り替えることができますが、そのような実装があります。 このコードを混同しないで、両方の呼び出しがSecure MonitorではなくSecure Supervisorモードで行われていることを確認することが重要です。
OP-TEEコードを見ると、Non-Secure Worldからのすべての呼び出しはSecureで処理され、Secure Monitorは何も処理しません。 OP-TEEでは、彼はゲートキーパーとして働いています。
更新:親愛なる
lorc、 ARM Trusted FirmwareではSecure Monitorの実装がモードを切り替えるだけでなく、電源管理などの多くのシステム機能も実行することを明確にします。 彼のコメントをご覧ください。
割り込みおよび例外処理
原則として、ゲストOSはあまり良くなく、それがゲストであることを知っています。 メモリの構成、割り込み、タスクの実行。 TEEによって課された何らかの制限に達するまで、すべてが正常に機能します。 飛んだ場合、前回の記事で書いたように、中止が発生します。
この場合、ゲストOSは多数のドライバーをロードし、割り込みとデバイスへの割り込みをゲストOSに割り当てます。 そして、なぜ、彼女に尋ねるのですか? TEEが一部のデバイスを排他モードで制御し、それらのデバイスからの割り込みを受信したい場合があります。 ここで、2つのOSが割り込みを共有する方法を理解します。
ARMプロセッサでは、メイン割り込みコントローラーは1つ(GICv2とします)であり、セキュアと非セキュア用の別個のコントローラーはありません。
割り込みが発生すると、GICv2はデフォルトでセキュアモードになります。 次に、割り込みが発生した場合、Secure VBARからのベクターがロードされます。
しかし、TEEとLinuxを並行して実行する場合、何らかの方法で割り込みを分割する必要があります。 すべての割り込みがTEE(セキュア)またはLinux(非セキュア)のみで発生するかどうかは関係ありません。
そのため、GICv2では、セキュリティ拡張機能をサポートする一環として、割り込みをグループ化するというアイデアを思いつきました(レジスタGICD_IGROUP):
- グループ0-これはセキュア割り込みであり、IRQまたはFIQを生成します。これは設定可能です。
- グループ1-非セキュア割り込み、IRQのみを生成します。
この実装を使用すると、TEEなしでLinuxを起動できます。デフォルトでSecureモードで実行され、Secure VBAR自体を構成します。すべての割り込みがそれになります(VBARについては前述しました)。 また、Linuxがゲストモードで実行されている場合、TEEはグループ1で不要な割り込みをすべて事前設定し、Linuxは非セキュアモードで起動します。 Linuxは自身に対してNon-Secure VBARを設定し、そのすべての割り込みがそれに行きます。
Idyllとソフトウェアの互換性 。LinuxのGICドライバーは、セキュアモードとゲストモードのどちらで動作するかを知らないはずです。
まあ、それはすべてがうまく理解できるように思われます。 セキュア割り込みが発生した場合、セキュアVBARからベクトルがロードされ、そうでない場合は非セキュアVBARがロードされます。
だからない! Secure Monitorを使用しているため、単にセキュアモードから非セキュアモードに切り替えることは不可能であることを覚えています。
したがって:
- 割り込みが非セキュアモードで発生し、それが非セキュアである場合、通常どおり非セキュアVBARによって実行されます。
- 割り込みがセキュアモードで発生し、それがセキュアである場合、通常どおりセキュアVBARを介して実行されます。
- ただし、非セキュアモードでセキュアな中断が発生した場合、最初にセキュアモードに切り替えるためにセキュアモニターが呼び出されます。
- Non-Secure-> Secureペアで何が起こっているかについては推測できます。
残留物の乾燥-非セキュアモードでセキュア割り込みが発生し、セキュアモニターを通過します。 前述のように、その動作のメカニズムでは、割り込みに送信されるかどうかを把握し、それに応じてすべてを処理する必要があります。 そして、すべてがOP-TEEコードにあります、見てください。
このテーマに関する非常に役立つ表はこちらです:
http :
//infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16352.htmlしかし、それだけではありません! 実際、これが機能するためには、他の何かを設定する必要があります。 既におなじみのSCRレジスタには、Secure Monitorに送信する割り込みと例外、およびVBARを介して処理する割り込みを構成するビットがあります。
画像-ARM Cortex-A5のSCR。 EA、FIQ、およびIRQビットは、それぞれルーティング、外部アボート、FIQ、およびIRQに影響します。
残念ながら、IRQグループ0とIRQグループ1はありません。すべてのIRQをSecure Monitorに送信するか、VBARを介してそのままにしておくことができます。 現状では、それは私たちに合わないでしょう。 したがって、ARMを使用するすべての開発者は次のスキームを使用します。
- GICは、すべてのセキュア割り込みに対してグループ0を構成します。
- グループ0は、IRQではなくFIQを生成するように構成されています。
- SCRレジスタでは、Secure MonitorでFIQルーティングが選択され、VBARに従ってIRQが選択されます。
ゲストOSはこれらすべての設定を変更できません。 その結果、セキュア割り込みは常にFIQを生成し、FIQは常に非セキュアモードからセキュアモニターに入ります。
そのため、ARMv7のことは複雑であり、時には混乱を招きます。
同様に(SCRレジスタを介して)、非セキュアモードからセキュアモニターへの外部アボートを構成およびキャッチできます。 これは便利かもしれません 外部アボートは、たとえば、非セキュアモードからセキュアペリフェラルにアクセスしようとしたときに発生する可能性があります。
おわりに
1つのレビュー記事ですべてのTrustZoneプログラミングを説明することはできませんでしたが、続きがあります。
今回は、Secure WorldとNormal Worldの分離に注目し、Secure Monitorの動作を検証し、信頼できる環境で割り込みをキャッチする方法を学びました。
次の記事では、TEEについて説明します。TEEの機能、実際にどれだけ独立したOSであるか、トラストレットが必要な理由、およびそのライフサイクルについてです。