Convalida SELinux

Android incoraggia fortemente gli OEM a testare approfonditamente le loro implementazioni SELinux. Man mano che i produttori implementano SELinux, dovrebbero prima applicare la nuova politica a un gruppo di dispositivi di prova.

Dopo aver applicato una nuova policy, assicurati che SELinux sia in esecuzione nella modalità corretta sul dispositivo emettendo il comando getenforce .

Questo stampa la modalità globale di SELinux: Enforcing o Permissive. Per determinare la modalità SELinux per ciascun dominio, è necessario esaminare i file corrispondenti o eseguire l'ultima versione di sepolicy-analyze con l'apposito flag ( -p ), presente in /platform/system/sepolicy/tools/ .

Lettura delle smentite

Verifica la presenza di errori, che vengono instradati come registri eventi a dmesg e logcat e sono visualizzabili localmente sul dispositivo. I produttori dovrebbero esaminare l'output di SELinux per dmesg su questi dispositivi e perfezionare le impostazioni prima del rilascio pubblico in modalità permissiva ed eventuale passaggio alla modalità di applicazione. I messaggi di log di SELinux contengono avc: e quindi possono essere facilmente trovati con grep . È possibile acquisire i registri di rifiuto in corso eseguendo cat /proc/kmsg o acquisire i registri di rifiuto dall'avvio precedente eseguendo cat /sys/fs/pstore/console-ramoops .

I messaggi di errore di SELinux hanno una velocità limitata dopo il completamento dell'avvio per evitare di inondare i log. Per assicurarti di visualizzare tutti i messaggi rilevanti puoi disabilitarlo eseguendo adb shell auditctl -r 0 .

Con questo output, i produttori possono identificare facilmente quando gli utenti o i componenti del sistema violano la politica di SELinux. I produttori possono quindi riparare questo cattivo comportamento, modificando il software, la politica di SELinux o entrambi.

Nello specifico, questi messaggi di registro indicano quali processi fallirebbero in modalità di applicazione e perché. Ecco un esempio:

avc: denied  { connectto } for  pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket

Interpreta questo output in questo modo:

  • Il { connectto } sopra rappresenta l'azione intrapresa. Insieme alla tclass alla fine ( unix_stream_socket ), ti dice approssimativamente cosa è stato fatto a cosa. In questo caso, qualcosa stava tentando di connettersi a un socket stream Unix.
  • Il scontext (u:r:shell:s0) ti dice quale contesto ha avviato l'azione. In questo caso si tratta di qualcosa in esecuzione come shell.
  • Il tcontext (u:r:netd:s0) indica il contesto dell'obiettivo dell'azione. In questo caso, si tratta di un unix_stream_socket di proprietà di netd .
  • Il comm="ping" in alto ti dà un ulteriore suggerimento su cosa era in esecuzione nel momento in cui è stato generato il rifiuto. In questo caso, è un buon suggerimento.

Un altro esempio:

adb shell su root dmesg | grep 'avc: '

Produzione:

<5> type=1400 audit: avc:  denied  { read write } for  pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file

Ecco gli elementi chiave di questa negazione:

  • Azione : l'azione tentata è evidenziata tra parentesi, read write o setenforce .
  • Attore : la voce scontext (contesto di origine) rappresenta l'attore, in questo caso il demone rmt_storage .
  • Oggetto - La voce tcontext (contesto di destinazione) rappresenta l'oggetto su cui si agisce, in questo caso kmem.
  • Risultato : la voce tclass (classe di destinazione) indica il tipo di oggetto su cui si agisce, in questo caso un chr_file (dispositivo di caratteri).

Dumping degli stack di utenti e kernel

In alcuni casi le informazioni contenute nel registro eventi non sono sufficienti a individuare l'origine del rifiuto. Spesso è utile raccogliere la catena di chiamate, inclusi kernel e spazio utente, per comprendere meglio il motivo per cui si è verificato il rifiuto.

I kernel recenti definiscono un tracepoint denominato avc:selinux_audited . Utilizza Android simpleperf per abilitare questo tracepoint e acquisire la catena di chiamate.

Configurazione supportata

  • Kernel Linux >= 5.10, in particolare sono supportati i rami Android Common Kernel mainline e android12-5.10 . È supportato anche il ramo Android12-5.4 . Puoi utilizzare simpleperf per determinare se il tracepoint è definito sul tuo dispositivo: adb root && adb shell simpleperf list | grep avc:selinux_audited . Per altre versioni del kernel, puoi scegliere i commit dd81662 e 30969bc .
  • Dovrebbe essere possibile riprodurre l'evento di cui si sta eseguendo il debug. Gli eventi all'avvio non sono supportati utilizzando simpleperf; tuttavia potresti essere ancora in grado di riavviare il servizio per attivare l'evento.

Catturare la catena delle chiamate

Il primo passo è registrare l'evento utilizzando simpleperf record :

adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"

Poi, dovrebbe scattare l’evento che ha causato il diniego. Successivamente, la registrazione dovrebbe essere interrotta. In questo esempio, utilizzando Ctrl-c , il campione avrebbe dovuto essere catturato:

^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.

Infine, simpleperf report può essere utilizzato per ispezionare lo stacktrace catturato. Ad esempio:

adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children  Self     Command  Pid   Tid   Shared Object                                   Symbol
100.00%   0.00%    dmesg    3318  3318  /apex/com.android.runtime/lib64/bionic/libc.so  __libc_init
       |
       -- __libc_init
          |
           -- main
              toybox_main
              toy_exec_which
              dmesg_main
              klogctl
              entry_SYSCALL_64_after_hwframe
              do_syscall_64
              __x64_sys_syslog
              do_syslog
              selinux_syslog
              slow_avc_audit
              common_lsm_audit
              avc_audit_post_callback
              avc_audit_post_callback

La catena di chiamate sopra è una catena di chiamate unificata del kernel e dello spazio utente. Ti offre una visione migliore del flusso del codice avviando la traccia dallo spazio utente fino al kernel dove avviene il rifiuto. Per ulteriori informazioni su simpleperf , vedere il riferimento ai comandi eseguibili Simpleperf

Passaggio al permissivo

L'imposizione di SELinux può essere disabilitata tramite ADB su userdebug o eng build. Per fare ciò, passa prima ADB a root eseguendo adb root . Quindi, per disabilitare l'imposizione di SELinux, eseguire:

adb shell setenforce 0

Oppure dalla riga di comando del kernel (durante il primo avvio del dispositivo):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Oppure tramite bootconfig in Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

Utilizzando audit2allow

Lo strumento audit2allow accetta i rifiuti dmesg e li converte nelle corrispondenti dichiarazioni della politica SELinux. In quanto tale, può accelerare notevolmente lo sviluppo di SELinux.

Per usarlo, esegui:

adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy

Tuttavia, è necessario prestare attenzione nell'esaminare ogni potenziale aggiunta per il superamento delle autorizzazioni. Ad esempio, alimentando audit2allow il rifiuto rmt_storage mostrato in precedenza si ottiene la seguente dichiarazione di politica SELinux suggerita:

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

Ciò garantirebbe rmt la capacità di scrivere la memoria del kernel, un evidente buco di sicurezza. Spesso le dichiarazioni audit2allow sono solo un punto di partenza. Dopo aver utilizzato queste istruzioni, potrebbe essere necessario modificare il dominio di origine e l'etichetta di destinazione, nonché incorporare macro adeguate, per arrivare a una buona politica. A volte il rifiuto esaminato non dovrebbe comportare alcun cambiamento politico; bisognerebbe piuttosto modificare l'applicazione incriminata.