Implementar o SELinux

O SELinux é configurado para negar por padrão, o que significa que todo acesso para o qual ele tem um hook 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 ativar novos dispositivos Android. Já há muitas informações disponíveis sobre o SELinux. Consulte a documentação de suporte para recursos sugeridos.

Arquivos de chave

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

Em geral, não é recomendável modificar os arquivos system/sepolicy diretamente. Em vez disso, adicione ou edite seus próprios arquivos de política específicos do dispositivo no /device/manufacturer/device-name/sepolicy diretório. No Android 8.0 e mais recente, as mudanças feitas nesses arquivos só afetam a política no diretório do fornecedor. Para mais detalhes sobre a separação da sepolicy pública no Android 8.0 e mais recente, consulte Personalizar a SEPolicy no Android 8.0 e mais recente. Independentemente da versão do Android, você ainda está modificando 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. Ao criar novas políticas, crie ou atualize esse arquivo para atribuir novos rótulos aos arquivos. Para aplicar novos file_contexts, recrie a imagem do sistema de arquivos ou execute restorecon no arquivo a ser rotulado novamente. Em upgrades, as mudanças em file_contexts são aplicadas automaticamente às partições do sistema e de dados do usuário como parte do upgrade. As mudanças também podem ser aplicadas automaticamente no upgrade a outras partições adicionando chamadas restorecon_recursive ao arquivo init.board.rc depois que a partição for montada como leitura/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 a propriedades do sistema Android para controlar quais processos podem defini-los. Essa configuração é lida pelo init processo durante a inicialização.
  • service_contexts atribui rótulos aos serviços do binder do Android para controlar quais processos podem adicionar (registrar) e encontrar (pesquisar) uma referência do binder para o serviço. Essa configuração é lida pelo servicemanager processo durante a inicialização.
  • seapp_contexts atribui rótulos a processos de apps e /data/data diretórios. Essa configuração é lida pelo zygote processo em cada inicialização do app e por installd durante a inicialização.
  • mac_permissions.xml atribui uma tag seinfo aos 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. Esses namespaces são aplicados pelo daemon keystore2. O Keystore sempre forneceu namespaces baseados em UID/AID. O Keystore 2 também aplica namespaces definidos pela sepolicy. Uma descrição detalhada do formato e das convenções desse arquivo pode ser encontrada aqui.

Makefile BoardConfig.mk

Depois de editar ou adicionar arquivos de política e contexto, atualize o /device/manufacturer/device-name/BoardConfig.mk Makefile para referenciar o sepolicy subdiretório e cada novo arquivo de política. Para mais informações sobre as variáveis BOARD_SEPOLICY, consulte o 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 você pode personalizar suas políticas do SELinux para acomodar suas próprias adições ao sistema operacional Android, conforme descrito em Personalização ou verificar a configuração atual, conforme abordado 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 incorporadas automaticamente ao arquivo de política do kernel final. Para mais informações sobre como a sepolicy é criada no dispositivo, consulte Como criar a 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 do dispositivo. Depois de ter uma política de bootstrap inicial, remova esse parâmetro para que o dispositivo seja aplicado ou falhe no CTS.
  3. Inicialize o sistema no 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 para 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 de rótulos.
  6. Use rótulos atuais ou novos para seus objetos. Consulte 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 esse seja um rótulo atual que se encaixe na política, mas às vezes um novo rótulo é necessário, assim como regras de acesso a ele são necessárias. Adicione seus rótulos aos arquivos de contexto apropriados.
  7. Identifique domínios/processos que precisam ter seus próprios domínios de segurança. É provável que você precise escrever uma política completamente nova para cada um deles. 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 permanecem em execução (mas TODOS 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 domínios que não têm um tipo de domínio. Atribua um domínio no início do seu processo de desenvolvimento para evitar adicionar regras a init ou confundir os acessos init com aqueles 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 detalhes sobre a configuração.
  10. Examine o arquivo init.device.rc e fstab.device e verifique se cada uso de mount corresponde a um sistema de arquivos rotulado corretamente ou se uma opção context= mount está especificada.
  11. Analise cada negação e crie uma política do SELinux para processar cada uma delas corretamente. Consulte os exemplos em Personalização.

Comece com as políticas na AOSP e 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 políticas do SELinux associadas:

Links simbólicos:como os links simbólicos aparecem como arquivos, eles são lidos com frequência 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 controlam, permitindo que o invasor substitua arquivos arbitrários. No entanto, se você souber que seu app nunca atravessa um link simbólico, poderá proibi-lo de fazer isso com o SELinux.

Arquivos do sistema:considere a classe de arquivos do sistema que só podem ser modificados 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 netd for comprometido, ele poderá comprometer esses arquivos e, potencialmente, 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 que tem acesso de leitura/gravação a eles é o servidor do sistema. Mesmo que netd seja comprometido, ele não poderá mudar de domínio para o domínio 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 precisam ser executadas como raiz, mas não podem acessar dados do app. Isso é incrivelmente útil, já que declarações abrangentes podem ser feitas, como determinados domínios não relacionados a dados de apps que são proibidos de acessar a Internet.

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