
TEEドライバー(CVE-2021-44733)を悪用するための脆弱なカーネル環境
最近、LinuxカーネルTEEサブシステム(バージョン5.15.11までを含む)においてuse-after-freeの脆弱性が発見され、CVE-2021-44733 [1]が割り当てられました。
一見すると、いくつかの理由で悪用可能には見えませんでしたが、脆弱なコードパスをさらに分析し、粗い概念実証エクスプロイトを実装した結果、カーネル内の関数ポインタを上書きすることが可能でした。この記事では特権昇格のペイロードは提示されていませんが、OPTEEとエクスプロイトを実行するための環境全体がさらなるテストのために利用可能です。「環境のセットアップ」を参照してください。
TEE(Trusted Execution Environment)は、ARM CPUのTrustZoneなどのセキュアな環境で動作する信頼されたOSです。TEEドライバは、TEEと通信するために必要な詳細を処理します。ドライバのより重要な役割のいくつかは、Globalplatform TEE Client API仕様[3]に基づいたTEEへの汎用APIを提供することですが、LinuxとTEE間の共有メモリを管理することもあります。このサブシステムは、ARMアーキテクチャのカーネル設定で CONFIG_OPTEE を設定することで有効にできます。
セキュアワールドには、OP-TEE OS [4]と呼ばれる信頼されたOSが含まれています。このOSの上では、いわゆるTrusted Applications(TA)を実行することができ、隔離された環境でいくつかの操作を実行できます。図1を参照してください。
図1: TEEの概要 - Linaroのプレゼンテーション[5]より
ノーマルワールド(Linuxユーザースペース/カーネル)は、クライアントアプリケーション(CA)とTEEサブシステムが公開するAPIを使用して、これらのアプリケーションと対話できます。CAは特定のTAに向けてセッションを開き、TAが実装する関数を呼び出すことができます。TAとCA間の引数の受け渡しは、共有メモリを使用して行われます。 次に、関連するすべてのシステムコールを使用したCAとTA間の相互作用について説明します。
CAはドライバと通信するために /dev/tee[0-9] を開きます。従来のAPIの使用方法では、これはlibteecを使用して暗黙的に行われることに注意してください。
CAは IOCTL TEE_IOC_SHM_ALLOC を使用して共有メモリを登録できます。これにより共有メモリが割り当てられ、ユーザースペースがmmapの一部として使用できるファイル記述子が返されます。
次のステップは、IOCTL TEE_IOC_OPEN_SESSION を使用し、特定のTAのUUIDを指定してセッションを確立することです。このUUIDはTAのコンパイル時にハードコードされます。
TA内の特定の関数を呼び出すために、CAは関数の識別子と入力引数を指定してこれを呼び出します。これは TEE_IOC_INVOKE を使用して行われます。
CAがすべてのリクエストを完了したら、TEE_IOC_CLOSE_SESSION を使用してセッションを閉じることができます。
図2: CAとTA間のセッション - Linaroのプレゼンテーション[5]より
クライアントとTEE間の通信の多くはドライバにとって透過的です。ドライバの主な仕事は、コンテキストを管理し、クライアントからのリクエストを受け取り、それらをTEEに転送し、結果を返すことです[2]。
CVE-2021-44733は、syzkallerを使用したファジングによって発見されました。これに使用された説明ファイルを以下に示します。ioctl$TEE_SHM_REGISTER_FD は、Linaro(メンテナ)カーネルツリーの一部であり、アップストリームには含まれていないことに注意してください。'Setting up the environment'で提供された環境は、syzkallerのドキュメント[6]に従って適切に設定すれば、ファジングに使用できます。```
#include <uapi/linux/tee.h>
resource fd_tee0[fd] resource session_resource[int32]
openat$tee0(fd const[AT_FDCWD], dev ptr[in, string["/dev/tee0"]], flags flags[open_flags], mode flags[open_mode]) fd_tee0 ioctl$TEE_OPEN_SESSION(fd fd_tee0, cmd const[0x8010a402], arg ptr[inout, tee_ioctl_buf_data_session]) ioctl$TEE_INVOKE(fd fd_tee0, cmd const[0x8010a403], arg ptr[inout, tee_ioctl_buf_data_invoke]) ioctl$TEE_CANCEL(fd fd_tee0, cmd const[0x8008a404], arg ptr[in, tee_ioctl_buf_data_cancel]) ioctl$TEE_CLOSE_SESSION(fd fd_tee0, cmd const[0x8004a405], arg ptr[in, tee_ioctl_buf_data_close]) ioctl$TEE_VERSION(fd fd_tee0, cmd const[0x800ca400], arg ptr[out, tee_ioctl_buf_data_version]) ioctl$TEE_SHM_ALLOC(fd fd_tee0, cmd const[0xc010a401], arg ptr[inout, tee_ioctl_buf_data_shm_alloc]) ioctl$TEE_SHM_REGISTER(fd fd_tee0, cmd const[0xc018a409], arg ptr[inout, tee_ioctl_buf_data_shm_register]) ioctl$TEE_SHM_REGISTER_FD(fd fd_tee0, cmd const[0xc018a408], arg ptr[inout, tee_ioctl_buf_data_shm_register_fd]) ioctl$TEE_SUPPL_RECV(fd fd_tee0, cmd const[0x8010a406], arg ptr[inout, tee_ioctl_buf_suppl_recv]) ioctl$TEE_SUPPL_SEND(fd fd_tee0, cmd const[0x8010a407], arg ptr[inout, tee_ioctl_buf_suppl_send])
#=======================================================
define TEE_IOCTL_UUID_LEN 16
tee_ioctl_param_struct { attr flags[TEE_IOCTL_PARAM_ATTR_TYPE, int64] a int64 b int64 c int64 }
TEE_IOCTL_PARAM_ATTR_TYPE = 0, 1, 2, 3, 5, 6, 7 TEE_LOGIN = 0, 1, 2, 4, 5, 6
#=======================================================
tee_ioctl_buf_data_session { buf_ptr ptr64[inout, tee_ioctl_open_session_struct] buf_len len[buf_ptr, int64] }
tee_ioctl_open_session_struct { uuid array[int8, TEE_IOCTL_UUID_LEN] (in) clnt_uuid array[int8, TEE_IOCTL_UUID_LEN] (in) clnt_login flags[TEE_LOGIN, int32] (in) cancel_id int32 (in) session session_resource (out) ret int32 (out) ret_origin int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }
#=======================================================
tee_ioctl_buf_data_invoke { buf_ptr ptr64[inout, tee_ioctl_invoke_struct] buf_len len[buf_ptr, int64] }
tee_ioctl_invoke_struct { func int32 (in) session session_resource (in) cancel_id int32 (in) ret int32 (out) ret_origin int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }
#=======================================================
tee_ioctl_buf_data_cancel { cancel_id int32 (in) session session_resource (in) }
#=======================================================
tee_ioctl_buf_data_close { session session_resource (in) }
#=======================================================
tee_ioctl_buf_data_version { impl_id int32 (out) impl_caps int32 (out) gen_caps int32 (out) }
#=======================================================
tee_ioctl_buf_data_shm_alloc { size int64 (inout) flags const[0, int32] (inout) id int32 (out) }
#=======================================================
tee_ioctl_buf_data_shm_register { addr int64 (in) length int64 (inout) flags const[0, int32] (inout) id int32 (out) }
#=======================================================
tee_ioctl_buf_data_shm_register_fd { fd int64 (in) size int64 (out) flags const[0, int32] (in) id int32 (out) } [align[8]]
#=======================================================
tee_ioctl_buf_suppl_recv { func int32 (in) num_params len[params, int32] (inout) params array[tee_ioctl_param_struct] (inout) }
#=======================================================
tee_ioctl_buf_suppl_send { ret int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }
ファジング中、興味を引いたクラッシュは、ミューテックスが保持されている間の task_struct オブジェクトの use-after-free に関連していました:```
==================================================================
BUG: KASAN: use-after-free in __mutex_lock.constprop.0+0x118c/0x11c4
Read of size 4 at addr 863b0714 by task optee_example_r/244
CPU: 0 PID: 244 Comm: optee_example_r Tainted: G D 5.14.0 #151
Hardware name: Generic DT based system
[<8012b204>] (unwind_backtrace) from [<8011f460>] (show_stack+0x20/0x24)
[<8011f460>] (show_stack) from [<81cf0108>] (dump_stack_lvl+0x5c/0x68)
[<81cf0108>] (dump_stack_lvl) from [<80650f04>] (print_address_description.constprop.0+0x38/0x304)
[<80650f04>] (print_address_description.constprop.0) from [<80651548>] (kasan_report+0x1c0/0x1dc)
[<80651548>] (kasan_report) from [<81d0a9b4>] (__mutex_lock.constprop.0+0x118c/0x11c4)
[<81d0a9b4>] (__mutex_lock.constprop.0) from [<81d0ada4>] (mutex_lock+0x128/0x13c)
[<81d0ada4>] (mutex_lock) from [<817424b0>] (tee_shm_release+0x4b0/0x6cc)
[<817424b0>] (tee_shm_release) from [<81303674>] (dma_buf_release+0x1b8/0x2f0)
[<81303674>] (dma_buf_release) from [<806d5ac0>] (__dentry_kill+0x4c4/0x678)
[<806d5ac0>] (__dentry_kill) from [<806d8a68>] (dput+0x630/0xba4)
[<806d8a68>] (dput) from [<8067d890>] (__fput+0x3b4/0x900)
[<8067d890>] (__fput) from [<801dd1d8>] (task_work_run+0x15c/0x230)
[<801dd1d8>] (task_work_run) from [<80172b70>] (do_exit+0x103c/0x3770)
[<80172b70>] (do_exit) from [<80179aec>] (do_group_exit+0x134/0x3ac)
[<80179aec>] (do_group_exit) from [<801a7658>] (get_signal+0x7d8/0x2f28)
[<801a7658>] (get_signal) from [<8011dea4>] (do_work_pending+0x984/0x154c)
[<8011dea4>] (do_work_pending) from [<801000d0>] (slow_work_pending+0xc/0x20)
Exception stack(0x85743fb0 to 0x85743ff8)
3fa0: 00023108 00000080 00000000 00000000
3fc0: 66bca2d0 66bca2d0 66bca2d0 000000f0 66bca2d0 66bca340 00000000 6ec00b0c
3fe0: 66bc9cc8 66bc9cb8 00011655 66c80c20 000e0130 00023108
Allocated by task 242:
set_alloc_info+0x48/0x50
__kasan_slab_alloc+0x48/0x58
kmem_cache_alloc+0x14c/0x314
copy_process+0x2014/0x7b18
kernel_clone+0x244/0xfc8
sys_clone+0xc8/0xec
ret_fast_syscall+0x0/0x58
0x6ec00a10
Freed by task 67:
kasan_set_track+0x28/0x30
kasan_set_free_info+0x20/0x34
__kasan_slab_free+0xdc/0x108
kmem_cache_free+0x80/0x394
__put_task_struct+0x2b4/0x35c
delayed_put_task_struct+0x104/0x384
rcu_core+0x91c/0x2a68
__do_softirq+0x2fc/0xfb8
Last potentially related work creation:
kasan_record_aux_stack+0xb8/0xc0
call_rcu+0x9c/0xfd0
put_task_struct_rcu_user+0x9c/0xbc
finish_task_switch+0x534/0xa10
__schedule+0x934/0x1adc
schedule_idle+0x9c/0x120
do_idle+0x2ec/0x434
cpu_startup_entry+0x18/0x1c
start_kernel+0x3ec/0x430
The buggy address belongs to the object at 863b0700
which belongs to the cache task_struct of size 1664
The buggy address is located 20 bytes inside of
1664-byte region [863b0700, 863b0d80)
The buggy address belongs to the page:
page:f09c9565 refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x463b0
head:f09c9565 order:3 compound_mapcount:0 compound_pincount:0
flags: 0x10200(slab|head|zone=0)
raw: 00010200 00000000 00000122 82802e00 00000000 80120012 ffffffff 00000001
page dumped because: kasan: bad access detected
Memory state around the buggy address:
863b0600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
863b0680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>863b0700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
863b0780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
863b0800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
これは、あるスレッドが存在しないTA(Trusted Application)に対してセッションを開いている間に、別のスレッドが TEE_IOC_SHM_ALLOC からすべてのファイルディスクリプタを閉じることによって引き起こされました。Syzkaller はこれを再現することに成功し、リプロデューサコードを実験して TEE_IOC_OPEN_SESSION の呼び出しをわずかに遅延させることで、kmalloc-64 キャッシュに属するオブジェクトに対して別のUAFが発生しました。```
================================================================== BUG: KASAN: use-after-free in tee_shm_put+0x8c/0x98 Read of size 4 at addr 86467020 by task optee_example_h/216
CPU: 0 PID: 216 Comm: optee_example_h Not tainted 5.14.0 #21 Hardware name: Generic DT based system [<80122584>] (unwind_backtrace) from [<80117fd4>] (show_stack+0x10/0x14) [<80117fd4>] (show_stack) from [<819d57a0>] (dump_stack_lvl+0x40/0x4c) [<819d57a0>] (dump_stack_lvl) from [<819ced74>] (print_address_description.constprop.0+0x5c/0x2d8) [<819ced74>] (print_address_description.constprop.0) from [<805a12c4>] (kasan_report+0x1b4/0x1d0) [<805a12c4>] (kasan_report) from [<814cc6b0>] (tee_shm_put+0x8c/0x98) [<814cc6b0>] (tee_shm_put) from [<814c9b2c>] (tee_ioctl+0x1578/0x2e44) [<814c9b2c>] (tee_ioctl) from [<806038ec>] (sys_ioctl+0x918/0x1e70) [<806038ec>] (sys_ioctl) from [<80100060>] (ret_fast_syscall+0x0/0x58) Exception stack(0x86417fa8 to 0x86417ff0) 7fa0: 00000080 00000000 00000003 8010a402 200001c0 00000003 7fc0: 00000080 00000000 00423018 00000036 66c562d0 66c55e10 66c562d0 6ebebafc 7fe0: 66c55cb0 66c55ca0 004114bd 66cebd72
Allocated by task 216: tee_shm_alloc+0x15c/0x7e8 tee_ioctl+0x8d0/0x2e44 sys_ioctl+0x918/0x1e70 ret_fast_syscall+0x0/0x58 0x66c55ca0
Freed by task 215: kasan_set_free_info+0x20/0x34 __kasan_slab_free+0xdc/0x108 kfree+0x98/0x294 tee_shm_release+0x1dc/0x610 dma_buf_release+0x180/0x2a0 __dentry_kill+0x488/0x6ac __fput+0x2f0/0x7b4 task_work_run+0x178/0x230 do_work_pending+0xaf8/0x10a8 slow_work_pending+0xc/0x20 0x66d5bd16
The buggy address belongs to the object at 86467000 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 32 bytes inside of 64-byte region [86467000, 86467040) The buggy address belongs to the page: page:(ptrval) refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x46467 flags: 0x200(slab|zone=0) raw: 00000200 00000000 00000122 82401200 00000000 00200020 ffffffff 00000001 page dumped because: kasan: bad access detected
Memory state around the buggy address: 86466f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 86466f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
86467000: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ 86467080: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc 86467100: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ==================================================================
この脆弱性は、システム上で動作する既存のTAとのセッションが確立されていない状態で、TEEドライバをファジングすることによって発見されました。これは、syzkallerにおけるいわゆる疑似システムコールを用いて、あるTAへのセッションをセットアップし開始するためにさらに拡張することができます。
## 根本原因分析
結論として、`tee_shm:dmabuf`オブジェクトのライフタイム追跡における設計上の問題です。ドライバは、`tee_ioctl_shm_alloc()`の呼び出し後にユーザー空間が唯一の参照カウントを保持するように設計されています。
オブジェクトがドライバのIDRオブジェクトにまだ存在する場合、dmabufへの参照はまだ有効であり、その参照カウントを増加できると想定されています。これは部分的にしか正しくないことが判明しました。dmabufメモリは依然としてdmabufドライバによって所有されていますが、破棄の過程にある可能性があり、参照カウントを再び非ゼロにしてもそれを止めることはできません。
この問題を引き起こすシナリオは、マルチスレッドアプリケーションにおいて、一方のスレッドがdmabufファイルディスクリプタを閉じるのと同時に、もう一方のスレッドがその共有メモリを参照するIOCTLコマンド`TEE_IOC_OPEN_SESSION`または`TEE_IOC_INVOKE`を呼び出す場合です。
ユーザー空間がfdを閉じたときのdmabufの破棄をトレースすると、カーネル内で以下のコードが実行されます:
1. `fput()`
2. `fput_many()` >> ファイル参照カウントがゼロになる。競合ウィンドウが開く。
3. `[task_workがスケジュールされる]`
4. `__fput`
5. `dput`
6. `dma_buf_release`
7. `tee_shm_release`
8. `mutex_lock(teedev->mutex)`
9. `idr_remove(teedev->idr, shm->id)` >> これでshmオブジェクトはユーザー空間から参照できなくなる。競合ウィンドウが閉じる。
10. `mutex_unlock()`
これは、IDRテーブルとそのミューテックスロックが、dmabufおよび対応する`tee_shm`がまだ有効であることを保証できないことを意味します。`tee_shm_get_from_id()`を呼び出して`fput()`と競合するプロセスは、まもなく無効になるshmへの参照を取得する可能性があります。```
/**
* tee_shm_get_from_id() - Find shared memory object and increase reference
* count
* @ctx: Context owning the shared memory
* @id: Id of shared memory object
* @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
*/
struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
{
struct tee_device *teedev;
struct tee_shm *shm;
if (!ctx)
return ERR_PTR(-EINVAL);
teedev = ctx->teedev;
mutex_lock(&teedev->mutex);
shm = idr_find(&teedev->idr, id);
if (!shm || shm->ctx != ctx)
shm = ERR_PTR(-EINVAL);
else if (shm->flags & TEE_SHM_DMA_BUF)
get_dma_buf(shm->dmabuf);
mutex_unlock(&teedev->mutex);
return shm;
}
この脆弱性を悪用するには、オブジェクトが解放された後、UAFがトリガーされる前に再割り当てを行う必要がある。tee_shm_get_from_id() の呼び出し後、tee_shm_put()(syzkallerからの2つ目のUAFクラッシュが発生する関数)が呼び出され、これが dma_buf_put() の入力引数として使用される tee_shm:dmabuf オブジェクトを逆参照する。```
/**
`tee_shm`オブジェクトは、kmalloc-64キャッシュに属しているため、UAFの前に再割り当てされる可能性があります。再割り当てには以下が必要です:
1. 偽の`tee_shm`、`tee_shm:dmabuf`、`dma_buf:file`オブジェクト
2. `file->f_count = 1` を設定
3. `fasync`関数ポインタが任意のアドレスに設定された`file:file_operations`オブジェクトを作成
この関数は、`file->f_count`がゼロになったときに`dma_buf_put()`の呼び出し後、`__fput()`内で呼び出されます。
PAN(Privileged Access Never)はこれを軽減します。なぜなら、`file:f_ops`構造体に任意の関数ポインタを設定するためには、偽のオブジェクトがユーザースペースメモリ内で参照されなければならないからです。したがって、これを機能させるには`CONFIG_CPU_SW_DOMAIN_PAN`を無効にする必要があります(提供された環境では無効になっています)。この脆弱性において、PANがバイパス可能かどうか(例:ret2dirを使用)については、未解決の疑問がいくつか残っています。
また、解放されたshmオブジェクトの再割り当てを成功させるには、IOCTL呼び出し`TEE_IOC_OPEN_SESSION`または`TEE_IOC_INVOKE`が、ファイルディスクリプタを閉じるスレッドとkmalloc-64キャッシュを埋めるヒープスプレースレッドによってプリエンプトされる必要があります。これを機能させるには、カーネルが`CONFIG_PREEMPT`で構成されている必要があります。このPoCでは、Nicolas Fabrettiのブログ投稿[7]からのヒープスプレーが、ブロッキング`sendmsg()`に基づいて利用されました。
要約すると、悪用に関する問題は、freeとUAFの両方が同じシステムコール内で発生しなければならないことです。これに加えて、freeのトリガーはシステムコール内での競合が必要なため困難です。freeの後、実際のUAFまでの時間は短い時間枠であり、その間にヒープスプレーを実行して解放されたオブジェクトを再割り当てする必要があります。次の図は、エクスプロイトコードに関与するスレッドとその役割を示しています。
<p align="center">
<img src="https://raw.githubusercontent.com/pjlantz/pjlantz.github.io/master/docs/assets/Threads.png?raw=true" alt="関与するスレッド" width="50%" height="50%"/>
<br /><em>図3: エクスプロイトコードに関与するスレッド</em>
</p>
3種類のスレッドが連続して実行されています。システムコールを呼び出すスレッドをプリエンプトするために、そのスレッドは可能な限り低い優先度`SCHED_IDLE`で実行され、他のスレッドは優先度`SCHED_OTHER`に設定されています。ブロッキング`sendmsg()`を使用しているため、各スプレー試行は独自のスレッドで実行する必要があり、各コアが独自のkmallocキャッシュを保持するため、UAFをトリガーするのと同じCPUコアで実行する必要があります。また、ステップ1b)の共有メモリ割り当てからファイルディスクリプタを閉じるいくつかの解放スレッドもあります。このUAFトリガーと関数ポインタ上書きの完全なソースコードは[10]にあります。
## 新しい環境のセットアップ
脆弱なカーネルとOPTEEを含む環境を再現するには、次のリポジトリからクローンして、以下のコマンドでビルドできます:```
$ mkdir optee-qemu && cd optee-qemu
$ repo init -u https://github.com/pjlantz/optee-qemu.git
$ repo sync
$ cd build
$ make toolchains -j2
$ make run
ビルドが成功すると、3つのコンソールが起動します。1つはQEMU用で、QEMUコンソールで'c'を押すと起動します。2つ目のコンソールはセキュアワールドからの出力を表示し、最後のコンソールはLinuxを起動します。rootとしてログインします(パスワードなし)。
file_operations 構造体の fasync 関数ポインタが 0x22000000 に設定されるまで、エクスプロイトコードを実行します。```
until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done
これは特権実行禁止(PXN)によって`PC=0x22000000`での実行がブロックされるため停止します。ここからは、カーネルバージョンによって悪用戦略が異なりますが、カーネルROPを実行してスタックピボットを行ったり、vDSO領域を書き込み可能にしてペイロードを配置することが可能かもしれません。また、ret2dirやphysmapスプレーを用いてPANをバイパスできるかどうかを調査することは、今後の研究として興味深いかもしれません。PANは、`linux/.config`で`CONFIG_CPU_SW_DOMAIN_PAN=y`を設定することでカーネルで有効化できます。実際のハードウェアでは、ARMv8.1とAArch64でデフォルトで有効になっており、ARMv7とAArch32では、この設定[8]を使用してソフトウェアエミュレートされたPANを有効にすることが可能です。
**注意**: このエクスプロイトはあまり最適化されておらず、共有メモリオブジェクトを解放するのが早すぎるとドライバがハングすることがあります。その場合、PCは`tee_shm_get_from_id()`にあります。その場合は、QEMUコンソールで`system_reset`を実行して環境を再起動してください。
## 謝辞
根本原因分析にご協力いただいたAxis CommunicationsのLars Persson氏、そしてスムーズなコミュニケーションと迅速な問題解決[9]にご尽力いただいたLinaroのTEEサブシステムメンテナJens Wiklander氏に感謝します。
## 参考文献
[1] CVE-2021-44733 - https://nvd.nist.gov/vuln/detail/CVE-2021-44733
[2] TEE subsystem - https://www.kernel.org/doc/html/latest/staging/tee.html
[3] Globalplatform TEE API - https://globalplatform.org/specs-library/?filter-committee=tee
[4] OP-TEE OS - https://github.com/OP-TEE/optee_os
[5] BKK16-110: A Gentle Introduction to Trusted Execution and OP-TEE - https://connect.linaro.org/resources/bkk16/bkk16-110/
[6] Syzkaller - https://github.com/google/syzkaller
[7] Lexfo's security blog, by Nicolas Fabretti: CVE-2017-11176: A step-by-step Linux Kernel exploitation - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html
[8] Linux Kernel Security Subsystem: Exploit Methods/Userspace data usage - http://kernsec.org/wiki/index.php/Exploit_Methods/Userspace_data_usage
[9] [PATCH v2] tee: handle lookup of shm with reference count 0 - https://lore.kernel.org/lkml/[email protected]/T/
[10] 概念実証エクスプロイト - https://github.com/pjlantz/optee_examples/tree/master/exploit/host