Android consiglia vivamente agli OEM di testare attentamente le loro implementazioni di SELinux. Quando i produttori implementano SELinux, devono prima applicare il nuovo criterio a un pool di test di dispositivi.
Dopo aver applicato un nuovo criterio, assicurati che SELinux sia in esecuzione nella modalità corretta sul dispositivo emettendo il comando getenforce
.
Viene stampata la modalità SELinux globale: Enforcing o Permissive. Per determinare la modalità SELinux per ogni dominio, devi esaminare i file corrispondenti o eseguire la versione più recente di sepolicy-analyze
con il flag (-p
) appropriato, presente in
/platform/system/sepolicy/tools/
.
Leggere i rifiuti
Controlla la presenza di errori, che vengono inoltrati come log eventi a dmesg
e logcat
e sono visualizzabili localmente sul dispositivo. I produttori devono esaminare l'output di SELinux su dmesg
su questi dispositivi e perfezionare le impostazioni prima del rilascio pubblico in modalità permissiva ed eventualmente passare alla modalità di applicazione. I messaggi di log di SELinux contengono avc:
e possono essere facilmente trovati con grep
. È possibile acquisire i log di rifiuto in corso eseguendo cat /proc/kmsg
o i log di rifiuto dall'avvio precedente eseguendo cat /sys/fs/pstore/console-ramoops
.
I messaggi di errore SELinux sono limitati in base alla frequenza al termine dell'avvio per evitare di intasare
i log. Per assicurarti di vedere tutti i messaggi pertinenti, puoi disattivare questa opzione eseguendo adb shell auditctl -r 0
.
Con questo output, i produttori possono identificare facilmente quando gli utenti o i componenti di sistema violano i criteri SELinux. I produttori possono quindi correggere questo comportamento scorretto modificando il software, le norme SELinux o entrambi.
Nello specifico, questi messaggi di log indicano quali processi non andrebbero a buon fine 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 nel seguente modo:
- Il simbolo
{ connectto }
sopra riportato indica l'azione intrapresa. Insieme al caratteretclass
alla fine (unix_stream_socket
), indicano approssimativamente cosa è stato fatto a cosa. In questo caso, qualcosa stava tentando di connettersi a una socket stream Unix. -
scontext (u:r:shell:s0)
indica il contesto che ha avviato l'azione. In questo caso, si tratta di un programma in esecuzione come shell. -
tcontext (u:r:netd:s0)
indica il contesto del target dell'azione. In questo caso, si tratta di un unix_stream_socket di proprietà dinetd
. - Il simbolo
comm="ping"
in alto fornisce un ulteriore suggerimento su cosa veniva eseguito al momento della generazione del rifiuto. In questo caso, è un suggerimento piuttosto buono.
Un altro esempio:
adb shell su root dmesg | grep 'avc: '
Uscita:
<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 questo rifiuto:
- Azione: l'azione tentata è evidenziata tra parentesi,
read write
osetenforce
. - Attore: la voce
scontext
(contesto di origine) rappresenta l'attore, in questo caso il daemonrmt_storage
. - Oggetto: la voce
tcontext
(contesto di destinazione) rappresenta l'oggetto su cui viene eseguito l'intervento, in questo caso kmem. - Risultato: la voce
tclass
(classe di destinazione) indica il tipo di oggetto su cui viene eseguito l'intervento, in questo caso unchr_file
(dispositivo di caratteri).
Esegui il dump degli stack utente e del kernel
In alcuni casi, le informazioni contenute nel log eventi non sono sufficienti per individuare la causa del rifiuto. Spesso è utile raccogliere la catena di chiamate, inclusi il kernel e lo spazio utente, per comprendere meglio il motivo del rifiuto.
I kernel recenti definiscono un tracepoint denominato avc:selinux_audited
. Utilizza Android
simpleperf
per attivare questo punto di traccia e acquisire la catena di chiamate.
Configurazione supportata
- Sono supportati i kernel Linux >= 5.10, in particolare i branch del kernel Android Common
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 in cui stai eseguendo il debug. Gli eventi relativi al tempo di avvio non sono supportati utilizzando simpleperf. Tuttavia, potresti comunque essere in grado di riavviare il servizio per attivare l'evento.
Acquisire la catena di chiamate
Il primo passaggio consiste nel registrare l'evento utilizzando simpleperf record
:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
Successivamente, deve essere attivato l'evento che ha causato il rifiuto. Dopodiché, la registrazione dovrebbe essere interrotta. In questo esempio, utilizzando Ctrl-c
, il campione dovrebbe essere stato acquisito:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Infine, simpleperf report
può essere utilizzato per ispezionare lo stack trace acquisito.
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 riportata è una catena di chiamate unificata del kernel e dello spazio utente. Ti offre una migliore
visualizzazione del flusso di codice avviando la traccia dallo spazio utente fino al kernel dove avviene il rifiuto. Per ulteriori informazioni su simpleperf
, consulta la documentazione di riferimento dei comandi eseguibili di Simpleperf.
Passare al criterio permissivo
L'applicazione di SELinux può essere disattivata con adb nelle build userdebug o eng. Per farlo,
innanzitutto passa ad ADB come utente root eseguendo adb root
. Quindi, per disattivare l'applicazione di SELinux, esegui:
adb shell setenforce 0
In alternativa, nella riga di comando del kernel (durante l'inizializzazione iniziale del dispositivo):
androidboot.selinux=permissive
androidboot.selinux=enforcing
In alternativa, tramite bootconfig in Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Utilizzare audit2allow
Lo strumento audit2allow
prende i rifiuti dmesg
e
li converte in istruzioni del criterio SELinux corrispondenti. Di conseguenza, può
accelerare notevolmente lo sviluppo di SELinux.
Per utilizzarlo, esegui:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
Tuttavia, è necessario esaminare attentamente ogni potenziale aggiunta per verificare che non siano presenti autorizzazioni eccessive. Ad esempio, se fornisci a audit2allow
il divieto rmt_storage
mostrato in precedenza, il risultato è la seguente istruzione del criterio SELinux suggerita:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Ciò consentirebbe a rmt
di scrivere nella memoria del kernel, un
evidente problema di sicurezza. Spesso le istruzioni audit2allow
sono solo un punto di partenza. Dopo aver utilizzato queste istruzioni, potrebbe essere necessario modificare il dominio di origine e l'etichetta del target, nonché incorporare le macro appropriate per ottenere un criterio valido. A volte il rifiuto esaminato non dovrebbe comportare alcuna modifica alle norme, ma l'app in questione dovrebbe essere modificata.