O Android incentiva fortemente os OEMs a testarem cuidadosamente as implementações do SELinux. À medida que os fabricantes implementam o SELinux, eles precisam aplicar a nova política primeiro a um conjunto de dispositivos de teste.
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 SELinux global: aplicador ou permissivo. Para
determinar o modo SELinux de cada domínio, examine os arquivos
correspondentes ou execute a versão mais recente do sepolicy-analyze
com a
flag (-p
) adequada, presente em
/platform/system/sepolicy/tools/
.
Ler negações
Verifique se há erros, que são roteados 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, eventualmente, mudar
para o modo de aplicação. As mensagens de registro do SELinux contêm avc:
e, portanto, podem
ser encontradas facilmente com grep
. É possível capturar os logs de negação
em andamento executando cat /proc/kmsg
ou capturar os logs de negação
da inicialização anterior executando
cat /sys/fs/pstore/console-ramoops
.
As mensagens de erro do SELinux são limitadas de taxa após a inicialização para evitar o
preenchimento dos registros. Para conferir todas as mensagens relevantes, desative essa
opção executando adb shell auditctl -r 0
.
Com esse resultado, os fabricantes podem identificar prontamente quando usuários ou componentes do sistema violam a política do SELinux. Os fabricantes podem reparar esse mau comportamento, seja por mudanças no software, na política do SELinux ou em ambos.
Especificamente, essas mensagens de registro indicam quais processos falhariam no modo de imposição e o motivo. 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 o resultado da seguinte forma:
- O
{ connectto }
acima representa a ação realizada. Junto com otclass
no final (unix_stream_socket
), ele informa aproximadamente o que está sendo feito no quê. Nesse caso, algo estava tentando se conectar a um soquete de stream Unix. - O
scontext (u:r:shell:s0)
informa qual contexto iniciou a ação. Nesse caso, é algo executado como o shell. - O
tcontext (u:r:netd:s0)
informa o contexto do destino da ação. Nesse caso, é um unix_stream_socket de propriedade denetd
. - O
comm="ping"
na parte superior oferece uma dica adicional sobre o que estava sendo executado no momento em que a negação 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
Aqui estão os principais elementos dessa negação:
- Ação: a ação é destacada entre colchetes,
read write
ousetenforce
. - Ator: a entrada
scontext
(contexto de origem) representa o ator. Neste caso, o daemonrmt_storage
. - Object: a entrada
tcontext
(contexto de destino) representa o objeto em ação, neste caso kmem. - Resultado: a entrada
tclass
(classe de destino) indica o tipo de objeto em que a ação é realizada. Neste caso, umchr_file
(dispositivo de caractere).
Fazer o despejo de pilhas de usuário e kernel
Em alguns casos, as informações contidas no log 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 a negação ocorreu.
Os kernels recentes definem um ponto de rastreamento chamado avc:selinux_audited
. Use o simpleperf
do Android para ativar esse ponto de rastreamento e capturar a cadeia de chamadas.
Configuração com suporte
- A versão 5.10 ou mais recente do kernel do Linux, principalmente as ramificações mainline
e android12-5.10
do kernel comum do Android,
têm suporte.
A ramificação android12-5.4
também é compatível. Use
simpleperf
para determinar se o ponto de rastreamento está definido no dispositivo:adb root && adb shell simpleperf list | grep avc:selinux_audited
. Para outras versões do kernel, você pode selecionar as confirmações dd81662 e 30969bc. - Deve ser possível reproduzir o evento que você está depurando. Os eventos de tempo de inicialização não são compatíveis com o simpleperf. No entanto, ainda é possível reiniciar o serviço para acionar o evento.
Capturar a cadeia de chamada
A primeira etapa é gravar 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 negação deve ser acionado. Depois disso, a gravação
precisa ser interrompida. Neste exemplo, ao usar Ctrl-c
, a amostra precisa 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 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 é um kernel unificado e uma cadeia de chamadas do espaço do usuário. Ele oferece uma visão melhor
do fluxo de código, iniciando o rastro desde o 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 fazer isso,
primeiro mude o ADB para raiz 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 inicial do dispositivo):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Ou pelo bootconfig do Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Usar audit2allow
A ferramenta audit2allow
recebe negações dmesg
e
as converte em declarações de política do SELinux correspondentes. Dessa forma, ele pode
acelerar muito o desenvolvimento do SELinux.
Para usá-lo, execute:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
No entanto, é preciso ter cuidado para examinar cada possível adição em busca de permissões excedentes. Por exemplo, alimentar audit2allow
com a
negação rmt_storage
mostrada anteriormente resulta na 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 evidente. Muitas vezes, as instruções audit2allow
são apenas um
ponto de partida. Depois de empregar essas instruçõ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 examinada não
resultará em nenhuma alteração da política, em vez disso, o app infrator
precisará ser alterado.