Per impostazione predefinita, le sezioni di codice eseguibile per i binari di sistema AArch64 sono contrassegnate come solo esecuzione (non leggibili) come misura di mitigazione del rafforzamento contro gli attacchi di riutilizzo del codice just-in-time. Il codice che mescola dati e codice e il codice che esamina intenzionalmente queste sezioni (senza prima rimappare i segmenti di memoria come leggibili) non funzionano più. Le app con un SDK target pari a 10 (livello API 29 o superiore) sono interessate se tentano di leggere sezioni di codice di librerie di sistema con memoria di sola esecuzione (XOM) attivate in memoria senza prima contrassegnare la sezione come leggibile.
Per trarre il massimo vantaggio da questa mitigazione, è necessario il supporto sia hardware sia del kernel. Senza questo supporto, la mitigazione potrebbe essere applicata solo parzialmente. Il kernel comune di Android 4.9 contiene le patch appropriate per fornire un supporto completo per questa funzionalità sui dispositivi ARMv8.2.
Implementazione
I file binari AArch64 generati dal compilatore presuppongono che il codice e i dati non siano mescolati. L'attivazione di questa funzionalità non influisce negativamente sul rendimento del dispositivo.
Per il codice che deve eseguire l'introspezione intenzionale della memoria sui suoi segmenti eseguibili, è consigliabile chiamare mprotect
sui segmenti di codice che richiedono l'ispezione per renderli leggibili, quindi rimuovere la leggibilità al termine dell'ispezione.
Questa implementazione causa errori di segmentazione (SEGFAULT
) nelle letture dei segmenti di memoria contrassegnati come di sola esecuzione.
Questo potrebbe verificarsi a causa di un bug, di una vulnerabilità, di dati mescolati con il codice (pooling di literal) o di un'introspezione intenzionale della memoria.
Supporto dei dispositivi e impatto
I dispositivi con hardware o kernel precedenti (inferiori alla versione 4.9) senza le patch richieste potrebbero non supportare completamente questa funzionalità o non trarne vantaggio. I dispositivi senza supporto del kernel potrebbero non applicare gli accessi utente alla memoria di sola esecuzione, tuttavia il codice del kernel che controlla esplicitamente se una pagina è leggibile potrebbe comunque applicare questa proprietà, ad esempio process_vm_readv()
.
Il flag del kernel CONFIG_ARM64_UAO
deve essere impostato nel kernel per
garantire che il kernel rispetti le pagine dello spazio utente contrassegnate come di sola esecuzione. I dispositivi ARMv8 precedenti o i dispositivi ARMv8.2 con l'override dell'accesso utente (UAO) disattivato potrebbero non trarre vantaggio da questa funzionalità e potrebbero comunque essere in grado di leggere le pagine di sola esecuzione utilizzando le chiamate di sistema.
Ristrutturare il codice esistente
Il codice portato da AArch32 potrebbe contenere dati e codice mescolati, causando problemi. In molti casi, la risoluzione di questi problemi è semplice come spostare le costanti in una sezione .data
del file assembly.
Potrebbe essere necessario eseguire il refactoring dell'assemblaggio scritto a mano per separare le costanti messe in pool localmente.
Esempi:
I file binari generati dal compilatore Clang non dovrebbero avere problemi con la commistione di dati nel codice. Se il codice generato dalla raccolta di compilatori GNU (GCC) è incluso (da una libreria statica), controlla il file binario di output per assicurarti che le costanti non siano state raggruppate in sezioni di codice.
Se è necessaria l'introspezione del codice nelle sezioni di codice eseguibile,
chiamate prima mprotect
per contrassegnare il codice come leggibile. Al termine dell'operazione, richiama di nuovo mprotect
per contrassegnarli come illeggibili.
Attiva XOM
L'opzione Solo esecuzione è attiva per impostazione predefinita per tutti i file binari a 64 bit nel sistema di compilazione.
Disattiva XOM
Puoi disattivare l'esecuzione solo a livello di modulo, per un'intera struttura ad albero di sottodirectory o globalmente per un'intera build.
XOM può essere disattivato per i singoli moduli che non possono essere sottoposti a refactoring o che devono leggere il codice eseguibile impostando le variabili LOCAL_XOM
e xom
su false
.
// Android.mk LOCAL_XOM := false // Android.bp cc_binary { // or other module types ... xom: false, }
Se la memoria di sola esecuzione è disattivata in una libreria statica, il sistema di compilazione lo applica a tutti i moduli dipendenti di quella libreria statica. Puoi eseguire l'override utilizzando xom: true,
.
Per disattivare la memoria di sola esecuzione in una determinata sottodirectory (ad esempio,
foo/bar/), passa il valore a XOM_EXCLUDE_PATHS
.
make -j XOM_EXCLUDE_PATHS=foo/bar
In alternativa, puoi impostare la variabile PRODUCT_XOM_EXCLUDE_PATHS
nella configurazione del prodotto.
Puoi disattivare i binari di sola esecuzione a livello globale passando
ENABLE_XOM=false
al comando make
.
make -j ENABLE_XOM=false
Convalida
Non sono disponibili test CTS o di verifica per la memoria di sola esecuzione. Puoi verificare manualmente i binari utilizzando readelf
e controllando i flag dei segmenti.