Implementar o SELinux

O SELinux é configurado para negar por padrão, o que significa que cada acesso para o qual ele tem um gancho no kernel precisa ser explicitamente permitido pela política. Isso significa que um arquivo de política é composto por uma grande quantidade de informações sobre regras, tipos, classes, permissões e muito mais. Uma consideração completa do SELinux está fora do escopo deste documento, mas entender como escrever regras de política agora é essencial ao usar novos dispositivos Android. Já há muitas informações disponíveis sobre o SELinux. Consulte a documentação de suporte para conferir recursos sugeridos.

Arquivos de chave

Para ativar o SELinux, integre o kernel do Android mais recente e incorpore os arquivos encontrados no diretório system/sepolicy. Quando compilados, esses arquivos compreendem a política de segurança do kernel SELinux e abrangem o sistema operacional Android upstream.

Em geral, não modifique os arquivos system/sepolicy diretamente. Em vez disso, adicione ou edite seus próprios arquivos de política específicos do dispositivo no diretório /device/manufacturer/device-name/sepolicy. No Android 8.0 e versões mais recentes, as mudanças feitas nesses arquivos só afetam a política no diretório do fornecedor. Para mais detalhes sobre a separação de sepolicy pública no Android 8.0 e versões mais recentes, consulte Personalizar SEPolicy no Android 8.0 e versões mais recentes. Independentemente da versão do Android, você ainda vai modificar estes arquivos:

Arquivos de política

Os arquivos que terminam com *.te são arquivos de origem da política do SELinux, que definem domínios e rótulos. Talvez seja necessário criar novos arquivos de política em /device/manufacturer/device-name/sepolicy, mas tente atualizar os arquivos atuais sempre que possível.

Arquivos de contexto

Os arquivos de contexto são onde você especifica rótulos para seus objetos.

  • file_contexts atribui rótulos a arquivos e é usado por vários componentes do espaço do usuário. À medida que você cria novas políticas, crie ou atualize esse arquivo para atribuir novos rótulos aos arquivos. Para aplicar um novo file_contexts, reconstrua a imagem do sistema de arquivos ou execute restorecon no arquivo a ser remarcado. Em upgrades, as mudanças em file_contexts são aplicadas automaticamente ao sistema e às partições de userdata como parte do upgrade. As mudanças também podem ser aplicadas automaticamente no upgrade para outras partições adicionando chamadas restorecon_recursive ao arquivo init.board.rc depois que a partição for montada para leitura e gravação.
  • genfs_contexts atribui rótulos a sistemas de arquivos, como proc ou vfat, que não oferecem suporte a atributos estendidos. Essa configuração é carregada como parte da política do kernel, mas as mudanças podem não entrar em vigor para inodes no núcleo, exigindo uma reinicialização ou desmontagem e remontagem do sistema de arquivos para aplicar totalmente a mudança. Rótulos específicos também podem ser atribuídos a montagens específicas, como vfat usando a opção context=mount.
  • property_contexts atribui rótulos às propriedades do sistema Android para controlar quais processos podem defini-los. Essa configuração é lida pelo processo init durante a inicialização.
  • service_contexts atribui rótulos aos serviços de vinculação do Android para controlar quais processos podem adicionar (registrar) e encontrar (procurar) uma referência de vinculação para o serviço. Essa configuração é lida pelo processo servicemanager durante a inicialização.
  • seapp_contexts atribui rótulos a processos de apps e diretórios /data/data. Essa configuração é lida pelo processo zygote em cada inicialização do app e pelo installd durante a inicialização.
  • mac_permissions.xml atribui uma tag seinfo a apps com base na assinatura e, opcionalmente, no nome do pacote. A tag seinfo pode ser usada como uma chave no arquivo seapp_contexts para atribuir um rótulo específico a todos os apps com essa tag seinfo. Essa configuração é lida por system_server durante a inicialização.
  • keystore2_key_contexts atribui rótulos aos namespaces do Keystore 2.0. Esse namespace é aplicado pelo daemon keystore2. O keystore sempre forneceu namespaces baseados em UID/AID. O Keystore 2.0 também aplica namespaces definidos pela sepolicy. Confira aqui uma descrição detalhada do formato e das convenções desse arquivo.

Makefile BoardConfig.mk

Depois de editar ou adicionar arquivos de política e contexto, atualize o /device/manufacturer/device-name/BoardConfig.mk makefile para fazer referência ao subdiretório sepolicy e a cada novo arquivo de política. Para mais informações sobre as variáveis BOARD_SEPOLICY, consulte arquivo system/sepolicy/README.

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

Após a recriação, o dispositivo é ativado com o SELinux. Agora é possível personalizar suas políticas do SELinux para acomodar suas próprias adições ao sistema operacional Android, conforme descrito em Personalização, ou verificar sua configuração atual, conforme descrito em Validação.

Quando os novos arquivos de política e as atualizações do BoardConfig.mk estiverem em vigor, as novas configurações de política serão criadas automaticamente no arquivo de política do kernel final. Para mais informações sobre como o sepolicy é criado no dispositivo, consulte Como criar o sepolicy.

Implementação

Para começar a usar o SELinux:

  1. Ative o SELinux no kernel: CONFIG_SECURITY_SELINUX=y
  2. Mude o parâmetro kernel_cmdline ou bootconfig para que:
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    ou
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    Isso é apenas para o desenvolvimento inicial da política para o dispositivo. Depois de ter uma política de inicialização inicial, remova esse parâmetro para que o dispositivo seja aplicado ou falhe no CTS.
  3. Inicialize o sistema em modo permissivo e veja quais negações são encontradas na inicialização:
    No Ubuntu 14.04 ou mais recente:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    No Ubuntu 12.04:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. Avalie a saída em busca de avisos semelhantes a init: Warning! Service name needs a SELinux domain defined; please fix!. Consulte Validação para instruções e ferramentas.
  5. Identifique dispositivos e outros novos arquivos que precisam ser rotulados.
  6. Use rótulos novos ou já existentes para seus objetos. Analise os arquivos *_contexts para saber como as coisas foram rotuladas anteriormente e use o conhecimento dos significados dos rótulos para atribuir um novo. O ideal é que seja um rótulo existente que se encaixe na política, mas às vezes é necessário um novo rótulo e regras para o acesso a ele. Adicione os rótulos aos arquivos de contexto apropriados.
  7. Identifique domínios/processos que precisam ter domínios de segurança próprios. Provavelmente, você precisará escrever uma política completamente nova para cada um. Todos os serviços gerados a partir de init, por exemplo, precisam ter o próprio. Os comandos a seguir ajudam a revelar aqueles que continuam em execução (mas TODOS os serviços precisam desse tratamento):
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. Analise init.device.rc para identificar os domínios que não têm um tipo. Forneça um domínio cedo no processo de desenvolvimento para evitar a adição de regras ao init ou confundir os acessos init com os que estão na própria política.
  9. Configure BOARD_CONFIG.mk para usar variáveis BOARD_SEPOLICY_*. Consulte o README em system/sepolicy para saber como configurar isso.
  10. Examine o arquivo init.device.rc e fstab.device e confira se cada uso de mount corresponde a um sistema de arquivos corretamente identificado ou se uma opção context= mount foi especificada.
  11. Analise cada negação e crie uma política SELinux para processar cada uma delas. Consulte os exemplos em Personalização.

Comece com as políticas do AOSP e depois crie suas próprias personalizações. Para mais informações sobre a estratégia de política e uma análise mais detalhada de algumas dessas etapas, consulte Como escrever uma política do SELinux.

Casos de uso

Confira exemplos específicos de exploits a serem considerados ao criar seu próprio software e as políticas SELinux associadas:

Links simbólicos:como eles aparecem como arquivos, geralmente são lidos como arquivos, o que pode levar a exploits. Por exemplo, alguns componentes privilegiados, como init, mudam as permissões de determinados arquivos, às vezes para serem excessivamente abertos.

Os invasores podem substituir esses arquivos por links simbólicos para o código que eles controlam, permitindo que o invasor sobrescreva arquivos arbitrários. No entanto, se você souber que o app nunca atravessa um link simbólico, poderá proibir isso com o SELinux.

Arquivos do sistema:considere a classe de arquivos do sistema que deve ser modificada apenas pelo servidor do sistema. No entanto, como netd, init e vold são executados como raiz, eles podem acessar esses arquivos do sistema. Portanto, se o netd for comprometido, ele poderá comprometer esses arquivos e, possivelmente, o próprio servidor do sistema.

Com o SELinux, é possível identificar esses arquivos como arquivos de dados do servidor do sistema. Portanto, o único domínio com acesso de leitura/gravação é o servidor do sistema. Mesmo que o netd tenha sido comprometido, ele não poderia mudar de domínio para o do servidor do sistema e acessar esses arquivos do sistema, embora seja executado como raiz.

Dados do app:outro exemplo é a classe de funções que precisa ser executada como raiz, mas não pode acessar os dados do app. Isso é muito útil, porque é possível fazer várias declarações, como a proibição de acesso à Internet de determinados domínios não relacionados aos dados do app.

setattr:para comandos como chmod e chown, é possível identificar o conjunto de arquivos em que o domínio associado pode realizar setattr. Qualquer coisa fora disso pode ser proibida dessas mudanças, mesmo por raiz. Assim, um app pode executar chmod e chown em relação aos rotulados app_data_files, mas não shell_data_files ou system_data_files.