O Android incentiva fortemente os OEMs a testarem minuciosamente suas implementações do SELinux. À medida que os fabricantes implementam o SELinux, eles devem primeiro aplicar a nova política a um conjunto de dispositivos de teste.
Após aplicar uma nova política, certifique-se de que o SELinux esteja sendo executado no modo correto no dispositivo emitindo o comando getenforce
.
Isso imprime o modo SELinux global: Enforcing ou Permissive. Para determinar o modo SELinux para cada domínio, você deve examinar os arquivos correspondentes ou executar a versão mais recente do sepolicy-analyze
com o sinalizador apropriado ( -p
), presente em /platform/system/sepolicy/tools/
.
Lendo negações
Verifique se há erros, que são roteados como logs de eventos para dmesg
e logcat
e podem ser visualizados localmente no dispositivo. Os fabricantes devem examinar a saída do SELinux para dmesg
nesses dispositivos e refinar as configurações antes do lançamento público no modo permissivo e eventual mudança para o modo de aplicação. As mensagens de log do SELinux contêm avc:
e portanto podem ser facilmente encontradas com grep
. É possível capturar os logs de negação em andamento executando cat /proc/kmsg
ou capturar logs de negação da inicialização anterior executando cat /sys/fs/pstore/console-ramoops
.
As mensagens de erro do SELinux têm taxa limitada após a conclusão da inicialização para evitar sobrecarregar os logs. Para ter certeza de ver todas as mensagens relevantes, você pode desabilitar isso executando adb shell auditctl -r 0
.
Com esta saída, os fabricantes podem identificar prontamente quando os usuários ou componentes do sistema violam a política do SELinux. Os fabricantes podem então reparar esse mau comportamento, seja por meio de alterações no software, na política do SELinux ou em ambos.
Especificamente, essas mensagens de log indicam quais processos falhariam no modo de imposição e por quê. Aqui está um exemplo:
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
Interprete esta saída assim:
- O
{ connectto }
acima representa a ação que está sendo executada. Juntamente com otclass
no final (unix_stream_socket
), ele informa aproximadamente o que estava sendo feito e o quê. Neste caso, algo estava tentando se conectar a um soquete de fluxo unix. - O
scontext (u:r:shell:s0)
informa qual contexto iniciou a ação. Neste caso, isso é algo rodando como shell. - O
tcontext (u:r:netd:s0)
informa o contexto do alvo da ação. Nesse caso, é um unix_stream_socket de propriedade denetd
. - O
comm="ping"
na parte superior fornece uma dica adicional sobre o que estava sendo executado no momento em que a negação foi gerada. Neste caso, é uma boa dica.
Outro exemplo:
adb shell su root dmesg | grep 'avc: '
Saída:
<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
Aqui estão os elementos-chave desta negação:
- Ação - a tentativa de ação é destacada entre colchetes,
read write
ousetenforce
. - Ator - A entrada
scontext
(contexto de origem) representa o ator, neste caso o daemonrmt_storage
. - Objeto - A entrada
tcontext
(contexto de destino) representa o objeto que está sendo acionado, neste caso kmem. - Resultado - A entrada
tclass
(classe de destino) indica o tipo de objeto sobre o qual está sendo atuado, neste caso umchr_file
(dispositivo de caractere).
Despejando pilhas de usuários e kernel
Em alguns casos, as informações contidas no registo de eventos não são suficientes para identificar a origem da negação. Muitas vezes é útil reunir a cadeia de chamadas, incluindo o kernel e o espaço do usuário, para entender melhor por que ocorreu a negação.
Kernels recentes definem um tracepoint chamado avc:selinux_audited
. Use o Android simpleperf
para ativar esse tracepoint e capturar o callchain.
Configuração suportada
- Kernel Linux >= 5.10, em particular as ramificações principais do Android Common Kernel e android12-5.10 são suportadas. A ramificação android12-5.4 também é suportada. Você pode usar
simpleperf
para determinar se o tracepoint está definido em seu dispositivo:adb root && adb shell simpleperf list | grep avc:selinux_audited
. Para outras versões do kernel, você pode escolher os commits dd81662 e 30969bc . - Deve ser possível reproduzir o evento que você está depurando. Eventos de tempo de inicialização não são suportados usando simpleperf; no entanto, você ainda poderá reiniciar o serviço para acionar o evento.
Capturando a cadeia de chamadas
O primeiro passo é registrar o evento usando simpleperf record
:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
Então, o evento que causou a negação deverá ser acionado. Depois disso, a gravação deve ser interrompida. Neste exemplo, usando Ctrl-c
, a amostra deveria ter sido capturada:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Finalmente, simpleperf report
pode ser usado para inspecionar o stacktrace capturado. Por exemplo:
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
A cadeia de chamadas acima é uma cadeia de chamadas unificada do kernel e do espaço do usuário. Ele oferece uma visão melhor do fluxo do código, iniciando o rastreamento do espaço do usuário até o kernel onde ocorre a negação. Para obter mais informações sobre simpleperf
, consulte a referência de comandos executáveis do Simpleperf
Mudando para permissivo
A aplicação do SELinux pode ser desabilitada via ADB em userdebug ou eng builds. Para fazer isso, primeiro mude o ADB para root executando adb root
. Então, para desabilitar a aplicação do SELinux, execute:
adb shell setenforce 0
Ou na linha de comando do kernel (durante a ativação inicial do dispositivo):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Ou através do bootconfig no Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Usando audit2allow
A ferramenta audit2allow
pega negações dmesg
e as converte em declarações de política SELinux correspondentes. Como tal, pode acelerar bastante o desenvolvimento do SELinux.
Para usá-lo, execute:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
No entanto, deve-se ter cuidado ao examinar cada possível acréscimo de permissões excessivas. Por exemplo, alimentar audit2allow
a negação rmt_storage
mostrada anteriormente resulta na seguinte declaração de política SELinux sugerida:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Isso concederia rmt
a capacidade de gravar na memória do kernel, uma falha de segurança gritante. Freqüentemente, as declarações audit2allow
são apenas um ponto de partida. Depois de empregar essas declarações, talvez seja necessário alterar o domínio de origem e o rótulo do destino, bem como incorporar macros adequadas, para chegar a uma boa política. Às vezes, a negação que está sendo examinada não deveria resultar em nenhuma mudança política; em vez disso, o aplicativo ofensivo deve ser alterado.