Arm Cortex-M 向けTrustZoneの話
Qiitaの「セキュリティAdvent Calendar 2021」の13日目の記事で、Cortex-M向けTrustZoneについて書きました。
はじめに
この記事は、Qiitaの「セキュリティAdvent Calendar 2021」の 8 13日目の記事であり、ArmのCortx-M向けのTrustZoneについてざっくり以下の事柄について書きました。
- Arm Cortex-MのCPUの権限モデル
- メモリ保護
- TrustZoneとは
- Arm Cortex-M向けのTrustZoneの仕組み
想的読者層としては、「IntelのRing Levelはわかるよ」「TrustZoneとかSGXとか聞いたことあるなぁ」ぐらいの TEEに興味が出てきたCPUの権限モデルがわかってるぐらいの人です。 いくつかの内容に絞って書いてますが、ざっくりしているので、細かいところは参考資料をあたると良いです。 ここでは、概要を掴んでもらうことで理解の助けになればと思っています。
Arm Cortex-Mとは
Arm Cortex-MはArm社によるCPUのIPのファミリの1つであり、マイクロコントローラ向けのものです。
スマートフォンに使われるようなCortex-Aシリーズに比べて
性能は低く、MMU(Memory Management Unit)を搭載しないなどの違いがあります。
アーキテクチャに着目すると、Cortex-MシリーズのアーキテクチャであるArmv8-MとCortex-AシリーズのアーキテクチャであるArmv8-Aでは、権限レベルに大きな違いがあります。
Armv8-Aでは、特権レベルとしてEL0〜EL3までの4段階があるのに対して、
Armv8-Mでは、Privileged(特権) とUnrivileged(非特権) の2種類しかありません。
特権の数は少ないですが、権限レベル以外の軸としてThead ModeとHandler Modeと呼ばれる2つのモードがあります。
Thread Modeは通常の動作のためのモードで、Handler Modeは割込み処理を行うモードです。
割込み処理は特権でしか行わないため、とりうる状態としては以下の図に示す3つになります。
また、メモリに関しても大きく異なるところがあります。
先にも述べたように、Cortex-MシリーズはMMUを搭載しませんが、
メモリ保護を行うMPU(Memory Protection Unit)というものが存在します。
MPUはMMUから仮想メモリ機能を取り除いたようなもので、権限とRWXに合わせたアクセス制限が可能です。
TrustZoneとは
TrustZoneはArmによるTEE(Trusted Execution Environment)を実現するCPUの機能です。
TEEは、従来のCPUの実行空間の他に信頼される実行空間を生成するものであり、
TrustZone以外には、Intel SGX、RISC-V Keystoneなどが挙げられます。
それぞれの違いについては、3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)がわかりやすいです。
TrustZoneでは、以下の2つの実行空間を生成します。
- Secure World
- Non-Secure World (Normal Worldと呼ぶ場合もある)
Non-Secure Worldは従来の実行空間であり、Secure WorldがTEEによって生成される
信頼される実行空間(Trusted Environment)となります。
また、基本的にNon-Secure Worldで動作するソフトウェアは、Secure Worldの資産にはアクセスできないようになっています。
CPUから見ると、ワールドはCPU状態の一種であり、Secure Stateというものでどちらのワールド中であるかを表現します。
従ってCortex-MなCPUでは、先程の画像を拡張して以下の図のようなCPUの状態を取ります。
Arm Cortex-M向けTrustZoneの仕組み
TrustZoneには2つの実装があります。
1つが、Arm Cortex-A向けのTrustZoneであり、もう1つがArm Cortex-M向けTrustZoneで後者が本記事で述べるものになります。
ワールドの遷移命令
先にも述べたように、Cortex-AとCortex-Mシリーズでは性能に大きな差があります。
そのため、TrustZoneの実装もそれぞれ大きく異なり、
特にEL3で動作するSecure Monitorと呼ばれるソフトウェアの有無が大きく異なる点になります。
Cortex-A向けTrustZoneでは、Secure Monitorと呼ばれるソフトウェアが各ワールドを管理し、ワールドを遷移する(切り替える)際には、これを経由する必要があります。
一方でCortex-M向けTrustZoneには、Secure Monitorのような一度経由するものはなく、3つの特別な命令を用いてワールドを遷移します。
この命令は以下に示す3つです。
- SG
- BXNS
- BLXNS
SG命令は、Non-Secure WorldからSecure Worldに遷移するための命令です。
反対に、BXNS/BLXNS命令はSecure WorldからNon-Secure Worldに遷移するための命令です。
これらを図に示すと以下のようになります。
SG命令
Non-Secure WorldからSecuer Worldに遷移する際には、SG命令を実行する必要がありますが、
Non-Secure World中のどのタイミングでも実行すれば良いというわけではありません。
そのようなことを許容すると、好き勝手にSecure Worldへ遷移することが可能になってしまうためです。
そのため、SG命令の実行には条件があります。
それは、NSC(Non-Secure Callable)と呼ばれるメモリ領域でのみ有効だということです。
NSCに関しては、後で述べますが、NSC領域という限られたメモリ領域上のSG命令だけを許可することで、
Secure Wolrdへの遷移が可能なポイントを制限しています。
BXNS・BLXNS命令
BXNS・BLXNS命令は、SGとは逆で、Secure WorldからNon-Secure Worldへ遷移するための命令です。
BXNS・BLXNS命令の違いは、リンク付き分岐を行うかどうかであり、BXNS命令はリンクなし分岐、BLXNS命令はリンク付き分岐を行います。
リンク付き分岐というのは、リンクレジスタ(LR/R14)にリターンアドレスを格納する分岐のことであり、
リンク付き分岐の場合は、BX LR
という命令を行うことで、呼び出しもとに返ることができます。
つまり、BLXNS命令は、Non-Secure Worldに遷移した後、Secure Worldに帰ってくる場合に利用する命令になります。
また、BLXNS命令によってNon-Secure Worldに遷移し、その後Secure Worldに帰還する際には、SG命令は必要ありません。
この場合は、Secure Worldのどこに返るかが確定しているため、NSC領域でSecure Worldへの遷移の制限を行う必要がないからです。
(LRを書き換えれば任意のSecure Worldの箇所に返ることが可能だと思われるかもしれませんが、BLXNS命令を利用した場合にLRへ格納される値はアドレスではないFNC_RETURN
と呼ばれる値で、
帰り先のアドレスはSecure World側に保存されています。)
メモリの分離
上記では、TrustZoneの特に命令について述べましたが、ここからはその命令が格納されているメモリについて述べます。
Cortex-M向けTrustZoneでは、それぞれのワールド用にメモリを割り当てることで、各Worldがアクセスするメモリ領域を分離しています。
このメモリ分離を行なっているのが、SAU(Secure Attribute Unit)とIDAU(Implementation Defined Attribution Unit)です。
両者の違いについてここではあまり言及しませんが、SAUはソフトウェアによって実行時に述べ換え可能で、IDAUはそうではなく実行時には書き換えできません。
ここでは、簡単のためSAUに限定して述べます。
SAUはメモリ領域に対して以下の属性を付与します。
- Non-Secure
- Secure
- Non-Secure Callable
それぞれの名の通り、Non-SecureはNon-Secure Worldのメモリ領域であり、SecureはSecure World用のメモリ領域です。
Non-Secure Callableは、Secure Worldに属しながらもNon-Secure World側からもアクセス可能な領域です。
このNon-Secure Callable領域は、先程のSG命令が実行される領域であり、Non-Secure Callable領域でSG命令を実行することで
CPUのSecure StateがSecureに変化し、その後分岐命令によってSecure属性を付与されているメモリ上の命令を実行することが可能になります。
ここまでの話を統合すると、Non-Secure WorldからSecure Worldへの遷移とSecure WorldからNon-Secure Worldへの帰還する遷移は以下の図のようになります。
終わりに
本記事では、Cortex-M向けTrustZoneについて書きました。
この記事で、Cortex-M向けTrustZoneに対する理解の助けができれば良いなと思います。
一方で、この記事ではざっくりもざっくり、非常に薄い情報しかなく、割込み発生時の動作や各ワールドでバンクわけされるレジスタ、FNC_RETURN
やEXC_RETURN
と呼ばれる特別な値の詳細など
に踏み込んではいません。
この辺りもCortex-Aに比べると日本語情報が少ないので文章に落とし込みたいとは考えているので、期待値低めの乞うご期待!ということでお願いします。
Share this post
Twitter
Facebook
Reddit
Pinterest
LINE