
Sfruttamento di CVE-2022-0847 - scritto da : Antonius (w1sdom)
Dirty Pipe (CVE-2022-0847) è una delle vulnerabilità di sicurezza più significative nel kernel Linux 5.8 – 5.15.24, scoperta da Max Kellermann nel 2022. Questa vulnerabilità consente agli utenti ordinari (senza privilegi speciali) di sovrascrivere dati in file che dovrebbero essere di sola lettura. Comprendere i Concetti Fondamentali
Prima di discutere Dirty Pipe in dettaglio, ecco alcuni concetti interni del kernel Linux che devono essere compresi:
1. Paging
Il paging è un meccanismo di gestione della memoria nel kernel Linux in cui il sistema di memoria divide la memoria fisica in piccoli blocchi di dimensione fissa chiamati page frame, e la memoria virtuale è divisa in blocchi della stessa dimensione chiamati pagine.
Questo meccanismo consente al kernel di mappare lo spazio degli indirizzi virtuali dei processi alla memoria fisica in modo non sequenziale, il che è cruciale per l'efficienza e la sicurezza nei sistemi moderni.
2. Page (Memoria Virtuale)
In Linux, una pagina è la più piccola unità di gestione della memoria fisica gestita dal kernel.
Analogia: la RAM è come un libro gigante. Una pagina è un singolo foglio di quel libro. Il kernel non sposta i dati bit per bit, ma foglio per foglio (pagina per pagina).
In generale, sulle architetture di sistema moderne (come x86_64), la dimensione standard di una pagina è 4 KB (4096 byte).
3. Page Cache
Questa è una parte cruciale. Linux non legge i file direttamente dal disco ogni volta perché è lento. Il kernel copia il contenuto dei file nella RAM chiamata Page Cache.
4. Pipe Buffer
La pipe è un meccanismo di comunicazione inter-processo (IPC). Internamente, il kernel gestisce le pipe tramite la struttura dati pipe_inode_info. I dati all'interno di una pipe sono memorizzati in un "buffer" chiamato Pipe Buffer.
5. Flag del Pipe Buffer (PIPE_BUF_FLAG_CAN_MERGE)
Il flag PIPE_BUF_FLAG_CAN_MERGE è stato introdotto nella versione 5.8 del kernel Linux.
È qui che risiede la vulnerabilità principale. Il flag chiamato PIPE_BUF_FLAG_CAN_MERGE.
6. Splice
splice() è una syscall per spostare dati tra due file descriptor senza copiare i dati tra lo spazio del kernel e lo spazio utente. Questo è spesso definito meccanismo Zero-copy.
La syscall splice() è il "protagonista principale" di Dirty Pipe:
7. Copy on Write (CoW)
Il meccanismo Copy-on-Write (CoW) è una strategia di ottimizzazione della gestione della memoria utilizzata dal kernel Linux per ritardare la copia dei dati finché non è assolutamente necessario.
La relazione tra Copy-on-Write (CoW) e l'exploit Dirty Pipe (CVE-2022-0847) riguarda il modo in cui un piccolo bug nel kernel Linux "inganna" con successo il meccanismo CoW, consentendo la scrittura di dati in file che dovrebbero essere di sola lettura.
8. Dirty Page
Una dirty page è una pagina di memoria nella RAM che è stata modificata da un'applicazione, ma le modifiche non sono ancora state riscritte nella memoria secondaria (come SSD o disco rigido).
Analisi della Vulnerabilità Dirty Pipe
Dirty Pipe è un tipo di bug logico nella gestione del pipe buffer nel kernel Linux dalla versione 5.8 fino alla versione 5.15.24. Il problema principale risiede nel meccanismo Pipe (canale di comunicazione inter-processo) e nel modo in cui il kernel gestisce la Page Cache (memoria che conserva copie dei dati dei file dal disco). Il problema centrale è un bug nel flag PIPE_BUF_FLAG_CAN_MERGE.
Il problema principale risiede nella mancata re-inizializzazione corretta di questo flag da parte del kernel (bug logico). Ecco l'analisi del codice: Nelle funzioni copy_page_to_iter_pipe e push_to_pipe del kernel Linux precedente alla versione 5.16.11, quando si eseguono operazioni di splice, il kernel prepara la struttura pipe_buffer ma dimentica di pulire il membro .flags.
Struttura del Codice Vulnerabile:
// Location of problem: fs/pipe.c or include/linux/pipe_fs_i.h
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;
unsigned int flags; // <--- THIS FLAG IS NOT RESET
unsigned long private;
};
Codice Prima della Patch (Vulnerabile):
// lib/iov_iter.c - Before CVE-2022-0847 patch
static size_t copy_page_to_iter_pipe(struct page *page,
size_t offset, size_t bytes, struct iov_iter *i) {
// ---------snip-----------
struct pipe_buffer *buf = &pipe->bufs[head & mask];