O Android Open Source Project (AOSP) oferece uma política de base sólida para os apps e serviços comuns em todos os dispositivos Android. Os colaboradores do AOSP refinam essa política regularmente. Espera-se que a política principal compõe cerca de 90% a 95% da política final no dispositivo, com personalizações específicas do dispositivo representando os 5% a 10% restantes. Este artigo se concentra nessas personalizações, em como escrever políticas específicas do dispositivo e em algumas armadilhas a serem evitadas.
Inicialização do dispositivo
Ao escrever a política específica do dispositivo, siga estas etapas.
Executar no modo permissivo
Quando um dispositivo está no modo permissivo, as negações são registradas, mas não aplicadas. O modo permissivo é importante por dois motivos:
- O modo permissivo garante que a inicialização da política não atrase outras tarefas iniciais de ativação do dispositivo.
- Uma negação aplicada pode mascarar outras. Por exemplo, o acesso a arquivos normalmente envolve uma pesquisa de diretório, a abertura do arquivo e a leitura do arquivo. No modo de aplicação, apenas a negação da pesquisa de diretório ocorreria. O modo permissivo garante que todas as negações sejam vistas.
A maneira mais simples de colocar um dispositivo no modo permissivo é usando a
linha de comando
do kernel. Isso pode ser adicionado ao arquivo BoardConfig.mk
do dispositivo:
platform/device/<vendor>/<target>/BoardConfig.mk
.
Depois de modificar a linha de comando, execute make clean
, depois
make bootimage
e atualize a nova imagem de inicialização.
Depois disso, confirme o modo permissivo com:
adb shell getenforce
Duas semanas é um período razoável para o modo permissivo global. Depois de resolver a maioria das negações, volte para o modo de aplicação e resolva os bugs conforme eles aparecem. Os domínios que ainda estiverem produzindo negações ou serviços ainda em desenvolvimento intenso podem ser colocados temporariamente em modo permissivo, mas revertê-los ao modo de aplicação assim que possível.
Aplicar antecipadamente
No modo de aplicação, as negações são registradas e aplicadas. É uma prática recomendada colocar o dispositivo no modo de aplicação o mais cedo possível. Esperar para criar e aplicar a política específica do dispositivo geralmente resulta em um produto com bugs e uma experiência ruim do usuário. Comece cedo o suficiente para participar do dogfooding e garantir a cobertura completa de testes da funcionalidade no uso real. Começar cedo garante que as preocupações de segurança informem as decisões de design. Por outro lado, conceder permissões com base apenas em negações observadas é uma abordagem não segura. Use esse tempo para realizar uma auditoria de segurança do dispositivo e registrar bugs em comportamentos que não devem ser permitidos.
Remover ou excluir uma política
Há vários bons motivos para criar uma política específica do dispositivo do zero em um novo dispositivo, incluindo:
- Auditoria de segurança
- Política muito permissiva
- Redução do tamanho da política
- Política inativa
Resolver negações de serviços principais
As recusas geradas pelos serviços principais geralmente são resolvidas com o rotulagem de arquivos. Exemplo:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
é totalmente resolvido ao rotular corretamente /dev/kgsl-3d0
. Neste
exemplo, tcontext
é device
. Isso representa um
contexto padrão em que tudo em /dev
recebe o
rótulo
device, a menos que um rótulo mais específico seja atribuído. Simplesmente aceitar
a saída de
audit2allow
resultaria em uma regra incorreta e excessivamente permissiva.
Para resolver esse tipo de problema, dê ao arquivo um rótulo mais específico, que, neste caso, é gpu_device. Nenhuma outra permissão é necessária, porque o mediaserver já tem as permissões necessárias na política principal para acessar o gpu_device.
Outros arquivos específicos do dispositivo que precisam ser rotulados com tipos predefinidos na política principal:
- bloquear dispositivos
- Dispositivos de áudio
- Dispositivos de vídeo
- sensores
- nfc
- gps_device
- arquivos em /sys
- Arquivos em /proc
Em geral, conceder permissões para rótulos padrão é errado. Muitas dessas permissões não são permitidas por regras dependendo da necessidade. No entanto, mesmo quando isso não é permitido explicitamente, a prática recomendada é fornecer um rótulo específico.
Rotular novos serviços e resolver negações
Os serviços iniciados pelo init precisam ser executados nos próprios domínios do SELinux. O exemplo a seguir coloca o serviço "foo" no próprio domínio do SELinux e concede permissões a ele.
O serviço é iniciado no arquivo
init.device.rc
do dispositivo como:
service foo /system/bin/foo class core
- Crie um novo domínio "foo"
Crie o arquivo
device/manufacturer/device-name/sepolicy/foo.te
com o seguinte conteúdo:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
Esse é o modelo inicial do domínio foo SELinux, ao qual você pode adicionar regras com base nas operações específicas realizadas por esse executável.
- Rótulo
/system/bin/foo
Adicione o seguinte a
device/manufacturer/device-name/sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
Isso garante que o executável seja devidamente rotulado para que o SELinux execute o serviço no domínio adequado.
- Crie e faça o flash das imagens de inicialização e do sistema.
- Refinar as regras do SELinux para o domínio.
Use as negações para determinar as permissões necessárias. A ferramenta audit2allow oferece boas diretrizes, mas use-a apenas para informar a redação da política. Não copie apenas a saída.
Voltar para o modo aplicado
Não há problema em solucionar problemas no modo permissivo, mas volte para o modo de aplicação o quanto antes e tente permanecer nele.
Erros comuns
Confira algumas soluções para erros comuns que acontecem ao escrever políticas específicas do dispositivo.
Uso excessivo de negação
O exemplo de regra a seguir é como trancar a porta da frente, mas deixar as janelas abertas:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
A intenção é clara: todos, exceto apps de terceiros, podem ter acesso ao dispositivo de depuração.
A regra tem algumas falhas. A exclusão de untrusted_app
é simples de contornar, porque todos os apps podem executar serviços no
domínio isolated_app
. Da mesma forma, se novos domínios de apps de terceiros
forem adicionados ao AOSP, eles também terão acesso a scary_debug_device
.
A regra é muito permissiva. A maioria dos domínios não se beneficia
de ter acesso a essa ferramenta de depuração. A regra precisa ter sido escrita para permitir apenas
os domínios que exigem acesso.
Depurar recursos em produção
Os recursos de depuração não podem estar presentes em builds de produção nem a política deles.
A alternativa mais simples é permitir o recurso de depuração somente quando o SELinux estiver
desativado em builds eng/userdebug, como adb root
e
adb shell setenforce 0
.
Outra alternativa segura é incluir as permissões de depuração em uma instrução userdebug_or_eng.
Aumento do tamanho das políticas
Caracterização de políticas do SEAndroid no mundo real descreve uma tendência preocupante no crescimento das personalizações de políticas do dispositivo. A política específica do dispositivo precisa representar de 5% a 10% da política geral em execução em um dispositivo. As personalizações na faixa de 20%ou mais provavelmente contêm domínios privilegiados e políticas inválidas.
Política grande demais:
- Tem um impacto duplo na memória, já que a política fica no ramdisk e também é carregada na memória do kernel.
- Desperdiça espaço em disco ao exigir uma imagem de inicialização maior.
- Afeta os tempos de pesquisa de políticas de ambiente de execução.
O exemplo a seguir mostra dois dispositivos em que a política específica do fabricante compreende 50% e 40% da política no dispositivo. Uma reescrita da política resultou em melhorias de segurança substanciais sem perda de funcionalidade, como mostrado abaixo. Os dispositivos AOSP Shamu e Flounder estão incluídos para comparação.
Em ambos os casos, a política foi drasticamente reduzida em tamanho e número
de permissões. A redução do tamanho da política se deve quase totalmente à remoção de permissões desnecessárias. Muitas delas foram prováveis regras geradas por audit2allow
que foram adicionadas indiscriminadamente à política. Os domínios
inativos também foram um problema para os dois dispositivos.
Conceder o capability dac_override
Uma negação dac_override
significa que o processo infrator está
tentando acessar um arquivo com as permissões de usuário/grupo/mundo incorretas do Unix.
A solução correta é quase nunca conceder a permissão dac_override
.
Em vez disso,
mude as permissões do Unix no arquivo ou processo. Alguns domínios, como
init
, vold
e installd
, precisam
de fato da capacidade de substituir as permissões de arquivo do Unix para acessar arquivos de outros processos.
Consulte o blog de Dan Walsh
para uma explicação mais detalhada.