
Ambiente con kernel vulnerabile per lo sfruttamento del driver TEE (CVE-2021-44733)
Recentemente è stata scoperta una vulnerabilità use-after-free nel sottosistema TEE del kernel Linux, fino alla versione 5.15.11 inclusa, alla quale è stato assegnato l'ID CVE-2021-44733 [1].
A prima vista non sembrava sfruttabile per diverse ragioni; tuttavia, dopo un'ulteriore analisi del percorso di codice vulnerabile e implementando un proof-of-concept grezzo, è stato possibile sovrascrivere un puntatore a funzione nel kernel. In questo post non viene presentato alcun payload per l'escalation dei privilegi, ma l'intero ambiente per eseguire OPTEE e l'exploit è disponibile per ulteriori test, si veda 'Configurazione dell'ambiente'.
Un TEE (Trusted Execution Environment) è un sistema operativo fidato che gira in un ambiente sicuro, ad esempio TrustZone sulle CPU ARM. Un driver TEE gestisce i dettagli necessari per comunicare con il TEE. Alcuni dei compiti più importanti del driver sono fornire un'API generica verso il TEE basata sulla specifica Globalplatform TEE Client API [3], ma anche gestire la memoria condivisa tra Linux e il TEE. Questo sottosistema può essere abilitato configurando CONFIG_OPTEE nelle configurazioni del kernel per le architetture ARM.
Il mondo sicuro contiene il sistema operativo fidato denominato OP-TEE OS [4]. Sopra questo OS è possibile avere le cosiddette Trusted Applications (TA) in esecuzione, che possono svolgere alcune operazioni nell'ambiente isolato, si veda la Figura 1.
Figura 1: Panoramica del TEE - dalla presentazione di Linaro [5]
Il mondo normale (userspace/kernel Linux) può interagire con queste applicazioni usando client application (CA) e l'API esposta dal sottosistema TEE. Una CA può aprire una sessione verso una specifica TA e invocare funzioni implementate dalla TA. Il passaggio di qualsiasi argomento tra TA e CA avviene tramite memoria condivisa. L'interazione tra una CA e una TA utilizzando tutte le syscall rilevanti è descritta di seguito.
Una CA apre /dev/tee[0-9] per comunicare con il driver. Si noti che, per l'uso convenzionale di queste API, ciò avviene implicitamente tramite libteec.
La memoria condivisa può essere registrata dalla CA usando l'IOCTL TEE_IOC_SHM_ALLOC. Questo alloca memoria condivisa e restituisce un descrittore di file che lo spazio utente può usare come parte di mmap.
Il passo successivo è stabilire una sessione usando l'IOCTL TEE_IOC_OPEN_SESSION e specificando lo uuid per una specifica TA. Questo uuid è hardcoded durante la compilazione della TA.
Per invocare una qualsiasi funzione specifica nella TA, la CA la invoca specificando l'identificatore di una funzione insieme agli eventuali argomenti di input; questo viene fatto usando TEE_IOC_INVOKE.
Quando la CA ha terminato tutte le richieste, la sessione può essere chiusa usando TEE_IOC_CLOSE_SESSION.
Figura 2: Sessione tra CA e TA - dalla presentazione di Linaro [5]
Gran parte della comunicazione tra i client e il TEE è opaca per il driver. Il compito principale del driver è gestire il contesto, ricevere le richieste dai client, inoltrarle al TEE e rispedire i risultati [2].
CVE-2021-44733 è stato scoperto utilizzando il fuzzing con syzkaller. Il file di descrizione usato per questo scopo è riportato di seguito. Si noti che ioctl$TEE_SHM_REGISTER_FD fa solo parte dell'albero del kernel di Linaro (manutentori) e non è presente in upstream. L'ambiente fornito in 'Configurazione dell'ambiente' può essere utilizzato per il fuzzing se configurato correttamente secondo la documentazione di 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) }
Durante il fuzzing, il crash che ha attirato l'attenzione era legato a un use-after-free di un oggetto task_struct mentre un mutex era detenuto:```
==================================================================
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
==================================================================
Questo è stato innescato chiudendo tutti i descrittori di file provenienti da TEE_IOC_SHM_ALLOC mentre un thread diverso apre una sessione verso, nel nostro caso, una TA inesistente. Syzkaller è riuscito a riprodurlo e, sperimentando con il codice del riproduttore e ritardando leggermente la chiamata a TEE_IOC_OPEN_SESSION, si è verificato un diverso UAF per un oggetto appartenente alla cache kmalloc-64:```
================================================================== 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 ==================================================================
Questa vulnerabilità è stata scoperta eseguendo fuzzing sul driver TEE senza che fosse stata stabilita alcuna sessione con una TA esistente in esecuzione sul sistema. Ciò potrebbe essere ulteriormente esteso con le cosiddette pseudo syscall in syzkaller per impostare e avviare una sessione verso una qualche TA.
## Analisi della causa principale
La conclusione è un problema di progettazione nel tracciamento del ciclo di vita di un oggetto `tee_shm:dmabuf`. Il driver è progettato per lasciare che lo spazio utente mantenga l'unico e solo contatore di riferimenti dopo una chiamata a `tee_ioctl_shm_alloc()`.
Si presume che se l'oggetto è ancora presente nell'oggetto IDR del driver, allora il riferimento al dmabuf sia ancora valido e il suo contatore di riferimenti possa essere incrementato. In realtà questo è solo parzialmente vero. La memoria del dmabuf è ancora di proprietà del driver dmabuf, ma potrebbe essere in procinto di essere distrutta e questo non può essere fermato riportando il contatore di riferimenti a un valore diverso da zero.
Lo scenario che innesca il problema è un'applicazione multi-thread in cui un thread chiude il descrittore di file del dmabuf nello stesso momento in cui un altro thread effettua una chiamata al comando IOCTL `TEE_IOC_OPEN_SESSION` o `TEE_IOC_INVOKE` facendo riferimento a quella memoria condivisa.
Tracciando la distruzione del dmabuf quando lo spazio utente chiude il fd, nel kernel verrà eseguito questo codice:
1. `fput()`
2. `fput_many()` >> Il contatore dei riferimenti del file raggiunge lo zero. Si apre la finestra di race condition.
3. `[task_work gets scheduled]`
4. `__fput`
5. `dput`
6. `dma_buf_release`
7. `tee_shm_release`
8. `mutex_lock(teedev->mutex)`
9. `idr_remove(teedev->idr, shm->id)` >> Ora l'oggetto shm non può più essere referenziato dallo spazio utente. La finestra di race condition si chiude.
10. `mutex_unlock()`
Questo significa che la tabella IDR e il suo mutex non possono garantire che il dmabuf e il corrispondente `tee_shm` siano ancora vivi. Un processo che compete con `fput()` chiamando `tee_shm_get_from_id()` può ottenere un riferimento a uno shm che sta per essere distrutto.```
/**
* 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;
}
Per sfruttare questo problema, deve essere effettuata una riallocazione dopo che l'oggetto è stato liberato e prima di innescare la UAF. Dopo la chiamata a tee_shm_get_from_id(), viene chiamata la funzione tee_shm_put() (per cui si verifica il secondo crash UAF da syzkaller) che dereferenzia l'oggetto tee_shm:dmabuf usato come argomento di input per dma_buf_put().```
/**
L'oggetto `tee_shm` potrebbe essere riallocato prima della UAF poiché appartiene alla cache kmalloc-64. Dovrebbe essere riallocato con:
1. oggetti fittizi `tee_shm`, `tee_shm:dmabuf`, `dma_buf:file`
2. impostare `file->f_count = 1`
3. creare un oggetto `file:file_operations` che abbia il puntatore a funzione `fasync` impostato su un indirizzo arbitrario
Questa funzione viene poi invocata in `__fput()` dopo la chiamata a `dma_buf_put()` quando `file->f_count` raggiunge lo zero.
PAN (Privileged Access Never) mitiga questo aspetto poiché gli oggetti fittizi devono essere referenziati nella memoria dello spazio utente per poter impostare un puntatore a funzione arbitrario nella struttura `file:f_ops`. Pertanto, `CONFIG_CPU_SW_DOMAIN_PAN` deve essere disabilitato affinché funzioni, e lo è nell'ambiente fornito. Rimangono alcune domande aperte sulla possibilità di aggirare PAN in questa vulnerabilità, ad esempio usando ret2dir.
Inoltre, per effettuare con successo la riallocazione dell'oggetto shm deallocato, la chiamata IOCTL `TEE_IOC_OPEN_SESSION` o `TEE_IOC_INVOKE` deve essere soggetta a preemption da parte di un thread che esegue la chiusura del file descriptor e di un thread di heap spraying che riempie la cache kmalloc-64. Affinché ciò funzioni, il kernel deve essere configurato con `CONFIG_PREEMPT`. In questo PoC è stato utilizzato l'heap spray dal post del blog di Nicolas Fabretti [7], basato su `sendmsg()` bloccante.
Per riassumere, il problema per quanto riguarda lo sfruttamento è che sia la free che la UAF devono avvenire all'interno della stessa chiamata di sistema. Inoltre, la free è difficile da innescare perché richiede una race condition all'interno della syscall. Dopo la free, il tempo tra questa e l'effettiva UAF è una piccola finestra temporale in cui deve essere eseguito un heap spray per riallocare l'oggetto deallocato. La figura seguente mostra i thread coinvolti nel codice dell'exploit e il loro ruolo.
<p align="center">
<img src="https://raw.githubusercontent.com/pjlantz/pjlantz.github.io/master/docs/assets/Threads.png?raw=true" alt="Threads involved" width="50%" height="50%"/>
<br /><em>Figure 3: Threads involved in the exploit code</em>
</p>
Tre tipi di thread sono in esecuzione continua. Per preemptare il thread che effettua la chiamata di sistema, esso gira con la priorità più bassa possibile, `SCHED_IDLE`, mentre gli altri hanno la priorità impostata su `SCHED_OTHER`. Poiché stiamo usando `sendmsg()` bloccante, ogni tentativo di spray deve girare nel proprio thread e deve girare sullo stesso core CPU che innesca la UAF, dato che ogni core mantiene le proprie cache kmalloc. Ci sono anche diversi thread di freeing che chiudono il file descriptor dell'allocazione di memoria condivisa del passaggio 1b). Il codice sorgente completo per questo trigger di UAF e la sovrascrittura del puntatore a funzione si trova in [10].
## Setting up the new environment
Per riprodurre l'ambiente con un kernel vulnerabile e OPTEE, può essere clonato dal seguente repository e compilato usando:```
$ 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
After successful build, it will spawn three consoles, one for QEMU - press 'c' in the QEMU console in order to boot. A second console shows output from the secure world and the final one will boot into Linux. Login as root (no password).
Run the exploit code until the fasync function pointer of the file_operations structure is set to 0x22000000.```
until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done
Questo si fermerà a causa del blocco dell'esecuzione Privileged execute-never (PXN) a `PC=0x22000000`. Da qui in poi, le strategie di sfruttamento possono variare a seconda della versione del kernel, ma potrebbe essere possibile eseguire una ROP nel kernel e fare stack pivoting, oppure rendere scrivibile l'area vDSO e collocare lì il payload. Potrebbe anche essere interessante, per lavori futuri, verificare se la PAN può essere aggirata usando ret2dir e un po' di physmap spraying. La PAN può essere abilitata nel kernel impostando `CONFIG_CPU_SW_DOMAIN_PAN=y` in `linux/.config`. Su hardware reale, è abilitata per impostazione predefinita su ARMv8.1 e AArch64; per ARMv7 e AArch32 è possibile avere una PAN emulata via software usando questa impostazione [8].
**Nota**: questo exploit non è molto ottimizzato e potrebbe occasionalmente bloccare il driver se riesce a liberare l'oggetto di memoria condivisa troppo presto; in questo caso PC sarà in `tee_shm_get_from_id()`. Se ciò accade, esegui un `system_reset` nella console QEMU per riavviare l'ambiente.
## Ringraziamenti
Grazie a Lars Persson di Axis Communications per l'aiuto con l'analisi della causa radice e a Jens Wiklander di Linaro, nonché maintainer del sottosistema TEE, per una comunicazione fluida e la rapida risoluzione di questo problema [9].
## Riferimenti
[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] Proof of concept exploit - https://github.com/pjlantz/optee_examples/tree/master/exploit/host