Implementare SELinux

SELinux è configurato per il rifiuto predefinito, il che significa che ogni singolo accesso per il quale è presente un hook nel kernel deve essere consentito esplicitamente dal criterio. Ciò significa che un file di criteri è costituito da una grande quantità di informazioni su regole, tipi, classi, autorizzazioni e altro ancora. Un'analisi completa di SELinux rientra al di fuori dell'ambito di questo documento, ma comprendere come scrivere le regole delle norme è ora essenziale per l'utilizzo di nuovi dispositivi Android. Esistono già moltissime informazioni su SELinux. Consulta la documentazione di supporto per le risorse suggerite.

File principali

Per attivare SELinux, integra il kernel Android più recente e poi incorpora i file trovati nella directory system/sepolicy. Una volta compilati, questi file comprendono i criteri di sicurezza del kernel SELinux e coprono il sistema operativo Android upstream.

In generale, non devi modificare direttamente i file system/sepolicy. Aggiungi o modifica i tuoi file di criteri specifici per il dispositivo nella directory/device/manufacturer/device-name/sepolicy. In Android 8.0 e versioni successive, le modifiche apportate a questi file dovrebbero riguardare solo i criteri nella directory del fornitore. Per ulteriori dettagli sulla separazione di sepolicy pubblico in Android 8.0 e versioni successive, consulta Personalizzazione di SEPolicy in Android 8.0 e versioni successive. Indipendentemente dalla versione di Android, dovrai comunque modificare questi file:

File di criteri

I file che terminano con *.te sono file di origine dei criteri SELinux, che definiscono i domini e le relative etichette. Potresti dover creare nuovi file di norme in /device/manufacturer/device-name/sepolicy, ma, se possibile, dovresti provare ad aggiornare i file esistenti.

File di contesto

Nei file di contesto specifichi le etichette per gli oggetti.

  • file_contexts assegna etichette ai file e viene utilizzato da vari componenti dello spazio utente. Man mano che crei nuovi criteri, crea o aggiorna questo file per assegnare nuove etichette ai file. Per applicare un nuovo file_contexts, ricostruisci l'immagine del file system o esegui restorecon sul file da rinominare. Durante gli upgrade, le modifiche a file_contexts vengono applicate automaticamente alle partizioni system e userdata nell'ambito dell'upgrade. Le modifiche possono essere applicate automaticamente anche durante l'upgrade ad altre partizioni aggiungendo chiamate restorecon_recursive al file init.board.rc dopo aver montato la partizione in modalità di lettura/scrittura.
  • genfs_contexts assegna etichette ai file system, come proc o vfat, che non supportano gli attributi estesi. Questa configurazione viene caricata come parte del criterio del kernel, ma le modifiche potrebbero non essere applicate agli inode in-core, richiedendo un riavvio o smontaggio e rimontaggio del file system per applicare completamente la modifica. È possibile assegnare etichette specifiche anche a supporti specifici, ad esempio vfat utilizzando l'opzione context=mount.
  • property_contexts assegna etichette alle proprietà di sistema Android per controllare quali processi possono impostarle. Questa configurazione viene letta dal processo init durante l'avvio.
  • service_contexts assegna etichette ai servizi binder di Android per controllare quali processi possono aggiungere (registrare) e trovare (cercare) un riferimento binder per il servizio. Questa configurazione viene letta dal processo servicemanager durante l'avvio.
  • seapp_contexts assegna etichette ai processi e alle directory /data/data dell'app. Questa configurazione viene letta dal processo zygote a ogni avvio dell'app e da installd durante l'avvio.
  • mac_permissions.xml assegna un tag seinfo alle app in base alla loro firma e, facoltativamente, al nome del pacchetto. Il tag seinfo può essere utilizzato come chiave nel file seapp_contexts per assegnare un'etichetta specifica a tutte le app con questo tag seinfo. Questa configurazione viene letta da system_server durante l'avvio.
  • keystore2_key_contexts assegna le etichette agli spazi dei nomi Keystore 2.0. Questi spazi dei nomi vengono applicati dal daemon keystore2. Il keystore ha sempre fornito spazi dei nomi basati su UID/AID. Keystore 2.0 applica inoltre gli spazi dei nomi definiti da sepolicy. Una descrizione dettagliata del formato e delle convenzioni di questo file è disponibile qui.

File makefile BoardConfig.mk

Dopo aver modificato o aggiunto i file di criteri e di contesto, aggiorna il /device/manufacturer/device-name/BoardConfig.mk makefile in modo che faccia riferimento alla sottodirectory sepolicy e a ogni nuovo file di criteri. Per ulteriori informazioni sulle variabili BOARD_SEPOLICY, consulta il file system/sepolicy/README.

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

Dopo la ricostruzione, il dispositivo è abilitato con SELinux. Ora puoi personalizzare i tuoi criteri SELinux per adattarli alle tue aggiunte al sistema operativo Android, come descritto in Personalizzazione, oppure verificare la configurazione esistente, come descritto in Convalida.

Quando i nuovi file di criteri e gli aggiornamenti di BoardConfig.mk sono in atto, le nuove impostazioni dei criteri vengono integrate automaticamente nel file di criteri del kernel finale. Per ulteriori informazioni su come viene creato sepolicy sul dispositivo, consulta Creazione di sepolicy.

Implementazione

Per iniziare a utilizzare SELinux:

  1. Attiva SELinux nel kernel: CONFIG_SECURITY_SELINUX=y
  2. Modifica il parametro kernel_cmdline o bootconfig in modo che:
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    oppure
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    Questo vale solo per lo sviluppo iniziale dei criteri per il dispositivo. Dopo aver definito un criterio di bootstrap iniziale, rimuovi questo parametro in modo che il dispositivo lo applichi o non superi il CTS.
  3. Avvia il sistema in modalità permissiva e controlla quali negazioni vengono rilevate all'avvio:
    Su Ubuntu 14.04 o versioni successive:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    Su Ubuntu 12.04:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. Valuta l'output per verificare la presenza di avvisi simili a init: Warning! Service name needs a SELinux domain defined; please fix! Consulta la sezione Convalida per istruzioni e strumenti.
  5. Identifica i dispositivi e gli altri nuovi file che devono essere etichettati.
  6. Utilizza etichette esistenti o nuove per gli oggetti. Esamina i file *_contexts per vedere come erano etichettate le risorse in precedenza e utilizza la conoscenza dei significati delle etichette per assegnarne una nuova. Idealmente, si tratta di un'etichetta esistente che rispetta i criteri, ma a volte è necessaria una nuova etichetta e sono necessarie regole per l'accesso a quell'etichetta. Aggiungi le etichette ai file di contesto appropriati.
  7. Identifica i domini/processi che devono avere i propri domini di sicurezza. Probabilmente dovrai scrivere una norma completamente nuova per ogni canale. Ad esempio, tutti i servizi generati da init devono avere il proprio. I seguenti comandi consentono di rilevare quelli che rimangono in esecuzione (ma TUTTI i servizi richiedono questo trattamento):
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. Esamina init.device.rc per identificare i domini che non hanno un tipo di dominio. Assegnagli un dominio all'inizio del processo di sviluppo per evitare di aggiungere regole a init o di confondere gli accessi a init con quelli previsti dalle sue norme.
  9. Configura BOARD_CONFIG.mk in modo da utilizzare le variabili BOARD_SEPOLICY_*. Per informazioni dettagliate sulla configurazione, consulta il file README in system/sepolicy.
  10. Esamina i file init.device.rc e fstab.device e assicurati che ogni utilizzo di mount corrisponda a un filesystem correttamente etichettato o che sia specificata un'opzione context= mount.
  11. Esamina ogni rifiuto e crea un criterio SELinux per gestirlo correttamente. Consulta gli esempi in Personalizzazione.

Dovresti iniziare con le norme nell'AOSP e poi svilupparle per le tue personalizzazioni. Per ulteriori informazioni sulla strategia di criteri e per approfondire alcuni di questi passaggi, consulta Scrivere i criteri SELinux.

Casi d'uso

Ecco alcuni esempi specifici di exploit da considerare quando crei il tuo software e i relativi criteri SELinux:

Link simbolici: poiché i link simbolici appaiono come file, spesso vengonoletti come file, il che può portare a exploit. Ad esempio, alcuni componenti privilegiati, come init, modificano le autorizzazioni di determinati file, a volte in modo eccessivamente aperto.

Gli utenti malintenzionati potrebbero quindi sostituire questi file con link simbolici al codice che controllano, consentendo loro di sovrascrivere file arbitrari. Tuttavia, se sai che la tua app non attraversa mai un link simbolico, puoi vietarlo con SELinux.

File di sistema:prendi in considerazione la classe di file di sistema che deve essere modificata solo dal server di sistema. Tuttavia, poiché netd, init e vold vengono eseguiti come root, possono accedere a questi file di sistema. Pertanto, se netd viene compromesso, potrebbe compromettere questi file e potenzialmente il server di sistema stesso.

Con SELinux, puoi identificare questi file come file di dati del server di sistema. Pertanto, l'unico dominio che ha accesso in lettura/scrittura è il server di sistema. Anche se netd fosse stato compromesso, non avrebbe potuto cambiare dominio con il dominio del server di sistema e accedere a questi file di sistema, anche se viene eseguito come utente root.

Dati dell'app:un altro esempio è la classe di funzioni che deve essere eseguita come root, ma non deve accedere ai dati dell'app. Questo è incredibilmente utile perché è possibile fare affermazioni di ampio respiro, ad esempio vietare a determinati domini non correlati ai dati delle app di accedere a internet.

setattr: per comandi come chmod e chown, puoi identificare l'insieme di file in cui il dominio associato può eseguire setattr. Tutto ciò che non rientra in questo ambito potrebbe essere vietato da queste modifiche, anche dall'utente root. Pertanto, un'app potrebbe eseguire chmod e chown su quelle etichettate come app_data_files, ma non su shell_data_files o system_data_files.