Android consiglia vivamente agli OEM di testare a fondo le proprie implementazioni SELinux. Man mano che i produttori implementano SELinux, devono applicare le nuove norme a un pool di test di dispositivi.
Dopo aver applicato un nuovo criterio, assicurati che SELinux sia in esecuzione nella modalità corretta sul dispositivo eseguendo il comando getenforce
.
Stampa la modalità SELinux globale: Enforcing o Permissive. Per
determinare la modalità SELinux per ogni dominio, devi esaminare i file corrispondenti
o eseguire l'ultima versione di sepolicy-analyze
con il
flag appropriato (-p
), presente in
/platform/system/sepolicy/tools/
.
Read denials
Controlla la presenza di errori, che vengono indirizzati come log eventi a dmesg
e logcat
e sono visualizzabili localmente sul dispositivo. I produttori
devono esaminare l'output di SELinux per dmesg
su questi dispositivi e
perfezionare le impostazioni prima del rilascio pubblico in modalità permissiva e del successivo passaggio
alla modalità di applicazione. I messaggi di log SELinux contengono avc:
e quindi possono
essere facilmente trovati con grep
. È possibile acquisire i log di negazione in corso eseguendo cat /proc/kmsg
o acquisire i log di negazione dell'avvio precedente eseguendo cat /sys/fs/pstore/console-ramoops
.
I messaggi di errore SELinux sono limitati in termini di frequenza dopo il completamento dell'avvio per evitare di sovraccaricare
i log. Per assicurarti di visualizzare 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 del sistema violano le norme SELinux. I produttori possono quindi correggere questo comportamento anomalo apportando modifiche al software, alle norme SELinux o a entrambi.
Nello specifico, questi messaggi di log indicano quali processi non funzionerebbero 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
{ connectto }
sopra rappresenta l'azione intrapresa. Insieme atclass
alla fine (unix_stream_socket
), ti dice approssimativamente cosa è stato fatto a cosa. In questo caso, è stato effettuato un tentativo di connessione a un socket di flusso Unix. - Il
scontext (u:r:shell:s0)
indica il contesto che ha avviato l'azione. In questo caso, si tratta di qualcosa in esecuzione come shell. - Il
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
comm="ping"
nella parte superiore fornisce un suggerimento aggiuntivo su cosa veniva eseguito al momento della generazione del rifiuto. In questo caso, è un suggerimento piuttosto utile.
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
. - Object: la voce
tcontext
(contesto di destinazione) rappresenta l'oggetto su cui viene eseguita l'azione, in questo caso kmem. - Risultato: la voce
tclass
(classe di destinazione) indica il tipo di oggetto su cui viene eseguita l'azione, in questo caso unchr_file
(dispositivo di caratteri).
Dump degli stack utente e kernel
In alcuni casi, le informazioni contenute nel log eventi non sono sufficienti per individuare l'origine del rifiuto. Spesso è utile raccogliere la catena di chiamate, inclusi il kernel e lo spazio utente, per capire meglio perché si è verificato il rifiuto.
I kernel recenti definiscono un punto di traccia denominato avc:selinux_audited
. Utilizza Android
simpleperf
per attivare questo punto di traccia e acquisire la callchain.
Configurazione supportata
- Sono supportati il kernel Linux >= 5.10, in particolare i rami del kernel comune Android
mainline
e
android12-5.10.
È supportato anche il ramo android12-5.4. Puoi utilizzare
simpleperf
per determinare se il punto di tracciamento è definito sul tuo dispositivo:adb root && adb shell simpleperf list | grep avc:selinux_audited
. Per altre versioni del kernel, puoi selezionare i commit dd81662 e 30969bc. - Dovrebbe essere possibile riprodurre l'evento di cui esegui il debug. Gli eventi di avvio non sono supportati utilizzando simpleperf, ma 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"
Dopodiché, deve essere attivato l'evento che ha causato il rifiuto. Dopodiché, la registrazione dovrebbe
essere interrotta. In questo esempio, utilizzando Ctrl-c
, il campione avrebbe dovuto essere acquisito:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Infine, è possibile utilizzare simpleperf report
per esaminare lo stacktrace 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 riportata sopra è una catena di chiamate unificata del kernel e dello spazio utente. Ti offre una visione migliore del flusso di codice iniziando la traccia dallo spazio utente fino al kernel in cui si verifica il rifiuto. Per ulteriori informazioni su simpleperf
, consulta il
riferimento ai comandi eseguibili di Simpleperf.
Passa alla modalità permissiva
L'applicazione di SELinux può essere disattivata con adb nelle build userdebug o eng. Per farlo,
passa prima ad ADB come root eseguendo adb root
. Quindi, per disattivare l'applicazione di SELinux, esegui:
adb shell setenforce 0
oppure nella riga di comando del kernel (durante l'avvio 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 nelle corrispondenti istruzioni delle norme SELinux. Pertanto, può
velocizzare notevolmente lo sviluppo di SELinux.
Per utilizzarlo, esegui:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
Tuttavia, è necessario prestare attenzione a esaminare ogni potenziale aggiunta per
autorizzazioni eccessive. Ad esempio, l'inserimento di audit2allow
nel
rmt_storage
negato mostrato in precedenza genera la seguente
istruzione della policy SELinux suggerita:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
In questo modo, rmt
avrebbe la possibilità di scrivere nella memoria del kernel, un
grave problema 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 della destinazione, nonché incorporare macro
appropriate, per ottenere una norma efficace. A volte il rifiuto esaminato non deve comportare
alcuna modifica delle norme; piuttosto, deve essere modificata
l'app incriminata.