Implementando o SELinux

O SELinux está configurado para negação padrão, o que significa que cada acesso para o qual ele tem um gancho no kernel deve 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 uma compreensão de como escrever regras de política agora é essencial ao trazer novos dispositivos Android. Já existe uma grande quantidade de informações disponíveis sobre o SELinux. Consulte a documentação de suporte para recursos sugeridos.

Arquivos de chave

Para habilitar o SELinux, integre o kernel 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 cobrem o sistema operacional Android upstream.

Em geral, você não deve modificar os arquivos do 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 superior, as alterações feitas nesses arquivos devem afetar apenas a política no diretório do fornecedor. Para obter mais detalhes sobre a separação da política de segurança pública no Android 8.0 e superior, consulte Personalizando SEPolicy no Android 8.0+ . 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 SELinux, que definem domínios e seus rótulos. Pode ser necessário criar novos arquivos de política em /device/ manufacturer / device-name /sepolicy , mas você deve tentar atualizar os arquivos existentes 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 este arquivo para atribuir novos rótulos aos arquivos. Para aplicar novos file_contexts , reconstrua a imagem do sistema de arquivos ou execute restorecon no arquivo a ser rotulado novamente. Em upgrades, as alterações em file_contexts são aplicadas automaticamente ao sistema e às partições userdata como parte do upgrade. As alterações também podem ser aplicadas automaticamente na atualização para outras partições adicionando chamadas restorecon_recursive ao seu arquivo init. board .rc após a partição ter sido montada leitura-gravação.
  • genfs_contexts atribui rótulos a sistemas de arquivos, como proc ou vfat que não suportam atributos estendidos. Essa configuração é carregada como parte da política do kernel, mas as alterações podem não ter efeito para inodes no núcleo, exigindo uma reinicialização ou desmontagem e remontagem do sistema de arquivos para aplicar totalmente a alteração. 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. Esta configuração é lida pelo processo de init durante a inicialização.
  • service_contexts atribui rótulos a serviços de binder do Android para controlar quais processos podem adicionar (registrar) e encontrar (procurar) uma referência de binder para o serviço. Essa configuração é lida pelo processo do servicemanager durante a inicialização.
  • seapp_contexts atribui rótulos a processos de aplicativos e diretórios /data/data . Essa configuração é lida pelo processo zygote em cada inicialização do aplicativo e por installd durante a inicialização.
  • mac_permissions.xml atribui uma tag seinfo aos aplicativos com base em sua 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 aplicativos com essa tag seinfo . Esta configuração é lida pelo system_server durante a inicialização.
  • keystore2_key_contexts atribui rótulos aos namespaces do Keystore 2.0. Esses namespaces são impostos pelo daemon keystore2. O keystore sempre forneceu namespaces baseados em UID/AID. Além disso, o Keystore 2.0 impõe namespaces definidos por sepolicy. Uma descrição detalhada do formato e convenções deste arquivo pode ser encontrada aqui .

Makefile BoardConfig.mk

Depois de editar ou adicionar arquivos de política e contexto, atualize seu makefile /device/ manufacturer / device-name /BoardConfig.mk para fazer referência ao subdiretório sepolicy e a cada novo arquivo de política. Para obter 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 reconstrução, seu dispositivo está habilitado com 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 sua configuração existente conforme abordado em Validação .

Quando os novos arquivos de política e as atualizações do BoardConfig.mk estão em vigor, as novas configurações de política são automaticamente incorporadas ao arquivo de política final do kernel. Para obter mais informações sobre como a política de segurança é criada no dispositivo, consulte Criação de política de segurança .

Implementação

Para começar com o SELinux:

  1. Habilite o SELinux no kernel: CONFIG_SECURITY_SELINUX=y
  2. Altere 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 bootstrap inicial, remova esse parâmetro para que seu dispositivo seja aplicado ou ele falhará no CTS.
  3. Inicialize o sistema de forma permissiva 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 ao init: Warning! Service name needs a SELinux domain defined; please fix! Consulte Validação para obter instruções e ferramentas.
  5. Identifique dispositivos e outros novos arquivos que precisam de rotulagem.
  6. Use rótulos novos ou existentes para seus objetos. Observe os arquivos *_contexts para ver como as coisas foram rotuladas anteriormente e use o conhecimento dos significados dos rótulos para atribuir um novo. Idealmente, este será um rótulo existente que se encaixará na política, mas às vezes será necessário um novo rótulo e serão necessárias regras para acesso a esse rótulo. Adicione seus rótulos aos arquivos de contexto apropriados.
  7. Identifique domínios/processos que devem ter seus próprios domínios de segurança. Você provavelmente precisará escrever uma política completamente nova para cada um. Todos os serviços gerados a partir do init , por exemplo, devem ter seus próprios. Os comandos a seguir ajudam a revelar aqueles que permanecem 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. Revise init. device .rc para identificar quaisquer domínios que não tenham um tipo de domínio. Dê a eles um domínio no início de seu processo de desenvolvimento para evitar adicionar regras ao init ou confundir acessos init com aqueles que estão em sua própria política.
  9. Configure BOARD_CONFIG.mk para usar variáveis BOARD_SEPOLICY_* . Consulte o README em system/sepolicy para obter detalhes sobre como configurar isso.
  10. Examine a inicialização. device .rc e fstab. device e certifique-se de que cada uso de mount corresponda a um sistema de arquivos devidamente rotulado ou que uma opção context= mount seja especificada.
  11. Passe por cada negação e crie uma política SELinux para lidar adequadamente com cada uma. Veja os exemplos em Personalização .

Você deve começar com as políticas no AOSP e depois criá-las para suas próprias personalizações. Para obter mais informações sobre a estratégia de política e uma análise mais detalhada de algumas dessas etapas, consulte Writing SELinux Policy .

Casos de uso

Aqui estão exemplos específicos de exploits a serem considerados ao criar seu próprio software e políticas SELinux associadas:

Links simbólicos - Como os links simbólicos aparecem como arquivos, eles geralmente são lidos como arquivos, o que pode levar a explorações. Por exemplo, alguns componentes privilegiados, como init , alteram as permissões de determinados arquivos, às vezes para ficarem 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. Mas se você sabe que seu aplicativo nunca atravessará um link simbólico, você pode proibi-lo de fazê-lo com o SELinux.

Arquivos do sistema - Considere a classe dos arquivos do sistema que devem ser modificados apenas pelo servidor do sistema. Ainda assim, como netd , init e vold são executados como root, eles podem acessar esses arquivos do sistema. Portanto, se netd for comprometido, poderá comprometer esses arquivos e potencialmente o próprio servidor do sistema.

Com o SELinux, você pode 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 comprometido, ele não pode alternar domínios para o domínio do servidor do sistema e acessar esses arquivos do sistema, embora seja executado como root.

Dados do aplicativo - Outro exemplo é a classe de funções que devem ser executadas como root, mas não devem acessar os dados do aplicativo. Isso é incrivelmente útil, pois afirmações abrangentes podem ser feitas, como certos domínios não relacionados a dados de aplicativos serem proibidos de acessar a Internet.

setattr - Para comandos como chmod e chown , você pode identificar o conjunto de arquivos onde o domínio associado pode conduzir setattr . Qualquer coisa fora disso pode ser proibida dessas alterações, mesmo pelo root. Portanto, um aplicativo pode executar chmod e chown contra esses app_data_files rotulados, mas não shell_data_files ou system_data_files .