O Android recomenda que os OEMs testem as implementações do SELinux com cuidado. À medida que os fabricantes implementam o SELinux, eles precisam aplicar a nova política primeiro a um pool de teste de dispositivos.
Depois de aplicar uma nova política, verifique se o SELinux está sendo executado no modo correto no dispositivo emitindo o comando getenforce
.
Isso imprime o modo global do SELinux: "Enforcing" ou "Permissive". Para determinar o modo do SELinux de cada domínio, examine os arquivos correspondentes ou execute a versão mais recente de sepolicy-analyze
com a flag apropriada (-p
), presente em
/platform/system/sepolicy/tools/
.
Ler negações
Verifique se há erros, que são encaminhados como registros de eventos para dmesg
e logcat
e podem ser visualizados localmente no dispositivo. Os fabricantes
precisam 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 da eventual mudança
para o modo de aplicação. As mensagens de registro do SELinux contêm avc:
e podem ser encontradas facilmente com grep
. É possível capturar os registros de negação
em andamento executando cat /proc/kmsg
ou capturar registros de negação
da inicialização anterior executando
cat /sys/fs/pstore/console-ramoops
.
As mensagens de erro do SELinux são limitadas após a conclusão da inicialização para evitar o excesso de registros. Para garantir que você veja todas as mensagens relevantes, desative essa opção
executando adb shell auditctl -r 0
.
Com essa saída, os fabricantes podem identificar facilmente quando os usuários ou componentes do sistema violam a política do SELinux. Os fabricantes podem corrigir esse comportamento inadequado fazendo mudanças no software, na política do SELinux ou em ambos.
Especificamente, essas mensagens de registro indicam quais processos falhariam no modo de aplicação e por quê. Confira 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 a saída assim:
- O
{ connectto }
acima representa a ação que está sendo realizada. Junto com otclass
no final (unix_stream_socket
), ele informa aproximadamente o que estava sendo feito para o quê. Nesse caso, algo estava tentando se conectar a um soquete de fluxo do Unix. - O
scontext (u:r:shell:s0)
informa qual contexto iniciou a ação. Nesse caso, é algo que está sendo executado como o shell. - O
tcontext (u:r:netd:s0)
informa o contexto do destino da ação. Nesse caso, é um unix_stream_socket pertencente anetd
. - O
comm="ping"
na parte de cima dá outra dica sobre o que estava sendo executado no momento em que a recusa foi gerada. Nesse caso, é uma dica muito boa.
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
Estes são os principais elementos da recusa:
- Ação: a ação tentada é 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 em que a ação está sendo realizada, neste caso, kmem. - Resultado: a entrada
tclass
(classe de destino) indica o tipo de objeto em que a ação está sendo realizada, neste caso, umchr_file
(dispositivo de caractere).
Despejar pilhas de usuário e kernel
Em alguns casos, as informações contidas no registro de eventos não são suficientes para identificar a origem da recusa. Geralmente, é útil coletar a cadeia de chamadas, incluindo kernel e espaço do usuário, para entender melhor por que a negação ocorreu.
Os kernels recentes definem um tracepoint chamado avc:selinux_audited
. Use o Android
simpleperf
para ativar esse ponto de rastreamento e capturar a cadeia de chamadas.
Configuração compatível
- O kernel do Linux >= 5.10, em especial as ramificações do kernel comum do Android
mainline
e
android12-5.10
são compatíveis.
A ramificação android12-5.4 também é compatível. Use
simpleperf
para determinar se o ponto de rastreamento está definido no seu dispositivo:adb root && adb shell simpleperf list | grep avc:selinux_audited
. Para outras versões do kernel, você pode escolher commits dd81662 e 30969bc. - É preciso ser possível reproduzir o evento que você está depurando. Eventos de tempo de inicialização não são compatíveis com o simpleperf. No entanto, talvez seja possível reiniciar o serviço para acionar o evento.
Capturar a cadeia de chamadas
A primeira etapa é registrar o evento usando simpleperf record
:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
Em seguida, o evento que causou a recusa será acionado. Depois disso, a gravação será interrompida. Neste exemplo, ao usar Ctrl-c
, a amostra deveria ter sido capturada:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Por fim, simpleperf report
pode ser usado para inspecionar o rastreamento de pilha 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 é unificada para kernel e espaço do usuário. Ele oferece uma visão melhor do fluxo de código, começando o rastreamento do espaço do usuário até o kernel, onde a negação acontece. Para mais informações sobre simpleperf
, consulte a
Referência de comandos executáveis do Simpleperf
Mudar para permissiva
A aplicação do SELinux pode ser desativada com o adb em builds userdebug ou eng. Para isso, primeiro mude o ADB para root executando adb root
. Em seguida, para desativar a aplicação do SELinux, execute:
adb shell setenforce 0
Ou na linha de comando do kernel (durante a inicialização do dispositivo):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Ou pelo bootconfig no Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Usar o audit2allow
A ferramenta audit2allow
usa negações de dmesg
e as converte em instruções de política do SELinux correspondentes. Assim, ele pode acelerar muito o desenvolvimento do SELinux.
Para usar, execute:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
No entanto, é preciso ter cuidado ao examinar cada possível adição para
permissões excessivas. Por exemplo, ao inserir audit2allow
na
negação rmt_storage
mostrada anteriormente, o resultado é a seguinte
instrução de política do SELinux sugerida:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Isso concederia a rmt
a capacidade de gravar memória do kernel, uma
falha de segurança grave. Muitas vezes, as instruções audit2allow
são apenas um ponto de partida. Depois de usar essas instruções, talvez seja necessário mudar o domínio de origem e o rótulo do destino, além de incorporar macros adequadas para chegar a uma boa política. Às vezes, a recusa em análise não resulta em mudanças na política, mas sim no app infrator.