Google is committed to advancing racial equity for Black communities. See how.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Scrittura della policy SELinux

Il progetto Android Open Source (AOSP) fornisce una solida politica di base per le applicazioni e i servizi comuni a tutti i dispositivi Android. I contributori di AOSP perfezionano regolarmente questa politica. Si prevede che la policy di base costituisca circa il 90–95% della policy finale sul dispositivo con personalizzazioni specifiche del dispositivo che costituiscono il restante 5-10%. Questo articolo si concentra su queste personalizzazioni specifiche del dispositivo, su come scrivere criteri specifici del dispositivo e su alcune delle insidie ​​da evitare lungo il percorso.

Richiamo del dispositivo

Durante la scrittura di criteri specifici del dispositivo, segui questi passaggi.

Esegui in modalità permissiva

Quando un dispositivo è in modalità permissiva , i dinieghi vengono registrati ma non applicati. La modalità permissiva è importante per due motivi:

  • La modalità permissiva garantisce che l'attivazione dei criteri non ritardi altre attività di attivazione anticipata del dispositivo.
  • Un diniego forzato può mascherare altri dinieghi. Ad esempio, l'accesso ai file in genere richiede una ricerca nella directory, l'apertura del file, quindi la lettura del file. In modalità di applicazione, si verifica solo il rifiuto della ricerca nella directory. La modalità permissiva garantisce che tutti i rifiuti siano visti.

Il modo più semplice per mettere un dispositivo in modalità permissiva è usare la riga di comando del kernel . Questo può essere aggiunto al file BoardConfig.mk del dispositivo: platform/device/<vendor>/<target>/BoardConfig.mk . Dopo aver modificato la riga di comando, eseguire make clean , quindi make bootimage e lampeggiare la nuova immagine di avvio.

Successivamente, conferma la modalità permissiva con:

adb shell getenforce

Due settimane sono un periodo di tempo ragionevole per essere in modalità permissiva globale. Dopo aver risolto la maggior parte dei dinieghi, torna alla modalità di applicazione e risolvi i bug non appena si presentano. I domini che continuano a produrre dinieghi o servizi ancora in fase di sviluppo pesante possono essere temporaneamente messi in modalità permissiva, ma riportali alla modalità di applicazione il prima possibile.

Applicare presto

In modalità di applicazione, i dinieghi vengono registrati e applicati. È buona norma portare il dispositivo in modalità di applicazione il prima possibile. In attesa di creare e applicare criteri specifici del dispositivo, spesso si ottiene un prodotto difettoso e una cattiva esperienza utente. Inizia abbastanza presto per partecipare alla versione sperimentale e assicurati la copertura completa dei test delle funzionalità nell'uso reale. L'avvio anticipato garantisce che i problemi di sicurezza informino le decisioni di progettazione. Al contrario, la concessione di autorizzazioni basate esclusivamente sui dinieghi osservati è un approccio non sicuro. Utilizzare questo tempo per eseguire un controllo di sicurezza del dispositivo e segnalare bug contro comportamenti che non dovrebbero essere consentiti.

Rimuovere o eliminare il criterio esistente

Esistono numerosi buoni motivi per creare da zero criteri specifici per dispositivo su un nuovo dispositivo, tra cui:

Affronta i dinieghi dei servizi fondamentali

I dinieghi generati dai servizi principali sono generalmente risolti dall'etichettatura dei file. Per esempio:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

è completamente risolto etichettando correttamente /dev/kgsl-3d0 . In questo esempio, tcontext è device . Questo rappresenta un contesto predefinito in cui tutto in /dev riceve l'etichetta " dispositivo " a meno che non venga assegnata un'etichetta più specifica. Accettare semplicemente l'output di audit2allow qui risulterebbe in una regola errata ed eccessivamente permissiva.

Per risolvere questo tipo di problema, dai al file un'etichetta più specifica, che in questo caso è gpu_device . Non sono necessarie ulteriori autorizzazioni poiché il mediaserver ha già le autorizzazioni necessarie nella politica di base per accedere a gpu_device.

Altri file specifici del dispositivo che dovrebbero essere etichettati con tipi predefiniti nella policy di base:

In generale, la concessione delle autorizzazioni alle etichette predefinite è sbagliata. Molte di queste autorizzazioni non sono consentite dalle regole neverallow , ma anche quando non sono esplicitamente disabilitate, la migliore pratica è fornire un'etichetta specifica.

Etichettare i nuovi servizi e rifiutare gli indirizzi

I servizi avviati da Init devono essere eseguiti nei propri domini SELinux. Il seguente esempio inserisce il servizio "pippo" nel proprio dominio SELinux e gli concede i permessi.

Il servizio viene avviato nell'init del nostro dispositivo init. device .rc file init. device .rc come:

service foo /system/bin/foo
    class core
  1. Crea un nuovo dominio "foo"

    Crea il file device/ manufacturer / device-name /sepolicy/foo.te con i seguenti contenuti:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    Questo è il modello iniziale per il dominio foo SELinux, a cui è possibile aggiungere regole basate sulle operazioni specifiche eseguite da quell'eseguibile.

  2. Etichetta /system/bin/foo

    Aggiungere quanto segue a device/ manufacturer / device-name /sepolicy/file_contexts :

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Ciò assicura che l'eseguibile sia etichettato correttamente in modo che SELinux esegua il servizio nel dominio appropriato.

  3. Crea e installa le immagini di avvio e di sistema.
  4. Affina le regole SELinux per il dominio.

    Utilizzare i dinieghi per determinare le autorizzazioni richieste. Lo strumento audit2allow fornisce buone linee guida, ma lo usa solo per informare la scrittura delle policy. Non copiare solo l'output.

Torna alla modalità di applicazione

Va bene risolvere i problemi in modalità permissiva, ma torna alla modalità di applicazione il prima possibile e cerca di rimanere lì.

Errori comuni

Di seguito sono riportate alcune soluzioni per errori comuni che si verificano durante la scrittura di criteri specifici del dispositivo.

Uso eccessivo della negazione

La seguente regola di esempio è come chiudere la porta d'ingresso ma lasciare le finestre aperte:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

L'intento è chiaro: tutti tranne le app di terze parti possono avere accesso al dispositivo di debug.

La regola è viziata in alcuni modi. L'esclusione di untrusted_app è banale da aggirare perché tutte le app possono facoltativamente eseguire servizi nel dominio isolated_app . Allo stesso modo, se vengono aggiunti nuovi domini per app di terze parti ad AOSP, avranno accesso anche a scary_debug_device . La regola è eccessivamente permissiva. La maggior parte dei domini non trarrà vantaggio dall'accesso a questo strumento di debug. La regola avrebbe dovuto essere scritta per consentire solo i domini che richiedono l'accesso.

Funzionalità di debug in produzione

Le funzionalità di debug non dovrebbero essere presenti nelle build di produzione né dovrebbero essere presenti i relativi criteri.

L'alternativa più semplice è consentire la funzionalità di debug solo quando SELinux è disabilitato su build eng / userdebug, come adb root e adb shell setenforce 0 .

Un'altra alternativa sicura è racchiudere le autorizzazioni di debug in un'istruzione userdebug_or_eng .

Esplosione delle dimensioni della politica

Caratterizzare le policy SEAndroid in the Wild descrive una tendenza preoccupante nella crescita delle personalizzazioni delle policy dei dispositivi. La policy specifica del dispositivo dovrebbe rappresentare il 5-10% della policy complessiva in esecuzione su un dispositivo. Le personalizzazioni nell'intervallo del 20% + contengono quasi certamente domini privilegiati e criteri morti.

Politica inutilmente grande:

  • Prende un doppio colpo sulla memoria poiché la politica si trova nel ramdisk e viene anche caricata nella memoria del kernel.
  • Spreca spazio su disco rendendo necessaria un'immagine di avvio più grande.
  • Influisce sui tempi di ricerca dei criteri di runtime.

L'esempio seguente mostra due dispositivi in ​​cui la policy specifica del produttore comprende il 50% e il 40% della policy sul dispositivo. Una riscrittura della policy ha prodotto miglioramenti sostanziali della sicurezza senza perdita di funzionalità, come mostrato di seguito. (I dispositivi AOSP Shamu e Flounder sono inclusi per il confronto.)

Figura 1: confronto delle dimensioni dei criteri specifici del dispositivo dopo il controllo della sicurezza.

Figura 1 . Confronto delle dimensioni dei criteri specifici del dispositivo dopo il controllo della sicurezza.

In entrambi i casi, la politica è stata drasticamente ridotta sia in termini di dimensioni che di numero di autorizzazioni. La diminuzione della dimensione della policy è quasi interamente dovuta alla rimozione di autorizzazioni non necessarie, molte delle quali erano probabilmente regole generate da audit2allow che sono state aggiunte indiscriminatamente alla policy. Anche i domini morti erano un problema per entrambi i dispositivi.

Concessione della funzionalità dac_override

Una negazione dac_override significa che il processo incriminato sta tentando di accedere a un file con le autorizzazioni utente / gruppo / mondo unix errate. La soluzione corretta è quasi mai quella di concedere l'autorizzazione dac_override . Cambia invece le autorizzazioni unix sul file o sul processo . Alcuni domini come init , vold e installd davvero bisogno della capacità di sovrascrivere i permessi dei file unix per accedere ai file di altri processi. Vedi il blog di Dan Walsh per una spiegazione più approfondita.