Questo articolo descrive in che modo Android gestisce i problemi di compatibilità dei criteri con gli aggiornamenti OTA della piattaforma, in cui le nuove impostazioni SELinux della piattaforma possono essere diverse da quelle SELinux del fornitore precedente.
La progettazione dei criteri SELinux basati su Treble prende in considerazione una distinzione binaria tra i criteri della piattaforma e quelli del fornitore. Lo schema diventa più complicato se le partizioni del fornitore generano dipendenze, ad esempio platform
< vendor
< oem
.
In Android 8.0 e versioni successive, il criterio globale SELinux è suddiviso in componenti pubblici e privati. I componenti pubblici sono costituiti dal criterio e dall'infrastruttura associata, che sono garantiti per essere disponibili per una versione della piattaforma. Questo criterio verrà mostrato agli autori dei criteri del fornitore per consentire loro di creare un file di criteri del fornitore che, se combinato con il criterio fornito dalla piattaforma, genera un criterio completamente funzionale per un dispositivo.
- Per il controllo della versione, i criteri pubblici della piattaforma esportati verranno scritti come attributi.
- Per facilitare la scrittura delle norme, i tipi esportati verranno trasformati in attributi con versione nell'ambito del processo di creazione delle norme. I tipi pubblici possono essere utilizzati anche direttamente nelle decisioni di etichettatura fornite dai file dei contesti del fornitore.
Android gestisce una mappatura tra i tipi concreti esportati nel criterio della piattaforma e gli attributi con versione corrispondente per ogni versione della piattaforma. In questo modo, quando gli oggetti vengono etichettati con un tipo, il comportamento garantito dalle norme relative alla piattaforma pubblica in una versione precedente non viene interrotto. Questa mappatura viene mantenuta aggiornando un file di mappatura per ogni versione della piattaforma, che conserva le informazioni sull'appartenenza degli attributi per ogni tipo esportato nelle norme pubbliche.
Proprietà e etichettatura degli oggetti
Quando personalizzi i criteri in Android 8.0 e versioni successive, la proprietà deve essere chiaramente definita per ogni oggetto per mantenere separati i criteri della piattaforma e del fornitore. Ad esempio, se il fornitore etichetta /dev/foo
e la piattaforma etichetta /dev/foo
in un OTA successivo, il comportamento sarà indefinito. Per SELinux, si tratta di una collisione di etichettatura. Il nodo del dispositivo può avere una sola etichetta che si risolve nell'etichetta applicata per ultima. Ne consegue che:
- I processi che hanno bisogno di accedere all'etichetta applicata senza successo perderanno l'accesso alla risorsa.
- I processi che ottengono l'accesso al file potrebbero non funzionare perché è stato creato il nodo del dispositivo sbagliato.
Le proprietà di sistema presentano anche potenziali collisioni di nomi che potrebbero comportare un comportamento non definito sul sistema (nonché per l'etichettatura SELinux). Le collisioni tra le etichette della piattaforma e del fornitore possono verificarsi per qualsiasi oggetto con un'etichetta SELinux, tra cui proprietà, servizi, processi, file e socket. Per evitare questi problemi, definisci chiaramente la proprietà di questi oggetti.
Oltre alle collisioni delle etichette, possono verificarsi anche collisioni dei nomi di tipo/attributo SELinux. Un conflitto di nomi di tipo/attributo comporterà sempre un errore del compilatore delle norme.
Spazio dei nomi di tipo/attributo
SELinux non consente più dichiarazioni dello stesso tipo/attributo. La compilazione del criterio con dichiarazioni duplicate non andrà a buon fine. Per evitare collisioni di nomi di tipi e attributi, tutte le dichiarazioni del fornitore devono avere un ambito iniziando con vendor_
.
type foo, domain; → type vendor_foo, domain;
Proprietà del sistema e proprietà dell'etichettatura dei processi
Il modo migliore per evitare collisioni di etichette è utilizzare gli spazi dei nomi delle proprietà. Per identificare facilmente le proprietà della piattaforma ed evitare conflitti di nomi durante la ridenominazione o l'aggiunta di proprietà della piattaforma esportate, assicurati che tutte le proprietà del fornitore abbiano i propri prefissi:
Tipo di proprietà | Prefissi accettabili |
---|---|
control properties | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor.
|
read-writable | vendor. |
di sola lettura | ro.vendor. ro.boot. ro.hardware.
|
persistente | persist.vendor. |
I fornitori possono continuare a utilizzare ro.boot.*
(che proviene dal cmdline del kernel) e ro.hardware.*
(una proprietà ovviamente correlata all'hardware).
Tutti i servizi del fornitore nei file init rc devono avere vendor.
per i servizi nei file init rc delle partizioni non di sistema. Regole simili vengono applicate alle etichette SELinux per le proprietà del fornitore (vendor_
per le proprietà del fornitore).
Proprietà dei file
Impedire le collisioni per i file è complicato perché le norme della piattaforma e del fornitore forniscono comunemente etichette per tutti i file system. A differenza della denominazione dei tipi, la scelta del nome dei file non è praticabile poiché molti di essi vengono creati dal kernel. Per evitare questi conflitti, segui le indicazioni di denominazione per i filesystem riportate in questa sezione. Per Android 8.0, si tratta di consigli senza applicazione tecnica. In futuro, questi consigli verranno applicati dalla Vendor Test Suite (VTS).
Sistema (/system)
Solo l'immagine di sistema deve fornire le etichette per i componenti /system
tramite file_contexts
, service_contexts
e così via. Se le etichette per i componenti /system
vengono aggiunte nel criterio /vendor
, un aggiornamento OTA solo del framework potrebbe non essere possibile.
Fornitore (/vendor)
Il criterio SELinux di AOSP etichetta già parti della partizione vendor
con cui la piattaforma interagisce, il che consente di scrivere regole SELinux per i processi della piattaforma in modo che possano comunicare e/o accedere a parti della partizione vendor
. Esempi:
Percorso /vendor |
Etichetta fornita dalla piattaforma | Processi della piattaforma a seconda dell'etichetta |
---|---|---|
/vendor(/.*)?
|
vendor_file
|
Tutti i client HAL nel framework, ueventd e così via.
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat , appdomain e così via.
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat , installd , idmap e così via.
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server , zygote , idmap e così via.
|
Di conseguenza, devono essere seguite regole specifiche (applicate tramite
neverallows
) per etichettare file aggiuntivi nella partizione vendor
:
vendor_file
deve essere l'etichetta predefinita per tutti i file della partizionevendor
. Il criterio della piattaforma lo richiede per accedere alle implementazioni HAL passthrough.- Tutti i nuovi
exec_types
aggiunti nella partizionevendor
tramite SEPolicy del fornitore devono avere l'attributovendor_file_type
. Questo viene applicato tramite neverallows. - Per evitare conflitti con i futuri aggiornamenti della piattaforma/del framework, evita di etichettare
file diversi da
exec_types
nella partizionevendor
. - Tutte le dipendenze delle librerie per gli HAL dello stesso processo identificati da AOSP devono essere
etichettate come
same_process_hal_file.
Procfs (/proc)
I file in /proc
possono essere etichettati utilizzando solo l'etichetta genfscon
. In Android 7.0, sia il criterio della
piattaforma
che quello del fornitore
utilizzavano genfscon
per etichettare i file in procfs
.
Consiglio:utilizza solo le etichette delle norme della piattaforma /proc
.
Se i processi vendor
devono accedere ai file in /proc
che attualmente sono etichettati con l'etichetta predefinita (proc
), i criteri del fornitore non devono etichettarli esplicitamente, ma devono utilizzare il tipo generico proc
per aggiungere regole per i domini del fornitore. In questo modo, gli aggiornamenti della piattaforma possono adattarsi alle future interfacce del kernel esposte tramite procfs
e etichettarle esplicitamente in base alle esigenze.
Debugfs (/sys/kernel/debug)
Debugfs
può essere etichettato sia in file_contexts
che in
genfscon
. Da Android 7.0 ad Android 10, sono supportate sia l'etichetta della piattaforma sia quella del fornitoredebugfs
.
In Android 11, non è possibile accedere o montare debugfs
sui dispositivi di produzione. I produttori di dispositivi devono
rimuovere debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Tracefs
può essere etichettato sia in file_contexts
che in
genfscon
. In Android 7.0, sono presenti solo le etichette della piattaforma
tracefs
.
Consiglio:solo la piattaforma può etichettare tracefs
.
Sysfs (/sys)
I file in /sys
possono essere etichettati utilizzando sia file_contexts
che genfscon
. In Android 7.0, sia la piattaforma sia il fornitore utilizzano
genfscon
per etichettare i file in sysfs
.
Consiglio:la piattaforma potrebbe etichettare i nodi sysfs
che non sono specifici per dispositivo. In caso contrario, solo il fornitore può etichettare i file.
tmpfs (/dev)
I file in /dev
potrebbero essere etichettati in file_contexts
. In Android 7.0, i file delle etichette della piattaforma e del fornitore sono disponibili qui.
Consiglio:il fornitore può etichettare solo i file in /dev/vendor
(ad es. /dev/vendor/foo
,/dev/vendor/socket/bar
).
Rootfs (/)
I file in /
potrebbero essere etichettati in file_contexts
. In Android
7.0, i file delle etichette della piattaforma e del fornitore sono disponibili qui.
Consiglio:solo il sistema può etichettare i file in /
.
Dati (/data)
I dati vengono etichettati tramite una combinazione di file_contexts
e
seapp_contexts
.
Consiglio:non consentire l'etichettatura del fornitore al di fuori di
/data/vendor
. Solo la piattaforma può etichettare altre parti di
/data
.
Versione delle etichette Genfs
A partire dal livello API del fornitore 202504, le etichette SELinux più recenti assegnate con genfscon
in system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil
sono facoltative per le partizioni del fornitore precedenti. In questo modo, le partizioni del fornitore precedenti possono mantenere l'implementazione esistente di SEPolicy. Questo
viene controllato dalla variabile Makefile BOARD_GENFS_LABELS_VERSION
memorizzata in
/vendor/etc/selinux/genfs_labels_version.txt
.
Esempio:
-
Nel livello API del fornitore 202404, il nodo
/sys/class/udc
è etichettato comesysfs
per impostazione predefinita. -
A partire dal livello API del fornitore 202504,
/sys/class/udc
è etichettato comesysfs_udc
.
Tuttavia, /sys/class/udc
potrebbe essere in uso dalle partizioni del fornitore che utilizzano il livello API 202404, con l'etichetta sysfs
predefinita o con un'etichetta specifica del fornitore. Se /sys/class/udc
viene etichettato come sysfs_udc
in modo incondizionato, la compatibilità con queste partizioni del fornitore potrebbe essere compromessa. Se selezioni BOARD_GENFS_LABELS_VERSION
, la piattaforma continuerà a utilizzare le etichette e le autorizzazioni precedenti per le partizioni del fornitore precedenti.
BOARD_GENFS_LABELS_VERSION
può essere maggiore o uguale al livello dell'API del fornitore. Ad esempio, le partizioni del fornitore che utilizzano il livello API 202404 possono impostare BOARD_GENFS_LABELS_VERSION
su 202504 per adottare le nuove etichette introdotte in 202504. Consulta l'elenco di
etichette genfs specifiche per 202504.
Quando etichetta i nodi genfscon
, la piattaforma deve prendere in considerazione le partizioni dei fornitori meno recenti e, se necessario, implementare meccanismi di riserva per la compatibilità. La piattaforma può utilizzare librerie solo per la piattaforma per eseguire query sulla versione delle etichette genfs.
-
Per gli annunci nativi, utilizza
libgenfslabelsversion
. Consultagenfslabelsversion.h
per il file di intestazione dilibgenfslabelsversion
. -
In Java, utilizza
android.os.SELinux.getGenfsLabelsVersion()
.
Attributi di compatibilità
Il criterio SELinux è un'interazione tra i tipi di origine e di destinazione per classi di oggetti e autorizzazioni specifiche. Ogni oggetto (processi, file e così via) interessato dall'attributo SELinux può avere un solo tipo, ma questo tipo può avere più attributi.
Le norme sono scritte principalmente in termini di tipi esistenti:
allow source_type target_type:target_class permission(s);
Questo funziona perché le norme sono state scritte tenendo conto di tutti i tipi di contenuti. Tuttavia, se i criteri del fornitore e della piattaforma utilizzano tipi specifici e l'etichetta di un oggetto specifico cambia solo in uno di questi criteri, l'altro potrebbe contenere criteri che hanno acquisito o perso l'accesso precedentemente utilizzato. Ad esempio:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Potrebbe essere modificato in:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Sebbene le norme del fornitore rimangano invariate, il v_domain
perderà l'accesso a causa della mancanza di norme per il nuovo tipo di sysfs_A
.
Definendo un criterio in termini di attributi, possiamo assegnare all'oggetto sottostante un tipo che abbia un attributo corrispondente al criterio sia per la piattaforma sia per il codice del fornitore. Questo può essere fatto per tutti i tipi per creare efficacemente un attribute-policy in cui i tipi concreti non vengono mai utilizzati. In pratica, questo è necessario solo per le parti delle norme che si sovrappongono tra la piattaforma e il fornitore, che sono definite e fornite come norme pubbliche della piattaforma che vengono create nell'ambito delle norme del fornitore.
La definizione delle norme pubbliche come attributi con versione soddisfa due scopi di compatibilità delle norme:
- Assicurati che il codice del fornitore continui a funzionare dopo l'aggiornamento della piattaforma. Ottenuta aggiungendo attributi a tipi concreti per gli oggetti corrispondenti a quelli su cui si basava il codice del fornitore, preservando l'accesso.
- Possibilità di ritirare i criteri. Questo risultato viene ottenuto delineando chiaramente gli insiemi di criteri in attributi che possono essere rimossi non appena la versione a cui corrispondono non è più supportata. Lo sviluppo può continuare nella piattaforma, sapendo che il vecchio criterio è ancora presente nel criterio del fornitore e verrà rimosso automaticamente quando/se verrà eseguito l'upgrade.
Scritturabilità dei criteri
Per raggiungere l'obiettivo di non richiedere la conoscenza di modifiche specifiche delle versioni per lo sviluppo delle norme, Android 8.0 include una mappatura tra i tipi di norme pubbliche della piattaforma e i relativi attributi. Il tipo foo
è mappato
all'attributo foo_vN
, dove N
è la
versione di destinazione. vN
corrisponde alla variabile di compilazione PLATFORM_SEPOLICY_VERSION
ed è del tipo MM.NN
, dove MM
corrisponde al numero dell'SDK della piattaforma e NN
è una versione specifica per la piattaforma sepolicy.
Gli attributi nelle norme pubbliche non sono sottoposti a controllo della versione, ma esistono come API su cui possono essere sviluppate le norme della piattaforma e del fornitore per mantenere stabile l'interfaccia tra le due partizioni. Sia gli autori dei criteri della piattaforma sia quelli dei fornitori possono continuare a scrivere i criteri come sono attualmente.
Le norme pubbliche della piattaforma esportate come allow source_foo target_bar:class
perm;
sono incluse nelle norme del fornitore. Durante la
compilazione (che include la
versione corrispondente), viene trasformato nel criterio che verrà inviato alla
parte del fornitore del dispositivo (mostrata nel linguaggio intermedio
comune (CIL) trasformato):
(allow source_foo_vN target_bar_vN (class (perm)))
Poiché le norme del fornitore non sono mai in anticipo rispetto alla piattaforma, non è necessario preoccuparsi delle versioni precedenti. Tuttavia, le norme della piattaforma devono sapere quanto sono lontane le norme del fornitore, includere gli attributi per i relativi tipi e impostare le norme corrispondenti agli attributi con versione.
Differenze nelle norme
La creazione automatica degli attributi aggiungendo _vN
alla fine
di ogni tipo non ha alcun effetto senza la mappatura degli attributi ai tipi tra le differenze
tra le versioni. Android gestisce una mappatura tra le versioni per gli attributi e una mappatura dei tipi a questi attributi. Questo viene fatto nei file di mappatura sopra menzionati con istruzioni, ad esempio (CIL):
(typeattributeset foo_vN (foo))
Upgrade della piattaforma
La sezione seguente illustra gli scenari per gli upgrade della piattaforma.
Stessi tipi
Questo scenario si verifica quando un oggetto non modifica le etichette nelle versioni dei criteri.
Questo vale per i tipi di origine e di destinazione e può essere visualizzato con/dev/binder
, che è etichettato come binder_device
in tutte le release. Viene rappresentato nel criterio trasformato come:
binder_device_v1 … binder_device_vN
Quando esegui l'upgrade da v1
a v2
, le norme della piattaforma devono contenere:
type binder_device; -> (type binder_device) (in CIL)
Nel file di mappatura v1 (CIL):
(typeattributeset binder_device_v1 (binder_device))
Nel file di mappatura v2 (CIL):
(typeattributeset binder_device_v2 (binder_device))
Nelle norme relative ai fornitori v1 (CIL):
(typeattribute binder_device_v1) (allow binder_device_v1 …)
Nelle norme relative ai fornitori v2 (CIL):
(typeattribute binder_device_v2) (allow binder_device_v2 …)
Nuovi tipi
Questo scenario si verifica quando la piattaforma ha aggiunto un nuovo tipo, il che può accadere quando vengono aggiunte nuove funzionalità o durante il rafforzamento delle norme.
- Nuova funzionalità. Quando il tipo etichetta un oggetto che non esisteva precedentemente (ad esempio un nuovo processo di servizio), il codice del fornitore non interagiva direttamente con l'oggetto, pertanto non esiste alcun criterio corrispondente. Il nuovo attributo corrispondente al tipo non ha un attributo nella versione precedente e quindi non richiede una voce nel file di mappatura che ha come target quella versione.
- Rigorosa applicazione delle norme. Quando il tipo rappresenta un rafforzamento delle norme, il nuovo attributo del tipo deve riagganciarsi a una catena di attributi corrispondente a quella precedente (simile all'esempio precedente in cui
/sys/A
passa dasysfs
asysfs_A
). Il codice del fornitore si basa su una regola che consente l'accesso asysfs
e deve includere questa regola come attributo del nuovo tipo.
Quando esegui l'upgrade da v1
a v2
, le norme della piattaforma devono contenere:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
Nel file di mappatura v1 (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
Nel file di mappatura v2 (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
Nelle norme relative ai fornitori v1 (CIL):
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Nelle norme relative ai fornitori v2 (CIL):
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Tipi rimossi
Questo scenario (raro) si verifica quando viene rimosso un tipo, il che può accadere quando l'oggetto di base:
- Rimane, ma riceve un'etichetta diversa.
- Viene rimosso dalla piattaforma.
Durante l'allentamento delle norme, un tipo viene rimosso e all'oggetto etichettato con quel tipo viene assegnata un'etichetta diversa esistente. Si tratta di una combinazione di mappature degli attributi: il codice del fornitore deve essere ancora in grado di accedere all'oggetto sottostante tramite l'attributo che possedeva in precedenza, ma il resto del sistema ora deve essere in grado di accedervi con il nuovo attributo.
Se l'attributo a cui è stato eseguito il passaggio è nuovo, la ridefinizione dell'etichetta è la stessa che nel caso del nuovo tipo, tranne per il fatto che, se viene utilizzata un'etichetta esistente, l'aggiunta del nuovo tipo dell'attributo precedente causerebbe l'accesso a nuovi oggetti anche etichettati con questo tipo. Questo è essenzialmente ciò che viene fatto dalla piattaforma ed è considerato un compromesso accettabile per mantenere la compatibilità.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Esempio di versione 1: tipi di aggregazione (rimozione di sysfs_A)
Quando esegui l'upgrade da v1
a v2
, le norme della piattaforma devono contenere:
type sysfs; (type sysfs) (in CIL)
Nel file di mappatura v1 (CIL):
(typeattributeset sysfs_v1 (sysfs)) (type sysfs_A) # in case vendors used the sysfs_A label on objects (typeattributeset sysfs_A_v1 (sysfs sysfs_A))
Nel file di mappatura v2 (CIL):
(typeattributeset sysfs_v2 (sysfs))
Nelle norme relative ai fornitori v1 (CIL):
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
Nelle norme relative ai fornitori v2 (CIL):
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Esempio di versione 2: rimozione completa (tipo foo)
Quando esegui l'upgrade da v1
a v2
, le norme della piattaforma devono contenere:
# nothing - we got rid of the type
Nel file di mappatura v1 (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
Nel file di mappatura v2 (CIL):
# nothing - get rid of it
Nelle norme relative ai fornitori v1 (CIL):
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
Nelle norme relative ai fornitori v2 (CIL):
(typeattribute sysfs_v2) (allow sysfs_v2 …)
Nuovo corso/nuove autorizzazioni
Questo scenario si verifica quando un upgrade della piattaforma introduce nuovi componenti delle norme
che non esistono nelle versioni precedenti. Ad esempio, quando Android ha aggiunto il gestore degli oggetti servicemanager
che ha creato le autorizzazioni di aggiunta, ricerca ed elenco, i demoni del fornitore che volevano registrarsi con servicemanager
non disponevano delle autorizzazioni necessarie. In Android 8.0, solo i criteri della piattaforma possono aggiungere nuove classi e autorizzazioni.
Per consentire a tutti i domini che potrebbero essere stati creati o estesi in base ai criteri del fornitore di utilizzare la nuova classe senza ostacoli, i criteri della piattaforma devono includere una regola simile alla seguente:
allow {domain -coredomain} *:new_class perm;
Potrebbe anche essere necessario un criterio che consenta l'accesso per tutti i tipi di interfaccia (criteri pubblici), per assicurarsi che l'immagine del fornitore ottenga l'accesso. Se ne risulta un criterio di sicurezza inaccettabile (come potrebbe accadere con le modifiche di ServiceManager), potrebbe essere forzato un upgrade del fornitore.
Corso/autorizzazioni rimossi
Questo scenario si verifica quando viene rimosso un gestore di oggetti (ad esempio il gestore di oggetti ZygoteConnection
) e non dovrebbe causare problemi. La classe e le autorizzazioni del gestore degli oggetti potrebbero rimanere definite nel criterio finché la versione del fornitore non le utilizza più. Per farlo, devi aggiungere le definizioni al file di mappatura corrispondente.
Personalizzazione del fornitore per tipi nuovi/rinominati
I nuovi tipi di fornitori sono al centro dello sviluppo delle norme relative ai fornitori in quanto sono necessari per descrivere nuovi processi, binari, dispositivi, sottosistemi e dati archiviati. Pertanto, è fondamentale consentire la creazione di tipi definiti dal fornitore.
Poiché il criterio del fornitore è sempre quello più vecchio sul dispositivo, non è necessario
convertire automaticamente tutti i tipi di fornitori in attributi nel criterio. La piattaforma
non si basa su nulla che sia etichettato nelle norme del fornitore perché non ne ha conoscenza; tuttavia, fornirà gli attributi e i tipi pubblici che utilizza per interagire con gli oggetti etichettati con questi tipi (ad esempio
domain
, sysfs_type
e così via). Affinché la piattaforma continui a interagire correttamente con questi oggetti, gli attributi e i tipi devono essere applicati in modo appropriato e potrebbe essere necessario aggiungere regole specifiche ai domini personalizzabili (ad esempio init
).
Modifiche agli attributi per Android 9
I dispositivi che eseguono l'upgrade ad Android 9 possono utilizzare i seguenti attributi, ma i dispositivi avviati con Android 9 non devono farlo.
Attributi degli autori di violazioni
Android 9 include questi attributi relativi al dominio:
data_between_core_and_vendor_violators
. Attributo per tutti i domini che violano il requisito di non condividere file in base al percorso travendor
ecoredomains
. I processi della piattaforma e del fornitore non devono utilizzare file su disco per comunicare (ABI instabile). Consiglio:- Il codice fornitore deve utilizzare
/data/vendor
. - Il sistema non deve utilizzare
/data/vendor
.
- Il codice fornitore deve utilizzare
system_executes_vendor_violators
. Attributo per tutti i domini di sistema (tranneinit
eshell domains
) che violano il requisito di non eseguire i binari del fornitore. L'esecuzione dei file binari del fornitore ha un'API instabile. La piattaforma non deve eseguire direttamente i binari del fornitore. Consiglio:- Queste dipendenze della piattaforma dai binari del fornitore devono essere dietro le HAL HIDL.
OPPURE
- I
coredomains
che richiedono l'accesso ai binari del fornitore devono essere trasferiti nella partizione del fornitore e quindi non essere piùcoredomain
.
- Queste dipendenze della piattaforma dai binari del fornitore devono essere dietro le HAL HIDL.
Attributi non attendibili
Le app non attendibili che ospitano codice arbitrario non devono avere accesso ai servizi HwBinder, tranne quelli considerati sufficientemente sicuri per l'accesso da queste app (vedi i servizi sicuri di seguito). I due motivi principali sono:
- I server HwBinder non eseguono l'autenticazione del client perché al momento HIDL non espone le informazioni sull'UID dell'autore della chiamata. Anche se HIDL esponesse questi dati, molti servizi HwBinder operano a un livello inferiore a quello delle app (ad esempio, HAL) o non devono fare affidamento sull'identità dell'app per l'autorizzazione. Pertanto, per sicurezza, l'impostazione predefinita è che ogni servizio HwBinder tratta tutti i suoi clienti come ugualmente autorizzati a eseguire le operazioni offerte dal servizio.
- I server HAL (un sottoinsieme di servizi HwBinder) contengono codice con un tasso di incidenza più elevato di problemi di sicurezza rispetto ai componenti
system/core
e hanno accesso ai livelli inferiori dello stack (fino all'hardware), aumentando così le opportunità per aggirare il modello di sicurezza di Android.
Servizi sicuri
I servizi sicuri includono:
same_process_hwservice
. Questi servizi (per definizione) vengono eseguiti nel processo del client e hanno quindi lo stesso accesso del dominio del client in cui viene eseguito il processo.coredomain_hwservice
. Questi servizi non presentano i rischi associati al motivo 2.hal_configstore_ISurfaceFlingerConfigs
. Questo servizio è progettato specificamente per essere utilizzato da qualsiasi dominio.hal_graphics_allocator_hwservice
. Queste operazioni sono offerte anche dal servizio Bindersurfaceflinger
, a cui le app sono autorizzate ad accedere.hal_omx_hwservice
. Si tratta di una versione HwBinder del servizio Bindermediacodec
, a cui le app sono autorizzate ad accedere.hal_codec2_hwservice
. Si tratta di una versione più recente dihal_omx_hwservice
.
Attributi utilizzabili
Tutti i hwservices
non considerati sicuri hanno l'attributo
untrusted_app_visible_hwservice
. I server HAL corrispondenti hanno
l'attributo untrusted_app_visible_halserver
. I dispositivi avviati con Android 9 NON DEVONO utilizzare nessuno degli attributi untrusted
.
Consiglio:
- Le app non attendibili devono invece comunicare con un servizio di sistema che comunica con l'HAL HIDL del fornitore. Ad esempio, le app possono comunicare con
binderservicedomain
, quindimediaserver
(che è unbinderservicedomain
) a sua volta comunica conhal_graphics_allocator
.OPPURE
- Le app che richiedono l'accesso diretto agli HAL
vendor
devono avere il proprio dominio sepolicy definito dal fornitore.
Test degli attributi dei file
Android 9 include test di compilazione che assicurano che tutti i file in determinate posizioni abbiano gli attributi appropriati (ad esempio, tutti i file in sysfs
abbiano l'attributo sysfs_type
richiesto).
Norme relative alla piattaforma e alle norme pubbliche
Le norme pubbliche della piattaforma sono il nucleo della conformità al modello di architettura di Android 8.0 senza semplicemente mantenere l'unione delle norme della piattaforma della versione 1 e 2. I fornitori sono esposti a un sottoinsieme di norme della piattaforma che contiene tipi e attributi utilizzabili e regole relative a questi tipi e attributi, che poi diventano parte delle norme del fornitore (ovvero vendor_sepolicy.cil
).
I tipi e le regole vengono tradotti automaticamente nel criterio generato dal fornitore
in attribute_vN
in modo che tutti i tipi forniti dalla piattaforma
siano attributi con versione (tuttavia gli attributi non sono con versione). La piattaforma è responsabile della mappatura dei tipi concreti forniti negli attributi appropriati per garantire che i criteri del fornitore continuino a funzionare e che le regole fornite per una determinata versione siano incluse. La combinazione di norme pubbliche della piattaforma e norme del fornitore soddisfa l'obiettivo del modello di architettura di Android 8.0 di consentire build indipendenti della piattaforma e del fornitore.
Mappatura alle catene di attributi
Quando utilizzi gli attributi per eseguire la mappatura alle versioni dei criteri, un tipo viene mappato a un attributo o a più attributi, garantendo che gli oggetti etichettati con il tipo siano accessibili tramite gli attributi corrispondenti ai relativi tipi precedenti.
Mantenere un obiettivo di occultamento delle informazioni sulla versione all'autore del criterio significa
generare automaticamente gli attributi con versione e assegnarli ai
tipi appropriati. Nel caso comune dei tipi statici, è semplice:type_foo
corrisponde a type_foo_v1
.
Per una modifica dell'etichetta di un oggetto, ad esempio sysfs
→ sysfs_A
o
mediaserver
→ audioserver
, la creazione di questa mappatura è
non banale (ed è descritta negli esempi precedenti). I responsabili dei criteri della piattaforma devono determinare come creare la mappatura nei punti di transizione per gli oggetti, il che richiede di comprendere la relazione tra gli oggetti e le etichette assegnate e di determinare quando si verifica. Per la compatibilità con le versioni precedenti, questa complessità deve essere gestita a livello di piattaforma, che è l'unica partizione che può essere aggiornata.
Version uprevs
Per semplicità, la piattaforma Android rilascia una versione di sepolicy quando viene creato un nuovo ramo di release. Come descritto sopra, il numero di versione è contenuto in
PLATFORM_SEPOLICY_VERSION
ed è del tipo MM.nn
,
dove MM
corrisponde al valore dell'SDK e nn
è un
valore privato mantenuto in /platform/system/sepolicy.
Per
esempio, 19.0
per Kitkat, 21.0
per Lollipop,
22.0
per Lollipop-MR1 23.0
per Marshmallow,
24.0
per Nougat, 25.0
per Nougat-MR1,
26.0
per Oreo, 27.0
per Oreo-MR1 e
28.0
per Android 9.
Le stime non sono sempre numeri interi. Ad esempio, se un aggiornamento MR a una versione richiede una modifica incompatibile in system/sepolicy/public
, ma non un aggiornamento dell'API, la versione sepolicy potrebbe essere vN.1
. La versione presente in un ramo di sviluppo è una versione da non utilizzare nei dispositivi in commercio 10000.0
.
Android potrebbe ritirare la versione più vecchia durante l'upgrade. Per avere indicazioni su quando ritirare una versione, Android potrebbe raccogliere il numero di dispositivi con criteri del fornitore che eseguono quella versione di Android e che continuano a ricevere aggiornamenti importanti della piattaforma. Se il numero è inferiore a una determinata soglia, la versione è ritirata.
Impatto sul rendimento di più attributi
Come descritto in https://github.com/SELinuxProject/cil/issues/9, un numero elevato di attributi assegnati a un tipo comporta problemi di prestazioni in caso di mancata corrispondenza della cache dei criteri.
È stato confermato che si tratta di un problema in Android, pertanto sono state apportate modifiche ad Android 8.0 per rimuovere gli attributi aggiunti al criterio dal compilatore dei criteri, nonché gli attributi inutilizzati. Queste modifiche hanno risolto le regressioni del rendimento.
Norme pubbliche di system_ext e relative ai prodotti
A partire da Android 11, le partizioni system_ext
e product
possono esportare i tipi pubblici designati nella partizione del fornitore. Come le norme pubbliche della piattaforma, il fornitore utilizza tipi e regole tradotti automaticamente negli attributi con versione, ad esempio da type
a
type_N
, dove N
è la versione
della piattaforma su cui è basata la partizione del fornitore.
Quando le partizioni system_ext
e product
si basano sulla stessa versione della piattaforma
N
, il sistema di compilazione genera file di mappatura di base per
system_ext/etc/selinux/mapping/N.cil
e
product/etc/selinux/mapping/N.cil
, che contengono mappature di identità da type
a type_N
. Il fornitore può accedere a type
con l'attributo versione type_N
.
Se vengono aggiornate solo le partizioni system_ext
e product
, ad esempio da N
a N+1
(o versioni successive), mentre il fornitore rimane su N
, il fornitore potrebbe perdere l'accesso ai tipi di partizioni system_ext
e product
. Per evitare interruzioni, le partizioni system_ext
e product
devono fornire file di mappatura da tipi concreti agli attributi type_N
. Ogni partner è responsabile della gestione dei file di mappatura, se supporta il fornitore N
con N+1
(o versioni successive) e le partizioni system_ext
e product
.
A tal fine, i partner sono tenuti a:
- Copia i file di mappatura di base generati dalle partizioni
N
system_ext
eproduct
alla relativa struttura ad albero di origine. - Modifica i file di mappatura in base alle esigenze.
-
Installa i
file di mappatura nelle partizioni
system_ext
eproduct
diN+1
(o versioni successive).
Ad esempio, supponiamo che N
system_ext
abbia un tipo pubblico chiamato foo_type
. Quindi system_ext/etc/selinux/mapping/N.cil
nella partizione N
system_ext
avrà il seguente aspetto:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
Se bar_type
viene aggiunto a N+1
system_ext e se bar_type
deve essere mappato a foo_type
per il fornitore N
, N.cil
può essere aggiornato da
(typeattributeset foo_type_N (foo_type))
to
(typeattributeset foo_type_N (foo_type bar_type))
e poi installato nella partizione N+1
system_ext.
Il fornitore di N
può continuare ad accedere a foo_type
e bar_type
di N+1
system_ext.
Etichettatura dei contesti SELinux
Per supportare la distinzione tra le norme sepolicy della piattaforma e del fornitore, il sistema genera i file di contesto SELinux in modo diverso per mantenerli separati.
Contesti dei file
Android 8.0 ha introdotto le seguenti modifiche per file_contexts
:
- Per evitare un sovraccarico di compilazione aggiuntivo sul dispositivo durante l'avvio,
file_contexts
non esiste più nella forma binaria. ma sono file di testo di espressioni regolari leggibili come{property, service}_contexts
(come prima della versione 7.0). - I
file_contexts
sono suddivisi in due file:plat_file_contexts
- Piattaforma Android
file_context
che non ha etichette specifiche per il dispositivo, ad eccezione delle parti della partizione/vendor
che devono essere etichettate con precisione per garantire il corretto funzionamento dei file sepolicy. - Deve trovarsi nella partizione
system
in/system/etc/selinux/plat_file_contexts
sul dispositivo e essere caricato dainit
all'avvio insieme al fornitorefile_context
.
- Piattaforma Android
vendor_file_contexts
file_context
specifico del dispositivo creato combinandofile_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo.- Deve essere installato in
/vendor/etc/selinux/vendor_file_contexts
nella partizionevendor
e caricato dainit
all'avvio insieme alla piattaformafile_context
.
Contesti delle proprietà
In Android 8.0, property_contexts
è suddiviso in due file:
plat_property_contexts
- Piattaforma Android
property_context
senza le etichette specifiche del dispositivo. - Deve risiedere nella partizione
system
in/system/etc/selinux/plat_property_contexts
e essere caricato dainit
all'avvio insieme al fornitoreproperty_contexts
.
- Piattaforma Android
vendor_property_contexts
property_context
specifico del dispositivo creato combinandoproperty_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo.- Deve trovarsi nella partizione
vendor
al/vendor/etc/selinux/vendor_property_contexts
e essere caricato dainit
all'avvio insieme alla piattaformaproperty_context
Contesti di servizio
In Android 8.0, service_contexts
è suddiviso tra i seguenti
file:
plat_service_contexts
service_context
specifico della piattaforma Android perservicemanager
.service_context
non ha etichette specifiche per il dispositivo.- Deve trovarsi nella partizione
system
in/system/etc/selinux/plat_service_contexts
e essere caricato daservicemanager
all'avvio insieme al fornitoreservice_contexts
.
vendor_service_contexts
service_context
specifico del dispositivo creato combinandoservice_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo.- Deve trovarsi nella partizione
vendor
in/vendor/etc/selinux/vendor_service_contexts
e essere caricato daservicemanager
all'avvio insieme alla piattaformaservice_contexts
. - Anche se
servicemanager
cerca questo file all'avvio, per un dispositivoTREBLE
completamente conforme, ilvendor_service_contexts
NON DEVE esistere. Questo perché tutta l'interazione tra i processivendor
esystem
DEVE passare perhwservicemanager
/hwbinder
.
plat_hwservice_contexts
- Piattaforma Android
hwservice_context
perhwservicemanager
che non ha etichette specifiche per il dispositivo. - Deve trovarsi nella partizione
system
in/system/etc/selinux/plat_hwservice_contexts
e essere caricato dahwservicemanager
all'avvio insieme avendor_hwservice_contexts
.
- Piattaforma Android
vendor_hwservice_contexts
hwservice_context
specifico del dispositivo creato combinandohwservice_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo.- Deve trovarsi nella partizione
vendor
in/vendor/etc/selinux/vendor_hwservice_contexts
e essere caricato dahwservicemanager
all'avvio insieme aplat_service_contexts
.
vndservice_contexts
service_context
specifico del dispositivo per ilvndservicemanager
creato combinandovndservice_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nelBoardconfig.mk
del dispositivo.- Questo file deve trovarsi nella partizione
vendor
al/vendor/etc/selinux/vndservice_contexts
e deve essere caricato davndservicemanager
all'avvio.
Contesti Seapp
In Android 8.0, seapp_contexts
è suddiviso in due file:
plat_seapp_contexts
- Piattaforma Android
seapp_context
senza modifiche specifiche per il dispositivo. - Deve trovarsi nella partizione
system
in/system/etc/selinux/plat_seapp_contexts.
- Piattaforma Android
vendor_seapp_contexts
- Estensione specifica del dispositivo alla piattaforma
seapp_context
creata combinandoseapp_contexts
trovati nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo. - Deve trovarsi nella partizione
vendor
in/vendor/etc/selinux/vendor_seapp_contexts
.
- Estensione specifica del dispositivo alla piattaforma
Autorizzazioni MAC
In Android 8.0, mac_permissions.xml
è suddiviso in due file:
- Piattaforma
mac_permissions.xml
- Piattaforma Android
mac_permissions.xml
senza modifiche specifiche per il dispositivo. - Deve trovarsi nella partizione
system
in/system/etc/selinux/.
- Piattaforma Android
- Non di piattaforma
mac_permissions.xml
- Estensione specifica del dispositivo alla piattaforma
mac_permissions.xml
creata damac_permissions.xml
trovata nelle directory a cui fa riferimentoBOARD_SEPOLICY_DIRS
nei fileBoardconfig.mk
del dispositivo. - Deve trovarsi nella partizione
vendor
in/vendor/etc/selinux/.
- Estensione specifica del dispositivo alla piattaforma