I segmenti vsyscall e vDSO sono due meccanismi utilizzati per accelerare determinate chiamate di sistema in Linux. Ad esempio, di gettimeofday
solito viene invocato tramite questo meccanismo. Il primo meccanismo introdotto è stato vsyscall , che è stato aggiunto come un modo per eseguire chiamate di sistema specifiche che non richiedono alcun livello reale di privilegio per essere eseguite al fine di ridurre il sovraccarico delle chiamate di sistema. Seguendo l'esempio precedente, tutto ciò che gettimeofday
occorre fare è leggere l'ora corrente del kernel. Ci sono applicazioni che chiamano gettimeofday
frequentemente (ad esempio per generare timestamp), al punto che si preoccupano anche di un po 'di overhead. Per risolvere questo problema, il kernel mappa nello spazio utente una pagina contenente l'ora corrente e un file fastgettimeofday
implementazione (cioè solo una funzione che legge il tempo risparmiato in vsyscall ). Usando questa chiamata di sistema virtuale, la libreria C può fornire un veloce gettimeofday
che non ha l'overhead introdotto dal cambio di contesto tra lo spazio del kernel e lo spazio utente solitamente introdotto dal modello classico della chiamata di sistema INT 0x80
o SYSCALL
.
Tuttavia, questo meccanismo vsyscall presenta alcune limitazioni: la memoria allocata è piccola e consente solo 4 chiamate di sistema e, cosa più importante e seria, la pagina vsyscall è staticamente allocata allo stesso indirizzo in ogni processo, poiché la posizione della pagina vsyscall è inchiodato nel kernel ABI. Questa allocazione statica della vsyscall compromette il vantaggio introdotto dalla randomizzazione dello spazio di memoria comunemente usata da Linux. Un utente malintenzionato, dopo aver compromesso un'applicazione sfruttando uno stack overflow, può invocare una chiamata di sistema dal vsyscallpagina con parametri arbitrari. Tutto ciò di cui ha bisogno è l'indirizzo della chiamata di sistema, che è facilmente prevedibile in quanto allocato staticamente (se provi a eseguire nuovamente il tuo comando anche con applicazioni diverse, noterai che l'indirizzo della vsyscall non cambia). Sarebbe bello rimuovere o almeno randomizzare la posizione della pagina vsyscall per contrastare questo tipo di attacco. Sfortunatamente, le applicazioni dipendono dall'esistenza e dall'indirizzo esatto di quella pagina, quindi non è possibile fare nulla.
Questo problema di sicurezza è stato risolto sostituendo tutte le istruzioni di chiamata di sistema a indirizzi fissi con un'istruzione trap speciale. Un'applicazione che tenta di chiamare nella pagina vsyscall si intrappolerà nel kernel, che quindi emulerà la chiamata di sistema virtuale desiderata nello spazio kernel. Il risultato è una chiamata di sistema del kernel che emula una chiamata di sistema virtuale che è stata inserita per evitare la chiamata di sistema del kernel in primo luogo. Il risultato è una vsyscall che richiede più tempo per essere eseguita ma, soprattutto, non interrompe l'ABI esistente. In ogni caso, il rallentamento sarà visibile solo se l'applicazione sta tentando di utilizzare la pagina vsyscall invece di vDSO .
Il vDSO offre le stesse funzionalità del vsyscall, superandone i limiti. Il vDSO (Virtual Dynamically linked Shared Objects) è un'area di memoria allocata nello spazio utente che espone alcune funzionalità del kernel nello spazio utente in modo sicuro. Questo è stato introdotto per risolvere le minacce alla sicurezza causate da vsyscall
. Il vDSO viene allocato dinamicamente, il che risolve i problemi di sicurezza e può avere più di 4 chiamate di sistema. I collegamenti vDSO vengono forniti tramite la libreria glibc. Il linker si collegherà alla funzionalità glibc vDSO , a condizione che tale routine abbia una versione vDSO di accompagnamento , come gettimeofday
. Quando il tuo programma viene eseguito, se il tuo kernel non ha vDSO supporto, verrà eseguita una chiamata di sistema tradizionale.
Crediti e link utili: