Pubblicità
Motherboard

Cosa c'è dietro l'apocalisse dei processori di Intel

Ovvero, quello che succede quando la sicurezza informatica si scontra con l'efficienza dei computer.

di Michael Byrne
04 gennaio 2018, 4:04pm

lungstruck/Flickr

Questa settimana si è scoperto che i processori x86-64 di Intel, che sono alla base della gran maggior parte dei computer odierni, soffrono di un bug critico di sicurezza. Abbastanza critico da richiedere un rimaneggiamento significativo dei kernel di Windows e Linux, il codice fondamentale del sistema operativo che è responsabile per mediare l'accesso alla CPU della macchina, alla sua memoria di sistema (la RAM) e ai dispositivi di input/output (I/O), che includono oggetti come le tastiere fino agli hard disk. Riparare il kernel di un sistema operativo è una pratica molto vicina a un'operazione chirurgica al cervello del computer.

In un computer, il kernel è la base fondamentale di qualunque altro aspetto della macchina, e ha accesso a tutto il resto. Non c'è modo di nascondersi dal kernel. Avere accesso al kernel significa avere accesso a tutto il resto della macchina. È un principio base fondamentale quello che prevede che il kernel rimanga protetto da qualunque normale imprevisto relativo di cui il computer potrebbe patire. Le interazioni con il kernel, per questo motivo, sono mediate in maniera estremamente rigida. Perché un software, per esempio, possa scrivere dei dati in memoria, deve parlare con il kernel attraverso una funzione conosciuta con il nome di system call.

La maggior parte degli sviluppatori non hanno granché a che fare con le system call. Per scrivere del software in grado di eseguire delle system call dovresti scrivere in C, che esiste proprio per supportare altri linguaggio di livello più alto come il Python o il Java. Ciò non significa che queste system call siano rare. Invece, si verificano costantemente sotto forma di un torrente di richieste che vengono delegate all'hardware sottostante attraverso un processo conosciuto come threading. Il threading è ciò che fornisce al computer le sembianze di un flusso operativo apparentemente ininterrotto, anche se in realtà sta operando proprio nel bel mezzo di un oceano di interruzioni.

Se il kernel è così protetto, come fa a interagire costantemente con il resto della macchina? Ecco, la soluzione a questo problema è proprio la protagonista di questo bug.

In breve, i programmi per computer esistono su una macchina sotto forma di processi. Un PC normale ha diversi processi avviati contemporaneamente (scrivete sul vostro terminale "ps -A" su Unix/Mac o "tasklist" su Windows per vedere tutti i vostri processi attualmente in corso). Ognuno di questi processi dispone di una piccola parte di computer a sua disposizione, con la sua lista privata di indirizzi di memoria (ovvero slot di memoria disponibili, in pratica). Il kernel è in un certo senso onnipresente in ognuno di questi processi, è parte di loro ma allo stesso tempo anche separato da essi. Un processo può accedere al kernel attraverso i propri indirizzi di memoria privati, ma il kernel non è contenuto all'interno del processo stesso.

Il vantaggio di questo setup è che riduce il carico su ciò che viene chiamato context switching, cioè il procedimento a tratti goffo e lento che si consuma quando un processore deve saltare tra i vari processi. Ciò che questo setup non dovrebbe fare è esporre l'intero cazzo di kernel a ognuno di questi processi, ma apparentemente è ciò che si è verificato con i processi x86-64 per davvero molto tempo.

Per essere chiari bisogna dire che non è semplice accedere al kernel attraverso questo bug. Ma in un certo senso si tratta di un Vaso di Pandora: una volta che la giostra parte non si ferma più.

Per di più non si tratta nemmeno di una scoperta così recente. La scorsa estate, un ricercatore di sicurezza informatica chiamato Anders Fogh ha pubblicato un post sul blog che descrive proprio questo problema. Questa settimana, lo stesso post è stato rilanciato da The Register, ed è proprio questo rilancio che ha generato tutto il casino che è scoppiato nelle ultime ore, inclusa la dichiarazione di risposta di Intel risalente a ieri. Apple ha già distribuito un fix nell'aggiornamento macOS di dicembre.

La natura di questa falla ha a che fare con il processo di threading di cui ho parlato prima. Una parte di ciò che fa funzionare il threading in maniera così funzionale e discreta è chiamato "speculative execution."

Un principio chiave dei sistemi computerizzati è l'instruction pipelining. Per ottimizzare l'utilizzo di un processore, un sistema organizza le istruzioni—unità computazionali atomiche di livello macchina che sono alla base di qualunque software—in sequenze pensate per minimizzare il numero di cicli procedurali sprecati. È sempre in cerca di istruzioni che possono essere processate in diverse subunità computazionali parallele, ovvero, in altre parole, sono istruzioni che non dipendono necessariamente dal risultato di altre istruzioni.

Per costruire le pipeline di istruzioni più efficienti, il sistema in un certo senso bara. Ciò che può davvero rallentare il pipeline planning è il fatto che non si sa sempre come i programmi si comporteranno nel corso del tempo. Di solito i programmi tendono a ramificarsi in "branch" in maniera condizionata. Ciò detto, potrebbero comportarsi in un modo o nell'altro sulla base di frammenti di dati che non sono ancora disponibili al sistema. Per questo motivo deve anticipare questi comportamenti che, nel peggiore dei casi, potrebbero significare che il sistema deve anticipare entrambi i tipi di risultati.

Nella speculative execution, il sistema tenta di tirare a indovinare in maniera informata per capire quale ramificazione è più probabile che venga perseguita. In alcuni casi, ciò significa che potrebbe eseguire delle istruzioni prima che si sappia se queste istruzioni siano davvero necessarie o meno. A volte queste previsioni sono errate e finiscono per proiettare la ramificazione sbagliata, per cui il sistema deve poi tornare indietro e intraprendere l'altra ramificazione. Nel suo insieme, questo sistema permette di disporre di un tipo di informatica molto più veloce.

Il trucco è che quando un processore tira a indovinare su una ramificazione, sta bypassando i controlli di accesso e, per un momento, sta esponendo lo spazio kernel protetto allo spazio utente. Un hacker intelligente potrebbe teoricamente sfruttare questa esposizione per dare un'occhiata alle password, alle chiavi e ad altre risorse protette.

"Per migliorare le performance, molte CPU potrebbe scegliere di eseguire speculativamente delle istruzioni sulla base di previsione che sono considerate probabilmente vere," hanno spiegato in un blog post Matt Vinton e Pat Parseghian di Google. "Durante la speculative execution, il processo verifica queste previsioni; se sono valide, l'esecuzione continua. Se non sono valide, allora l'esecuzione viene fermata, e viene intrapresa la ramificazione corretta sulla base delle condizioni reali. È possibile che la speculative execution abbia delle controindicazioni che non vengono ripristinate quando lo stato della CPU viene resettato, e ciò potrebbe esporre delle informazioni."

Google ha scovato tre possibili exploit che potrebbero sfruttare la speculative execution e che non sono esclusivi a Intel. Sono inclusi in qualsiasi processo che sfrutta la speculative execution, e ciò include anche i processori ARM e AMD, secondo il post. (Anche se AMD ha negato che ciò sia possibile.) Prendere di mira solamente Intel non è esattamente equo, ma sembra che fosse a conoscenza di tutto ciò da un bel po' di tempo prima che la stampa e i social media cominciassero a parlarne.