Solo allo stesso modo che modprobe
"sconfigge" la sicurezza caricando il nuovo codice nel kernel.
Per vari motivi, a volte ha più senso avere un codice semi-privilegiato (come i driver grafici all'interno del server X) in esecuzione nello spazio utente anziché in un thread del kernel.
- Poterlo
kill
più facilmente, a meno che non blocchi l'HW.
- Avendolo richiesto-page il suo codice / dati dai file nel filesystem. (La memoria del kernel non è impaginabile)
- Dandogli il suo spazio di indirizzi virtuale in cui i bug nel server X potrebbero semplicemente arrestare il server X, senza rimuovere il kernel.
Non fa molto per la sicurezza, ma ci sono grandi vantaggi in termini di affidabilità e architettura del software.
L'inserimento di driver grafici nel kernel potrebbe ridurre i cambi di contesto tra client X e server X, come un solo utente user-> kernel-> invece di dover inserire i dati in un altro processo di spazio di utilizzo, ma i server X sono storicamente troppo grandi e con errori volerli completamente nel kernel.
Sì, il codice dannoso con questi priv potrebbe assumere il kernel se lo desidera, usando /dev/mem
per modificare il codice del kernel.
O ad esempio su x86, eseguire cli
un'istruzione per disabilitare gli interrupt su quel core dopo aver effettuato una iopl
chiamata di sistema per impostare il suo livello di privilegio IO su ring 0.
Ma anche x86 iopl
"solo" dà accesso ad alcune istruzioni : in / out (e le versioni di stringa in / out) e cli / sti. Non ti permette di usare rdmsr
o wrmsr
di leggere o scrivere "registri specifici del modello" (ad esempio, IA32_LSTAR
che imposta l'indirizzo del punto di ingresso del kernel per l' syscall
istruzione x86-64 ), o usa lidt
per sostituire la tabella descrittore di interrupt (che ti permetterebbe di prendere totalmente sulla macchina dal kernel esistente, almeno su quel core.)
Non è nemmeno possibile leggere i registri di controllo (come CR3 che contiene l'indirizzo fisico della directory di pagina di livello superiore, che un processo di attacco potrebbe trovare utile come offset /dev/mem
per modificare le proprie tabelle di pagine in alternativa a mmap
più di /dev/mem
. )
invd
(invalidare tutte le cache senza riscrittura !! ( caso d'uso = BIOS iniziale prima della configurazione della RAM)) è un altro divertente che richiede sempre il CPL 0 completo (livello di privilegio corrente), non solo IOPL. Anche wbinvd
è privilegiato perché è così lento (e non interrompibile) e deve svuotare tutte le cache su tutti i core. (Vedere C'è un modo per svuotare l'intera cache CPU relativa a un programma? E l'uso di istruzioni WBINVD )
I bug che causano il salto a un indirizzo errato eseguono i dati come codice, pertanto non possono eseguire accidentalmente nessuna di queste istruzioni in un server X dello spazio utente.
Il livello di privilegio corrente (in modalità protetta e lunga) è rappresentato dai 2 bit bassi di cs
(il selettore del segmento di codice) . mov eax, cs
/ and eax, 3
funziona in qualsiasi modalità per leggere il livello di privilegio.
Per scrivere il livello di privilegio, fai un jmp far
o call far
per impostare CS:RIP
(ma la voce GDT / LDT per il segmento di destinazione può limitarlo in base al vecchio livello di privilegio, motivo per cui lo spazio utente non può farlo per elevarsi). Oppure usi int
o syscall
per passare al ring 0 in un punto di ingresso del kernel.
iopl
non consente tutte le istruzioni privilegiate, quindi è ancora utile per assicurarsi che un programma con spazio utente errato non venga eseguito accidentalmenteinvd
saltando attraverso un puntatore di funzione danneggiato che punta alla memoria eseguibile che inizia con0F 08
byte. Ho aggiunto una risposta con alcuni dei motivi di non sicurezza per cui è utile che i processi dello spazio utente elevino i loro privilegi.