O Android encoraja fortemente os OEMs a testarem suas implementações do SELinux completamente. À 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 imposição. As mensagens de log do SELinux contêm avc:
e 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
.
Com essa saída, os fabricantes podem identificar prontamente quando os usuários ou componentes do sistema estão violando a política do SELinux. Os fabricantes podem então reparar esse mau comportamento, seja por 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 atclass
no final (unix_stream_socket
), ela informa aproximadamente o que estava sendo feito com o quê. Nesse 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. Nesse caso, isso é algo em execução 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 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 principais elementos dessa negação:
- Ação - a ação tentada é destacada entre colchetes,
read write
ousetenforce
. - Ator - A
scontext
(contexto de origem) representa o ator, neste caso o daemonrmt_storage
. - Object - A
tcontext
(contexto de destino) representa o objeto que está sendo executado, neste caso kmem. - Resultado - A entrada
tclass
(classe de destino) indica o tipo de objeto que está sendo executado, neste caso umchr_file
(dispositivo de caractere).
Despejando 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 kernel e espaço de usuário, para entender melhor por que ocorreu a negação.
Os kernels recentes definem um ponto de rastreamento chamado avc:selinux_audited
. Use o Android simpleperf
para habilitar este tracepoint e capturar o callchain.
Configuração compatível
- Kernel do Linux >= 5.10, em particular os ramos do Android Common Kernel mainline e android12-5.10 são suportados. A ramificação android12-5.4 também é suportada. Você pode usar o
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. Os 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 é 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 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 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 é uma cadeia de chamadas unificada do kernel e do espaço do usuário. Ele oferece uma visão melhor do fluxo de código iniciando o rastreamento do espaço do usuário até o kernel onde a negação acontece. Para obter mais informações sobre simpleperf
, consulte a referência de comandos executáveis Simpleperf
Mudando para permissivo
A aplicação do SELinux pode ser desabilitada via ADB em builds userdebug ou eng. Para fazer isso, primeiro alterne ADB para root executando adb root
. Em seguida, para desabilitar a imposição do SELinux, execute:
adb shell setenforce 0
Ou na linha de comando do kernel (durante o início 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 as negações do dmesg
e as converte em declarações de política SELinux correspondentes. Como tal, 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, deve-se tomar cuidado para examinar cada adição em potencial para 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 ao rmt
a capacidade de escrever na memória do kernel, uma falha de segurança gritante. Muitas vezes, as instruções audit2allow
são apenas um ponto de partida. Depois de empregar essas instruções, pode ser necessário alterar o domínio de origem e o rótulo do destino, bem como incorporar macros apropriadas, para chegar a uma boa política. Às vezes, a negação que está sendo examinada não deve resultar em nenhuma mudança de política; em vez disso, o aplicativo ofensivo deve ser alterado.