Implementando SELinux

O SELinux está configurado para negar por padrão, o que significa que todo acesso para o qual ele possui 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 agora é essencial compreender como escrever regras de política ao criar 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 principais

Para habilitar o SELinux, integre o kernel Android mais recente e, em seguida, incorpore os arquivos encontrados no diretório system/sepolicy . Quando compilados, esses arquivos constituem 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 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 posteriores, as alterações feitas nesses arquivos devem afetar apenas a política no seu diretório de fornecedores. Para obter mais detalhes sobre a separação da sepolicy pública no Android 8.0 e superior, consulte Personalização da SEPolicy no Android 8.0+ . Independentemente da versão do Android, você ainda está modificando estes arquivos:

Arquivos de política

Arquivos que terminam com *.te são arquivos de origem de políticas do SELinux, que definem domínios e seus rótulos. Talvez seja 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 aos 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 novos file_contexts , reconstrua a imagem do sistema de arquivos ou execute restorecon no arquivo a ser renomeado. Nas atualizações, as alterações em file_contexts são aplicadas automaticamente ao sistema e às partições userdata como parte da atualização. As alterações também podem ser aplicadas automaticamente na atualização para outras partições, adicionando chamadas restorecon_recursive ao seu init. board .rc após a partição ter sido montada em leitura e gravação.
  • genfs_contexts atribui rótulos a sistemas de arquivos, como proc ou vfat , que não suportam atributos estendidos. Esta configuração é carregada como parte da política do kernel, mas as alterações podem não ter efeito para inodes in-core, 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 init durante a inicialização.
  • service_contexts atribui rótulos aos serviços de binder do Android para controlar quais processos podem adicionar (registrar) e encontrar (pesquisar) uma referência de binder para o serviço. Esta configuração é lida pelo processo 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 pelo 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 então 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 por 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. O Keystore 2.0 também impõe namespaces definidos pela 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 de 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 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 estará habilitado com SELinux. Agora você pode personalizar suas políticas 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 estiverem em vigor, as novas configurações de política serão automaticamente incorporadas ao arquivo de política do kernel final. Para obter mais informações sobre como a sepolicy é criada no dispositivo, consulte Construindo sepolicy .

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
    Isto seja 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 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 em busca de avisos semelhantes a 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 arquivos novos que precisam ser rotulados.
  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 enquadrará na política, mas por vezes será necessário um novo rótulo e serão necessárias regras para o 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. Provavelmente, você precisará escrever uma política completamente nova para cada um. Todos os serviços gerados a partir de init , por exemplo, devem ter os 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 do seu processo de desenvolvimento para evitar adicionar regras ao init ou confundir os 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 o arquivo init. 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. Analise cada negação e crie uma política SELinux para lidar adequadamente com cada uma. Veja os exemplos em Customização .

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

Casos de uso

Aqui estão exemplos específicos de explorações a serem consideradas 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 serem excessivamente abertos.

Os invasores podem então substituir esses arquivos por links simbólicos para o código que controlam, permitindo que o invasor substitua arquivos arbitrários. Mas se você sabe que seu aplicativo nunca atravessará um link simbólico, você pode proibi-lo de fazer isso com o SELinux.

Arquivos de sistema - Considere a classe de arquivos de sistema que deve ser modificada 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 fosse comprometido, ele não poderia mudar de domínio para o domínio do servidor do sistema e acessar esses arquivos do sistema, embora fosse executado como root.

Dados do aplicativo - Outro exemplo é a classe de funções que deve ser executada como root, mas não deve acessar os dados do aplicativo. Isso é extremamente útil, pois podem ser feitas afirmações abrangentes, como a proibição de acesso à Internet de determinados domínios não relacionados aos dados do aplicativo.

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, até mesmo pelo root. Portanto, um aplicativo pode executar chmod e chown naqueles rotulados, app_data_files , mas não em shell_data_files ou system_data_files .