ARM64のセキュリティ機能

# はじめに
こちらは　[NEC デジタルテクノロジー開発研究所 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/nec-dt-labs)　22日目の記事です。
　[17日目](https://qiita.com/sa_fujii/items/8040941b1e0b62a7bea5)の記事に引き続き2回目の登場となります。一回ポッキリのつもりでしたが、セキュリティ関連の投稿をすると、なんとCPEが申請できるとのことで、CISSPホルダーとしては２回目の投稿のモチベーションがものすごくわきました。ということで、２日目はARM64のセキュリティ関連のネタになります。なお、手元の実行環境は引き続き、動作環境は前回と同じ、RaspberryPi Model B(8GByte)です。


# もう一つの動機
　私は、実務では32bitまでしか経験がありません(ARMv7-A)。16進数でEで始まるのが多くないとARMのアセンブラな気がしないです（苦笑）。そんな私が、実は17日目の記事を書くに当たり、atomic処理の一つ目のアセンブラを見て、「何だこれ？見たことがない！」と気になってしまい、記事を書く前にかなり調べて、~~貴重な週末の時間を潰したのでした~~とても勉強になりました。
　その見たことがなかったアセンブラが以下の1500番地のモノです。

```asm:17日の記事ではカットした、atomic処理の先頭部分
0000000000001500 <__aarch64_ldadd8_acq_rel>:
    1500:       d503245f        bti     c
    1504:       f00000f0        adrp    x16, 20000 <_ZNSo3putEc@GLIBCXX_3.4>
    1508:       39436610        ldrb    w16, [x16, #217]
    150c:       34000070        cbz     w16, 1518 <__aarch64_ldadd8_acq_rel+0x18>
    1510:       f8e00020        ldaddal x0, x0, [x1]
    1514:       d65f03c0        ret
    #ここから先を一日目には出しました。
```
　うん？``bti c``、えー、"ブランチ　ターゲット　イ・・・・？"[^1] 


# BTIはセキュリティ機能
  ``bti c``は、調べたところARMv8.5(のextension)で追加されたセキュリティ機能の一つ[^2]で、Branch target identification(BTI)が正式名称です。これは、何かをものすごく簡単に言うと、

  **分岐した先がbtiじゃないとダメ**  

というものです。この機能により、悪意を持ったプログラムが、分岐先を何がしかの手段で勝手に書き換えても、「任意の場所には飛ばせません」ということになります。ARMの場合、BRやBLRが任意の場所に飛べる命令になりますので、そこが狙われることになりますが、BR/BLRで飛んだ先はBTIである必要があるのです。なお、BTIには、``bti c``(関数ジャンプのBLRに適用)、``bti j``(switch case文とか、jumpテーブルでのBRに適用)の二種類と、その２種類が同時２設定出来る``bti jc``という３種類あります。先程は、関数コールのようなものなので、``bti c``でした。
　エレガントだな〜と思ったのが、この命令をサポートしていないCPUからはNOP(何もしない命令)にみえるという、後方互換性バッチリなところです。

# 書き換えて不正な状態にしたら何が起こるかやってみた
　1日目のプログラムのatomicを有効にしたバージョンを例に、btiを別の命令、ここではNOPに書き換えて何が起こるか検証してみましょう。地味に、cliを駆使して書き換えていきます。
 ```shell
 xxd a.out a.dump
 emacs a.dump
 ```
 あ、emacs派だとバレますね。[^3]

 ```
000014e0: 34f0 7dd3 f7ff ff17 0000 0090 0040 1591  4.}..........@..
000014f0: 50fe ff97 1f20 03d5 1f20 03d5 1f20 03d5  P.... ... ... ..
00001500: 5f24 03d5 f000 00f0 1066 4339 7000 0034  _$.......fC9p..4
00001510: 2000 e0f8 c003 5fd6 f003 00aa 20fc 5fc8   ....._..... ._.
00001520: 1100 108b 31fc 0fc8 afff ff35 c003 5fd6  ....1......5.._.
 ```
1500番地のところを、NOP命令に書き換えてあげます。objdumpの結果の周囲を見渡せば、NOPはあちこちにありまして、``d503201f``です。エンディアンの関係でちょっと順番が違いますが、そこは我慢。（なお、右側の文字表示部分は変更しません）
```
000014e0: 34f0 7dd3 f7ff ff17 0000 0090 0040 1591  4.}..........@..
000014f0: 50fe ff97 1f20 03d5 1f20 03d5 1f20 03d5  P.... ... ... ..
00001500: 1f20 03d5 f000 00f0 1066 4339 7000 0034  _$.......fC9p..4
00001510: 2000 e0f8 c003 5fd6 f003 00aa 20fc 5fc8   ....._..... ._.
00001520: 1100 108b 31fc 0fc8 afff ff35 c003 5fd6  ....1......5.._.
 ```
戻します。

 ```shell
 xxd -r a.dump a.out
 ```
objdumpでみてみます。

```asm
0000000000001500 <__aarch64_ldadd8_acq_rel>:
    1500:       d503201f        nop
    1504:       f00000f0        adrp    x16, 20000 <_ZNSo3putEc@GLIBCXX_3.4>
    1508:       39436610        ldrb    w16, [x16, #217]
    150c:       34000070        cbz     w16, 1518 <__aarch64_ldadd8_acq_rel+0x18>
    1510:       f8e00020        ldaddal x0, x0, [x1]
    1514:       d65f03c0        ret

```
ちゃんと、NOPに変わっているではありませんか。

それでは、実行してみましょう。おそらく例外で落ちるのだと推測していました。実行する前までは。

```shell
user@raspberrypi:~ $ ./a.out
100000000
```
あれ？動いていますけど。  



# そういえば、BTIはextensionでした
　（この間ちょっとした時間が経過しております）カーネルをビルドするときのCONFIGは、``CONFIG_ARM64_BTI=y``とソフトウエアのビルドの観点ではサポートしているようではありますが、ネットの情報や、カーネルソースを読むと、ハードウエアがサポートしている場合、ログで
> CPU features: detected: Branch Target Identification

というのが出るようです。手元の環境を確かめてみますと、

```shell
user@raspberrypi:~ $ dmesg | grep Branch
user@raspberrypi:~ $ 
```
ログにBranchという言葉さえありません。 **なんと未サポートでした！** 残念。後方互換性まで用意してあるextensionですから、１００％サポートしているわけではありません・・・とはわかっていましたが、最初に調べろってはなしですね。じゃぁと思って、AWS環境で検証しようとも思ったのですが、AWS Graviton4を搭載したR8gでようやくサポート。執筆時点ではまだプレビューです。実行結果は断念することにしました。


# さいごに
　不正な場合の実行結果をお見せできなかったのは非常に残念ですが、いかがでしょうか。コンパイラが用意したBTIという着地点以外には、ジャンプできないよ・・・という機能は、悪意を持ったアプリケーションが分岐先を都合の良いように書き換える攻撃の手段をだいぶ奪うのではないかと思います。今回はatomicのライブラリ実装のところでみつけたのが私にとっての契機でしたが、このようなライブラリはもちろんのこと、コンパイラ、カーネルなどいたるところに影響がある機能がちゃんと実装されるところにも凄さを感じました。
　本記事では紹介しませんでしたが、対で紹介されることも多い、特に戻りアドレスの改ざんを防ぐPAC[^2]も合わせることでかなり強固になると思います。ご興味がありましたら、調べてみてください。



[^1]:大昔の記憶の、Branch target address cache(BTAC)に引きずられて適当に思ったのですが、Branch targetまであってました。  

[^2]:もう一つ、並んで紹介されるのが、PAC(Pointer Authnetication Code)というのがありますが、本記事では説明しません。
[^3]:M-x hexl-find-file　でももちろんできます。ベタな方法は、記載しておくとemacsがない環境でも役立つかと。