Personalizzare SELinux

Dopo aver integrato il livello di base della funzionalità SELinux e aver esaminato attentamente i risultati, puoi aggiungere le tue impostazioni dei criteri per coprire le tue personalizzazioni del sistema operativo Android. Questi criteri devono comunque soddisfare i requisiti del programma di compatibilità Android e non devono rimuovere le impostazioni SELinux predefinite.

I produttori non devono rimuovere le norme SELinux esistenti. In caso contrario, rischiano di danneggiare l'implementazione di SELinux di Android e le app che regola. Sono incluse le app di terze parti che probabilmente dovranno essere migliorate per essere conformi e operative. Le app non devono richiedere modifiche per continuare a funzionare sui dispositivi con SELinux abilitato.

Quando inizi a personalizzare SELinux, ricordati di:

  • Scrivi il criterio SELinux per tutti i nuovi demoni
  • Utilizza i domini predefiniti, se opportuno
  • Assegna un dominio a qualsiasi processo generato come servizio init
  • Acquisire familiarità con le macro prima di scrivere le norme
  • Inviare le modifiche alle norme di base ad AOSP

Inoltre, ricordati di non:

  • Creare una norma incompatibile
  • Consenti la personalizzazione dei criteri per gli utenti finali
  • Consenti le personalizzazioni dei criteri MDM
  • Spaventare gli utenti con violazioni delle norme
  • Aggiungere backdoor

Per requisiti specifici, consulta la sezione Funzionalità di sicurezza del kernel del documento di definizione della compatibilità di Android.

SELinux utilizza un approccio di tipo whitelist, il che significa che tutto l'accesso deve essere esplicitamente consentito nel criterio per essere concesso. Poiché il criterio SELinux predefinito di Android supporta già il progetto Android Open Source, non è necessario modificare le impostazioni di SELinux in alcun modo. Se personalizzi le impostazioni SELinux, fai molta attenzione a non danneggiare le app esistenti. Per iniziare:

  1. Utilizza il kernel Android più recente.
  2. Adotta il principio del privilegio minimo.
  3. Risolvi solo i problemi relativi alle tue aggiunte ad Android. Il criterio predefinito funziona automaticamente con la base di codice del progetto Android Open Source.
  4. Suddividi i componenti software in moduli che svolgono singole attività.
  5. Crea criteri SELinux che isolino queste attività da funzioni non correlate.
  6. Inserisci questi criteri nei file *.te (l'estensione per i file di codice sorgente dei criteri SELinux) all'interno della directory /device/manufacturer/device-name/sepolicy e utilizza le variabili BOARD_SEPOLICY per includerli nella compilazione.
  7. Rendi inizialmente permissivi i nuovi domini. Ciò viene fatto utilizzando una dichiarazione permissiva nel file .te del dominio.
  8. Analizza i risultati e perfeziona le definizioni di dominio.
  9. Rimuovi la dichiarazione permissiva se non vengono visualizzati ulteriori rifiuti nelle build userdebug.

Dopo aver integrato la modifica del criterio SELinux, aggiungi un passaggio al flusso di lavoro di sviluppo per garantire la compatibilità con SELinux in futuro. In un processo ideale di sviluppo software, il criterio SELinux cambia solo quando cambia il modello software e non l'implementazione effettiva.

Quando inizi a personalizzare SELinux, controlla prima le aggiunte ad Android. Se hai aggiunto un componente che esegue una nuova funzione, assicurati che il componente soddisfi i criteri di sicurezza di Android, nonché eventuali criteri associati creati dall'OEM, prima di attivare la modalità di applicazione.

Per evitare problemi non necessari, è meglio essere troppo generici e compatibili piuttosto che troppo restrittivi e incompatibili, il che comporta il malfunzionamento delle funzioni del dispositivo. Al contrario, se le modifiche sono vantaggiose per altri, devi inviare le modifiche al criterio SELinux predefinito come patch. Se la patch viene applicata al criterio di sicurezza predefinito, non dovrai apportare questa modifica con ogni nuova release di Android.

Dichiarazioni di norme di esempio

SELinux si basa sul linguaggio di programmazione M4 e pertanto supporta una serie di macro per farti risparmiare tempo.

Nell'esempio seguente, a tutti i domini viene concesso l'accesso in lettura o scrittura a /dev/null e in lettura a /dev/zero.

# Allow read / write access to /dev/null
allow domain null_device:chr_file { getattr open read ioctl lock append write};

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file { getattr open read ioctl lock };

La stessa istruzione può essere scritta con le macro *_file_perms SELinux (abbreviazione):

# Allow read / write access to /dev/null
allow domain null_device:chr_file rw_file_perms;

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file r_file_perms;

Norme di esempio

Di seguito è riportato un esempio completo di criterio per DHCP:

type dhcp, domain;
permissive dhcp;
type dhcp_exec, exec_type, file_type;
type dhcp_data_file, file_type, data_file_type;

init_daemon_domain(dhcp)
net_domain(dhcp)

allow dhcp self:capability { setgid setuid net_admin net_raw net_bind_service
};
allow dhcp self:packet_socket create_socket_perms;
allow dhcp self:netlink_route_socket { create_socket_perms nlmsg_write };
allow dhcp shell_exec:file rx_file_perms;
allow dhcp system_file:file rx_file_perms;
# For /proc/sys/net/ipv4/conf/*/promote_secondaries
allow dhcp proc_net:file write;
allow dhcp system_prop:property_service set ;
unix_socket_connect(dhcp, property, init)

type_transition dhcp system_data_file:{ dir file } dhcp_data_file;
allow dhcp dhcp_data_file:dir create_dir_perms;
allow dhcp dhcp_data_file:file create_file_perms;

allow dhcp netd:fd use;
allow dhcp netd:fifo_file rw_file_perms;
allow dhcp netd:{ dgram_socket_class_set unix_stream_socket } { read write };
allow dhcp netd:{ netlink_kobject_uevent_socket netlink_route_socket
netlink_nflog_socket } { read write };

Analizziamo l'esempio:

Nella prima riga, la dichiarazione del tipo, il daemon DHCP eredita dal criterio di sicurezza di base (domain). Dagli esempi di dichiarazione precedenti, DHCP può leggere e scrivere in /dev/null.

Nella seconda riga, DHCP è identificato come dominio permissivo.

Nella riga init_daemon_domain(dhcp), il criterio indica che DHCP viene generato da init e può comunicare con questo.

Nella riga net_domain(dhcp), il criterio consente a DHCP di utilizzare la funzionalità di rete comune del dominio net, ad esempio la lettura e la scrittura di pacchetti TCP, la comunicazione tramite socket e l'esecuzione di richieste DNS.

Nella riga allow dhcp proc_net:file write;, il criterio indica che DHCP può scrivere in file specifici in /proc. Questa riga mostra l'etichettatura granulare dei file di SELinux. Utilizza l'etichetta proc_net per limitare l'accesso in scrittura solo ai file in /proc/sys/net.

Il blocco finale dell'esempio che inizia con allow dhcp netd:fd use; mostra in che modo le app possono essere autorizzate a dialogare tra loro. Il criterio indica che DHCP e netd possono comunicare tra loro tramite descrittori file, file FIFO, socket datagramma e socket stream UNIX. DHCP può leggere e scrivere solo nelle socket di datagrammi e nelle socket stream UNIX, senza crearle o aprirle.

Controlli disponibili

Classe Autorizzazione
file
ioctl read write create getattr setattr lock relabelfrom relabelto append
unlink link rename execute swapon quotaon mounton
directory
add_name remove_name reparent search rmdir open audit_access execmod
presa
ioctl read write create getattr setattr lock relabelfrom relabelto append bind
connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg
name_bind
filesystem
mount remount unmount getattr relabelfrom relabelto transition associate
quotamod quotaget
processo
fork transition sigchld sigkill sigstop signull signal ptrace getsched setsched
getsession getpgid setpgid getcap setcap share getattr setexec setfscreate
noatsecure siginh setrlimit rlimitinh dyntransition setcurrent execmem
execstack execheap setkeycreate setsockcreate
sicurezza
compute_av compute_create compute_member check_context load_policy
compute_relabel compute_user setenforce setbool setsecparam setcheckreqprot
read_policy
funzionalità
chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap
linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock
ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin
sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write
audit_control setfcap

ALTRO

E ANCORA

Regole neverallow

Le regole neverallow SELinux vietano comportamenti che non dovrebbero mai verificarsi. Con i test di compatibilità, le regole SELinux neverallow vengono ora applicate su tutti i dispositivi.

Le seguenti linee guida hanno lo scopo di aiutare i produttori a evitare errori correlati alle regole neverallow durante la personalizzazione. I numeri di regole usati qui corrispondono ad Android 5.1 e sono soggetti a modifiche in base alla release.

Regola 48: neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
Consulta la pagina man di ptrace. La funzionalità sys_ptrace concede la possibilità di ptrace qualsiasi processo, il che consente un gran controllo su altri processi e deve appartenere solo a componenti di sistema designati, descritti nella regola. La necessità di questa funzionalità indica spesso la presenza di elementi non destinati alle build rivolte agli utenti o di funzionalità non necessarie. Rimuovi il componente non necessario.

Regola 76: neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;
Questa regola ha lo scopo di impedire l'esecuzione di codice arbitrario sul sistema. Nello specifico, afferma che viene eseguito solo il codice su /system, il che consente garanzie di sicurezza grazie a meccanismi come l'avvio verificato. Spesso, la soluzione migliore quando si verifica un problema con questa neverallow regola è spostare il codice in violazione nella /system partizione.

Personalizzare SEPolicy in Android 8.0 e versioni successive

Questa sezione fornisce linee guida per i criteri SELinux del fornitore in Android 8.0 e versioni successive, inclusi dettagli su SEPolicy e sulle estensioni SEPolicy di Android Open Source Project (AOSP). Per ulteriori informazioni su come i criteri SELinux vengono mantenuti compatibili tra le partizioni e le versioni di Android, consulta Compatibilità.

Posizionamento delle norme

In Android 7.0 e versioni precedenti, i produttori di dispositivi potevano aggiungere criteri a BOARD_SEPOLICY_DIRS, inclusi criteri pensati per integrare i criteri AOSP su diversi tipi di dispositivi. In Android 8.0 e versioni successive, l'aggiunta di un criterio a BOARD_SEPOLICY_DIRS lo inserisce solo nell'immagine del fornitore.

In Android 8.0 e versioni successive, i criteri esistono nelle seguenti posizioni in AOSP:

  • system/sepolicy/public. Sono incluse le norme esportate per l'utilizzo nelle norme specifiche del fornitore. Tutto viene inserito nell'infrastruttura di compatibilità di Android 8.0. Le norme pubbliche sono destinate a essere mantenute nelle release, pertanto puoi includere qualsiasi cosa /public nei tuoi criteri personalizzati. Per questo motivo, il tipo di criteri che possono essere inseriti in /public è più limitato. Considerala l'API dei criteri esportata della piattaforma: tutto ciò che riguarda l'interfaccia tra /system e /vendor appartiene a questa sezione.
  • system/sepolicy/private. Include i criteri necessari per il funzionamento dell'immagine di sistema, ma di cui i criteri delle immagini del fornitore non devono essere a conoscenza.
  • system/sepolicy/vendor. Include le norme per i componenti che vanno in /vendor, ma esistono nella struttura della piattaforma di base (non nelle directory specifiche del dispositivo). Si tratta di un artefatto della distinta tra dispositivi e componenti globali del sistema di compilazione. A livello concettuale, fa parte delle norme specifiche per i dispositivi descritte di seguito.
  • device/manufacturer/device-name/sepolicy. Sono inclusi i criteri specifici per dispositivo. Sono incluse anche le personalizzazioni del dispositivo per le norme, che in Android 8.0 e versioni successive corrispondono alle norme per i componenti sull'immagine del fornitore.

In Android 11 e versioni successive, le partizioni system_ext e product possono includere anche criteri specifici per le partizioni. I criteri system_ext e product sono inoltre suddivisi in pubblici e privati e i fornitori possono utilizzare i criteri pubblici di system_ext e product, come i criteri di sistema.

  • SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS. Sono inclusi i criteri esportati per essere utilizzati nelle norme specifiche del fornitore. Installato nella partizione system_ext.
  • SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS. Include i criteri necessari per il funzionamento dell'immagine system_ext, ma di cui i criteri dell'immagine del fornitore non devono essere a conoscenza. Installato nella partizione system_ext.
  • PRODUCT_PUBLIC_SEPOLICY_DIRS. Sono inclusi i criteri esportati per essere utilizzati nelle norme specifiche del fornitore. Installato nella partizione del prodotto.
  • PRODUCT_PRIVATE_SEPOLICY_DIRS. Sono incluse le norme necessarie per il funzionamento dell'immagine del prodotto, ma le norme relative alle immagini del fornitore non devono essere prese in considerazione. Installato nella partizione del prodotto.
Nota:quando viene utilizzato GSI, le partizioni system_ext e product dell'OEM non vengono montate. Le regole nel file sepolicy del fornitore che utilizzano i criteri pubblici system_ext e del prodotto dell'OEM diventano NOP perché mancano le definizioni di tipo specifiche dell'OEM.
Nota: fai molta attenzione quando utilizzi le norme pubbliche system_ext e del prodotto. I criteri pubblici fungono da API esportate tra system_ext/product e il fornitore. I partner sono tenuti a gestire autonomamente i problemi di compatibilità.

Scenari di criteri supportati

Sui dispositivi lanciati con Android 8.0 e versioni successive, l'immagine del fornitore deve funzionare con l'immagine di sistema OEM e l'immagine di sistema AOSP di riferimento fornite da Google (e superare il CTS su questa immagine di riferimento). Questi requisiti garantiscono una separazione chiara tra il framework e il codice del fornitore. Questi dispositivi supportano i seguenti scenari.

estensioni solo immagine del fornitore

Esempio: aggiunta di un nuovo servizio a vndservicemanager dall'immagine del fornitore che supporta i processi dell'immagine del fornitore.

Come per i dispositivi lanciati con versioni precedenti di Android, aggiungi la personalizzazione specifica del dispositivo in device/manufacturer/device-name/sepolicy. Le nuove norme che regolano il modo in cui i componenti del fornitore interagiscono con (solo) altri componenti del fornitore devono coinvolgere tipi presenti solo in device/manufacturer/device-name/sepolicy. Le norme scritte qui consentono il funzionamento del codice del fornitore, non verranno aggiornate nell'ambito di un aggiornamento OTA solo del framework e sono presenti nelle norme combinate su un dispositivo con l'immagine di sistema AOSP di riferimento.

Supporto dell'immagine del fornitore per il funzionamento con AOSP

Esempio: aggiunta di un nuovo processo (registrato con hwservicemanager dall'immagine del fornitore) che implementa un HAL definito da AOSP.

Come per i dispositivi lanciati con versioni precedenti di Android, esegui la personalizzazione specifica del dispositivo in device/manufacturer/device-name/sepolicy. Il criterio esportato nell'ambito di system/sepolicy/public/ è disponibile per l'utilizzo e viene fornito nell'ambito delle norme del fornitore. I tipi e gli attributi delle norme pubbliche possono essere utilizzati nelle nuove regole che dettano le interazioni con i nuovi bit specifici del fornitore, rispettando le limitazioni neverallowfornite. Come per il caso solo del fornitore, le nuove norme qui non verranno aggiornate nel contesto di un OTA solo del framework e sono presenti nelle norme combinate su un dispositivo con l'immagine di sistema AOSP di riferimento.

Estensioni solo per immagini di sistema

Esempio: aggiunta di un nuovo servizio (registrato con servicemanager) a cui accedono solo altri processi dall'immagine di sistema.

Aggiungi questo criterio a system/sepolicy/private. Puoi aggiungere processi o oggetti aggiuntivi per attivare la funzionalità in un'immagine di sistema partner, a condizione che questi nuovi componenti non debbano interagire con i nuovi componenti dell'immagine del fornitore (in particolare, questi processi o oggetti devono funzionare completamente senza le norme dell'immagine del fornitore). Il criterio esportato da system/sepolicy/public è disponibile qui, così come per le estensioni solo con immagine del fornitore. Questo criterio fa parte dell'immagine di sistema e potrebbe essere aggiornato in un aggiornamento OTA solo del framework, ma non sarà presente se si utilizza l'immagine di sistema AOSP di riferimento.

Estensioni vendor-image che forniscono componenti AOSP estesi

Esempio: un nuovo HAL non AOSP da utilizzare per i client estesi che esistono anche nell'immagine di sistema AOSP (ad esempio un system_server esteso).

I criteri per l'interazione tra il sistema e il fornitore devono essere inclusi nella directory device/manufacturer/device-name/sepolicy fornita nella partizione del fornitore. È simile allo scenario precedente di aggiunta del supporto delle immagini del fornitore per il funzionamento con l'immagine AOSP di riferimento, tranne per il fatto che i componenti AOSP modificati potrebbero anche richiedere criteri aggiuntivi per funzionare correttamente con il resto della partizione di sistema (il che va bene purché abbiano ancora le etichette di tipo AOSP pubblico).

Le norme per l'interazione dei componenti AOSP pubblici con le estensioni solo per l'immagine di sistema devono essere in system/sepolicy/private.

Estensioni dell'immagine di sistema che accedono solo alle interfacce AOSP

Esempio: un nuovo processo di sistema non AOSP deve accedere a un HAL su cui si basa AOSP.

È simile all'esempio di estensione solo immagine del sistema, tranne per il fatto che i nuovi componenti di sistema possono interagire tramite l'interfacciasystem/vendor. I criteri per il nuovo componente di sistema devono essere inseriti in system/sepolicy/private, il che è accettabile a condizione che vengano utilizzati tramite un'interfaccia già stabilita da AOSP in system/sepolicy/public (ovvero i tipi e gli attributi richiesti per la funzionalità siano presenti). Sebbene il criterio possa essere incluso nel criterio specifico del dispositivo, non potrà utilizzare altri tipi di system/sepolicy/private o modificarsi (in alcun modo che influisca sui criteri) a seguito di un aggiornamento solo del framework. Il criterio può essere modificato in un aggiornamento OTA solo del framework, ma non sarà presente se si utilizza un'immagine di sistema AOSP (che non avrà nemmeno il nuovo componente di sistema).

Estensioni immagine del fornitore che pubblicano nuovi componenti di sistema

Esempio: aggiunta di un nuovo HAL non AOSP da utilizzare da parte di un processo client senza un analogo AOSP (e quindi richiede un proprio dominio).

Come nell'esempio di estensioni AOSP, le norme per le interazioni tra il sistema e il fornitore devono essere inserite nella directory device/manufacturer/device-name/sepolicy fornita nella partizione del fornitore (per garantire che le norme di sistema non siano a conoscenza di dettagli specifici del fornitore). Puoi aggiungere nuovi tipi pubblici che estendono il criterio in system/sepolicy/public. Questa operazione deve essere eseguita solo in aggiunta al criterio AOSP esistente, ovvero non rimuovere il criterio pubblico AOSP. I nuovi tipi pubblici possono quindi essere utilizzati per i criteri in system/sepolicy/private e in device/manufacturer/device-name/sepolicy.

Tieni presente che ogni aggiunta a system/sepolicy/public aggiunge complessità mostrando una nuova garanzia di compatibilità che deve essere monitorata in un file di mappatura ed è soggetta ad altre limitazioni. In system/sepolicy/public è possibile aggiungere solo nuovi tipi e le regole allow corrispondenti. Gli attributi e altre istruzioni del criterio non sono supportati. Inoltre, i nuovi tipi pubblici non possono essere utilizzati per etichettare direttamente gli oggetti nel criterio /vendor.

Scenari di criteri non supportati

I dispositivi lanciati con Android 8.0 e versioni successive non supportano lo scenario e gli esempi di norme riportati di seguito.

Estensioni aggiuntive all'immagine di sistema che richiedono l'autorizzazione per i nuovi componenti dell'immagine del fornitore dopo un aggiornamento OTA solo del framework

Esempio: nella prossima release di Android viene aggiunto un nuovo processo di sistema non AOSP che richiede un proprio dominio e deve accedere a un nuovo HAL non AOSP.

Interazione simile a quella tra componenti del sistema e del fornitore (non AOSP) nuovi, tranne per il fatto che il nuovo tipo di sistema viene introdotto in un OTA solo del framework. Sebbene il nuovo tipo possa essere aggiunto al criterio in system/sepolicy/public, il criterio del fornitore esistente non è a conoscenza del nuovo tipo in quanto monitora solo le norme pubbliche del sistema Android 8.0. AOSP gestisce questo problema esponendo le risorse fornite dal fornitore tramite un attributo (ad esempio, l'attributo hal_foo), ma poiché le estensioni dei partner degli attributi non sono supportate in system/sepolicy/public, questo metodo non è disponibile per le norme del fornitore. L'accesso deve essere fornito da un tipo pubblico esistente in precedenza.

Esempio: una modifica a un processo di sistema (AOSP o non AOSP) deve cambiare il modo in cui interagisce con il nuovo componente del fornitore non AOSP.

I criteri nell'immagine di sistema devono essere scritti senza conoscenza di personalizzazioni specifiche del fornitore. Le norme relative a interfacce specifiche in AOSP vengono quindi esposte tramite attributi in system/sepolicy/public in modo che le norme del fornitore possano attivare le norme di sistema future che utilizzano questi attributi. Tuttavia, le estensioni degli attributi in system/sepolicy/public non sono supportate, pertanto tutte le norme che regolano l'interazione dei componenti di sistema con i nuovi componenti del fornitore (e che non sono gestite dagli attributi già presenti in AOSP system/sepolicy/public) devono essere in device/manufacturer/device-name/sepolicy. Ciò significa che i tipi di sistema non possono modificare l'accesso consentito ai tipi di fornitori nell'ambito di un aggiornamento OTA solo del framework.