Compatibilità con i criteri

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 partizione vendor. Il criterio della piattaforma lo richiede per accedere alle implementazioni HAL passthrough.
  • Tutti i nuovi exec_types aggiunti nella partizione vendor tramite SEPolicy del fornitore devono avere l'attributo vendor_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 partizione vendor.
  • 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 come sysfs per impostazione predefinita.
  • A partire dal livello API del fornitore 202504, /sys/class/udc è etichettato come sysfs_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.

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 da sysfs a sysfs_A). Il codice del fornitore si basa su una regola che consente l'accesso a sysfs 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 tra vendor e coredomains. 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.
  • system_executes_vendor_violators. Attributo per tutti i domini di sistema (tranne init e shell 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.

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:

  1. 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.
  2. 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 Binder surfaceflinger, a cui le app sono autorizzate ad accedere.
  • hal_omx_hwservice. Si tratta di una versione HwBinder del servizio Binder mediacodec, a cui le app sono autorizzate ad accedere.
  • hal_codec2_hwservice. Si tratta di una versione più recente di hal_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, quindi mediaserver (che è un binderservicedomain) a sua volta comunica con hal_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 sysfssysfs_A o mediaserveraudioserver, 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:

  1. Copia i file di mappatura di base generati dalle partizioni N system_ext e product alla relativa struttura ad albero di origine.
  2. Modifica i file di mappatura in base alle esigenze.
  3. Installa i file di mappatura nelle partizioni system_ext e product di N+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 da init all'avvio insieme al fornitore file_context.
    • vendor_file_contexts
      • file_context specifico del dispositivo creato combinando file_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
      • Deve essere installato in /vendor/etc/selinux/vendor_file_contexts nella partizione vendor e caricato da init all'avvio insieme alla piattaforma file_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 da init all'avvio insieme al fornitore property_contexts.
  • vendor_property_contexts
    • property_context specifico del dispositivo creato combinando property_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
    • Deve trovarsi nella partizione vendor al /vendor/etc/selinux/vendor_property_contexts e essere caricato da init all'avvio insieme alla piattaforma property_context

Contesti di servizio

In Android 8.0, service_contexts è suddiviso tra i seguenti file:

  • plat_service_contexts
    • service_context specifico della piattaforma Android per servicemanager. service_context non ha etichette specifiche per il dispositivo.
    • Deve trovarsi nella partizione system in /system/etc/selinux/plat_service_contexts e essere caricato da servicemanager all'avvio insieme al fornitore service_contexts.
  • vendor_service_contexts
    • service_context specifico del dispositivo creato combinando service_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
    • Deve trovarsi nella partizione vendor in /vendor/etc/selinux/vendor_service_contexts e essere caricato da servicemanager all'avvio insieme alla piattaforma service_contexts.
    • Anche se servicemanager cerca questo file all'avvio, per un dispositivo TREBLE completamente conforme, il vendor_service_contexts NON DEVE esistere. Questo perché tutta l'interazione tra i processi vendor e system DEVE passare per hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • Piattaforma Android hwservice_context per hwservicemanager che non ha etichette specifiche per il dispositivo.
    • Deve trovarsi nella partizione system in /system/etc/selinux/plat_hwservice_contexts e essere caricato da hwservicemanager all'avvio insieme a vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context specifico del dispositivo creato combinando hwservice_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
    • Deve trovarsi nella partizione vendor in /vendor/etc/selinux/vendor_hwservice_contexts e essere caricato da hwservicemanager all'avvio insieme a plat_service_contexts.
  • vndservice_contexts
    • service_context specifico del dispositivo per il vndservicemanager creato combinando vndservice_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nel Boardconfig.mk del dispositivo.
    • Questo file deve trovarsi nella partizione vendor al /vendor/etc/selinux/vndservice_contexts e deve essere caricato da vndservicemanager 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.
  • vendor_seapp_contexts
    • Estensione specifica del dispositivo alla piattaforma seapp_context creata combinando seapp_contexts trovati nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
    • Deve trovarsi nella partizione vendor in /vendor/etc/selinux/vendor_seapp_contexts.

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/.
  • Non di piattaforma mac_permissions.xml
    • Estensione specifica del dispositivo alla piattaforma mac_permissions.xml creata da mac_permissions.xml trovata nelle directory a cui fa riferimento BOARD_SEPOLICY_DIRS nei file Boardconfig.mk del dispositivo.
    • Deve trovarsi nella partizione vendor in /vendor/etc/selinux/.