Implementazione della dm-verity

Android 4.4 e versioni successive supporta l'Avvio verificato tramite l'opzione la funzionalità kernel device-mapper-verity (dm-verity), che fornisce il controllo dell'integrità dei dispositivi a blocchi. dm-verity aiuta a prevenire i rootkit persistenti che possono conservare i privilegi di root e compromettere i dispositivi. Questo aiuta gli utenti Android ad assicurarsi che quando si avviano un dispositivo si trovi nello stesso utilizzato per l'ultima volta.

Le applicazioni potenzialmente dannose con privilegi di root possono essere nascoste da dei programmi di rilevamento delle minacce e altrimenti mascherarsi. Il software di rooting può perché spesso sono più privilegiati dei rilevatori, abilitando il software per "mentire" ai programmi di rilevamento.

La funzionalità dm-verity ti consente di esaminare un dispositivo a blocchi, lo spazio di archiviazione livello del file system e determinare se corrisponde al livello previsto configurazione. Per farlo, utilizza una struttura ad albero di hash crittografico. Per ogni blocco (in genere 4 kB), è presente un hash SHA256.

Poiché i valori hash sono memorizzati in una struttura di pagine, solo lo stato "radice" l'hashing deve essere considerato attendibile per verificare il resto dell'albero. La possibilità di modificare un blocco equivale a rompere l'hash di crittografia. Consulta il seguente diagramma per una rappresentazione di questa struttura.

tabella-hash-dm-verity

Figura 1. Tabella hash dm-verity

Nella partizione di avvio è inclusa una chiave pubblica, che deve essere verificata da parte del produttore del dispositivo. Quella chiave viene utilizzata per verificare la firma per quell'hash e verifica che la partizione di sistema del dispositivo sia protetta senza modifiche.

Funzionamento

La protezione dm-verity risiede nel kernel. Quindi se il software di rooting compromette di sistema prima che appaia il kernel, conserverà quell'accesso. Per limitare questo rischio, la maggior parte dei produttori verifica il kernel tramite una chiave incorporata nel dispositivo. Questa chiave non è modificabile dopo che il dispositivo lascia la fabbrica di produzione.

I produttori usano questa chiave per verificare la firma al primo livello bootloader, che a sua volta verifica la firma nei livelli successivi, il bootloader dell'applicazione e infine il kernel. Ogni produttore che desidera sfruttano i servizi verificati boot deve avere un metodo per verificare l'integrità del kernel. Supponendo che il kernel sia stato verificato, il kernel può guardare un dispositivo a blocchi e verifica che sia montato.

Un modo per verificare un dispositivo a blocchi è eseguire l'hashing diretto dei suoi contenuti e confrontare in un valore memorizzato. Tuttavia, il tentativo di verificare un intero dispositivo a blocchi può richiedono un periodo prolungato e consumano gran parte della batteria del dispositivo. I dispositivi occuperebbero per lunghi periodi di tempo e poi essere svuotato in modo significativo prima dell'uso.

Dm-verity verifica invece i blocchi singolarmente e solo quando o rifiutano le richieste in base all'organizzazione a cui si accede. Quando viene letto in memoria, il blocco viene sottoposto ad hashing in parallelo. L'hash è e poi aver verificato l'albero. E siccome leggere il blocco è così costoso operativa, la latenza introdotta da questa verifica a livello di blocco è relativamente nominali.

Se la verifica non va a buon fine, il dispositivo genera un errore di I/O che indica il blocco non possono essere letti. Sarà come se il file system fosse danneggiato, così com'è previsto.

Le applicazioni possono scegliere di procedere senza i dati risultanti, ad esempio quando non sono necessari per la funzione primaria dell'applicazione. Tuttavia, se l'applicazione non può continuare senza i dati, non riuscirà.

Correzione di errori di inoltro

Android 7.0 e versioni successive migliora la robustezza della verifica dm con errori di inoltro di correzione (FEC). L'implementazione di AOSP inizia con il modello Reed-Solomon per la correzione degli errori e applica un tecnica nota come interfoliazione per ridurre l'overhead di spazio e aumentare di blocchi danneggiati che possono essere recuperati. Per ulteriori dettagli sulla FEC, vedi Avvio verificato rigorosamente con correzione errori.

Implementazione

Riepilogo

  1. Genera un'immagine di sistema ext4.
  2. Genera un albero di hash per l'immagine.
  3. Crea una tabella dm-verity per quell'albero hash.
  4. Firma la tabella dm-verity per produrre una tabella firma.
  5. Raggruppa la firma della tabella e la tabella dm-verity in metadati di verifica.
  6. Concatena l'immagine di sistema, i metadati di verifica e l'albero di hash.

Visita la pagina I progetti Chromium - Avvio verificato per una descrizione dettagliata dell'albero di hash e della tabella dm-verity.

Generazione dell'albero di hash

Come descritto nell'introduzione, l'albero di hash è parte integrante della dm-verity. La cryptsetup generare automaticamente un albero di hash. In alternativa, ne viene definito uno compatibile qui:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

Per formare l'hash, l'immagine di sistema viene divisa nel livello 0 in blocchi da 4.000, ciascuno e assegnato un hash SHA256. Il livello 1 si crea unendo solo gli hash SHA256 in blocchi di 4000 pixel, che risultano in un'immagine molto più piccola. Viene formato il livello 2 in modo identico con gli hash SHA256 del livello 1.

Questo viene fatto finché gli hash SHA256 del livello precedente non rientrano in un singolo bloccare. Quando ottieni l'algoritmo SHA256 del blocco, ottieni l'hash radice dell'albero.

La dimensione dell'albero di hash (e l'utilizzo dello spazio su disco corrispondente) varia con delle dimensioni della partizione verificata. In pratica, la dimensione degli alberi di hashing tende a essere piccoli, spesso inferiori a 30 MB.

Se in uno strato è presente un blocco che non è completamente riempito naturalmente dal hash dello strato precedente, devi riempirlo con zeri per ottenere previsto 4K. Ciò consente di sapere che l'albero di hash non è stato rimosso e completa invece con dati vuoti.

Per generare l'albero di hash, concatena gli hash del livello 2 su quelli del livello 1, il livello 3 gli hash su quelli del livello 2 e così via. Scrivi tutto questo su disco. Tieni presente che questo non fa riferimento al livello 0 dell'hash principale.

Ricapitolando, l'algoritmo generale per costruire l'albero di hash è il seguente:

  1. Scegli un sale casuale (codifica esadecimale).
  2. Annulla l'analisi dell'immagine di sistema in blocchi da 4.000.
  3. Per ogni blocco, ottieni l'hash SHA256 (salato).
  4. Concatena questi hash per formare un livello
  5. Completa il livello con 0 secondi fino a un limite di 4000 blocchi.
  6. Concatena il livello nell'albero di hash.
  7. Ripeti i passaggi 2-6 usando il livello precedente come sorgente per quello successivo, di avere un solo hash.

Il risultato è un singolo hash, ovvero l'hash principale. Questo e il tuo sale vengono utilizzati durante la creazione della tabella di mappatura dm-verity.

Creazione della tabella di mappatura dm-verity

Crea la tabella di mappatura dm-verity, che identifica il dispositivo a blocchi (o target) il kernel e la posizione dell'albero di hash (che è lo stesso valore). Questo il mapping viene utilizzato per la generazione e l'avvio di fstab. La tabella identifica inoltre la dimensione dei blocchi e hash_start, la posizione iniziale dell'albero di hash (nello specifico, il numero di blocco dall'inizio dell'immagine).

Vedi cryptsetup per Descrizione dettagliata dei campi della tabella di mappatura del target di verifica.

Firma della tabella dm-verity

Firma la tabella dm-verity per produrre una firma della tabella. Durante la verifica di un , la firma della tabella viene convalidata per prima. Questo avviene sulla base di una chiave l'immagine di avvio in una posizione fissa. Le chiavi sono generalmente incluse nel dei produttori creare sistemi per l'inclusione automatica sui dispositivi in un in ogni località.

Per verificare la partizione con questa combinazione di firma e chiave:

  1. Aggiungi alla sezione una chiave RSA-2048 in formato compatibile con libmincrypt /boot partizione alle ore /verity_key. Identifica la posizione della chiave utilizzata per la verifica l'albero di hash.
  2. Nel file fstab relativo alla voce pertinente, aggiungi verify ai flag fs_mgr.

Raggruppamento della firma della tabella nei metadati

Raggruppa la firma della tabella e la tabella dm-verity nei metadati di verifica. L'intero blocco di metadati viene sottoposto al controllo delle versioni, quindi può essere esteso, ad esempio per aggiungere un secondo di firma o di cambiare l'ordine.

Come controllo di integrità, a ogni insieme di metadati della tabella viene associato un numero magico che aiuta a identificare la tabella. Poiché la lunghezza è inclusa nel sistema ext4, intestazione immagine, che offre un modo per cercare i metadati senza conoscere i contenuti dei dati stessi.

In questo modo ti assicuri di non aver scelto di verificare una partizione non verificata. Se sì, l'assenza di questo numero magico interromperà la procedura di verifica. Questo numero assomiglia a:
0xb001b001

I valori dei byte in esadecimale sono:

  • primo byte = b0
  • secondo byte = 01
  • terzo byte = b0
  • quarto byte = 01

Il seguente diagramma illustra la suddivisione dei metadati di verifica:

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

In questa tabella sono descritti i campi dei metadati.

Tabella 1. Campi dei metadati di verifica

Campo Finalità Dimensioni Valore
numero magico usato da fs_mgr come controllo di integrità 4 byte 0xb001b001
versione utilizzata per creare le versioni del blocco di metadati 4 byte attualmente 0
firma la firma della tabella in PKCS1.5 modulo riempito 256 byte
lunghezza tabella la lunghezza della tabella dm-verity in byte 4 byte
tavolo la tabella dm-verity descritta in precedenza lunghezza della tabella byte
padding questa struttura ha una lunghezza da 0 riempita fino a 32 KB 0

Ottimizzazione della versione dm-verity

Per ottenere le migliori prestazioni da dm-verity, devi:

  • Nel kernel, attiva NEON SHA-2 per ARMv7 e SHA-2 per ARMv8.
  • Sperimenta con read-ahead e prefetch_cluster diversi impostazioni per trovare la configurazione migliore per il tuo dispositivo.