Gravar política do SELinux

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 específicas do dispositivo, em como escrever uma política específica do dispositivo e em algumas das 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 ativação da política não atrase outras tarefas iniciais de ativação do dispositivo.
  • Uma recusa forçada pode mascarar outras recusas. 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 mostradas.

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 faça o flash da 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 estão produzindo negações ou serviços ainda em desenvolvimento intenso podem ser colocados temporariamente no modo permissivo, mas volte a eles para o 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 para o usuário. Comece cedo o suficiente para participar do dogfooding e garantir a cobertura de teste completa 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 insegura. 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:

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, atribua ao arquivo um rótulo mais específico, que, neste caso, é gpu_device. Nenhuma outra permissão é necessária, já que 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:

Em geral, conceder permissões a marcadores padrão é errado. Muitas dessas permissões são proibidas pelas regras neverallow, mas, mesmo quando não são explicitamente proibidas, a prática recomendada é fornecer um rótulo específico.

Rotular novos serviços e negar endereços

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
  1. 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.

  2. 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 rotulado corretamente para que o SELinux execute o serviço no domínio correto.

  3. Crie e faça o flash das imagens de inicialização e do sistema.
  4. 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 ao modo de aplicação

Não há problema em resolver problemas no modo permissivo, mas mude de volta para o modo de aplicação o mais rápido possível e tente permanecer nele.

Erros comuns

Confira algumas soluções para erros comuns que acontecem ao escrever políticas específicas para dispositivos.

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 apenas 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 da política

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, exigindo 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. A reescrita da política resultou em melhorias substanciais na segurança sem perda de funcionalidade, conforme mostrado abaixo. Os dispositivos AOSP Shamu e Flounder estão incluídos para comparação.

Figura 1: comparação do tamanho da política específica do dispositivo após a auditoria de segurança.

Figura 1. Comparação do tamanho da política específica do dispositivo após a auditoria de segurança.

Em ambos os casos, a política foi drasticamente reduzida em tamanho e número de permissões. A redução no tamanho da política é quase totalmente devido à remoção de permissões desnecessárias, muitas das quais eram provavelmente 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 recurso 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 adequada é 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.