Criar a política do SELinux

Esta página explica como a política do SELinux é criada. A política do SELinux é criada com a combinação da política principal do AOSP (plataforma) e da política específica do dispositivo (fornecedor). O fluxo de build da política do SELinux para Android 4.4 a 7.0 mesclava todos os fragmentos de sepolicy e gerava arquivos monolíticos no diretório raiz. Isso significava que os fornecedores de SoC e os fabricantes de ODM modificavam boot.img (para dispositivos não A/B) ou system.img (para dispositivos A/B) sempre que a política era modificada.

No Android 8.0 e versões mais recentes, a política da plataforma e do fornecedor é criada separadamente. Os SOCs e OEMs podem atualizar as partes da política, criar imagens (como vendor.img e boot.img) e atualizar essas imagens independentemente das atualizações da plataforma.

No entanto, como os arquivos de política do SELinux modularizados são armazenados em partições /vendor, o processo init precisa montar as partições do sistema e do fornecedor antes para ler os arquivos do SELinux dessas partições e mesclar com os arquivos principais do SELinux no diretório do sistema (antes de carregá-los no kernel).

Arquivos de origem

A lógica para criar o SELinux está nestes arquivos:

  • external/selinux: projeto SELinux externo, usado para criar utilitários de linha de comando HOST para compilar políticas e rótulos do SELinux.
    • external/selinux/libselinux: o Android usa apenas um subconjunto do projeto libselinux externo, além de algumas personalizações específicas do Android. Para mais detalhes, consulte external/selinux/README.android.
    • external/selinux/libsepol:
      • chkcon: determina se um contexto de segurança é válido para uma determinada política binária (executável do host).
      • libsepol: biblioteca do SELinux para manipular políticas de segurança binárias (biblioteca estática/compartilhada do host, biblioteca estática de destino).
    • external/selinux/checkpolicy: compilador de políticas do SELinux (executáveis do host: checkpolicy, checkmodule e dispol). Depende de libsepol.
  • system/sepolicy: configurações principais da política do SELinux do Android, incluindo contextos e arquivos de política. A principal lógica de build da sepolicy também está aqui (system/sepolicy/Android.mk).

Para mais detalhes sobre os arquivos em system/sepolicy Implementando o SELinux.

Android 7.x e versões anteriores

Esta seção aborda como a política do SELinux é criada no Android 7.x e versões anteriores.

Processo de build para Android 7.x e versões anteriores

A política do SELinux é criada combinando a política principal do AOSP com personalizações específicas do dispositivo. A política combinada é transmitida ao compilador de políticas e a vários verificadores. A personalização específica do dispositivo é feita pela variável BOARD_SEPOLICY_DIRS definida no arquivo Boardconfig.mk específico do dispositivo. Essa variável de build global contém uma lista de diretórios que especificam a ordem em que os arquivos de política adicionais devem ser pesquisados.

Por exemplo, um fornecedor de SoC e um ODM podem adicionar um diretório cada um, um para as configurações específicas do SoC e outro para as configurações específicas do dispositivo, para gerar as configurações finais do SELinux para um determinado dispositivo:

  • BOARD_SEPOLICY_DIRS += device/SOC/common/sepolicy
  • BOARD_SEPOLICY_DIRS += device/SoC/DEVICE/sepolicy

O conteúdo dos arquivos file_contexts em system/sepolicy e BOARD_SEPOLICY_DIRS é concatenado para gerar o file_contexts.bin no dispositivo:

Esta imagem mostra a lógica de build do SELinux para o Android 7.x.

Figura 1. Lógica de build do SELinux.

O arquivo sepolicy consiste em vários arquivos de origem:

  • O texto simples policy.conf é gerado concatenando os arquivos security_classes, initial_sids, *.te, genfs_contexts e port_contexts nessa ordem.
  • Para cada arquivo (como security_classes), o conteúdo é a concatenação dos arquivos com o mesmo nome em system/sepolicy/ e BOARDS_SEPOLICY_DIRS.
  • O policy.conf é enviado ao compilador do SELinux para verificação de sintaxe e compilado em formato binário como sepolicy no dispositivo.
    Esta imagem mostra os arquivos que geram o arquivo de política do SELinux
                para o Android 7.x.

    Figura 2. Arquivo de política do SELinux.

Arquivos do SELinux

Depois da compilação, os dispositivos Android com versões 7.x e anteriores geralmente contêm os seguintes arquivos relacionados ao SELinux:

  • selinux_version
  • sepolicy: saída binária após combinar arquivos de política (como security_classes, initial_sids e *.te)
  • file_contexts
  • property_contexts
  • seapp_contexts
  • service_contexts
  • system/etc/mac_permissions.xml

Para mais detalhes, consulte Implementar o SELinux.

Inicialização do SELinux

Quando o sistema é inicializado, o SELinux está no modo permissivo (e não no modo de restrição). O processo init executa as seguintes tarefas:

  • Carrega arquivos sepolicy do ramdisk para o kernel usando /sys/fs/selinux/load.
  • Muda o SELinux para o modo de restrição.
  • Executa re-exec() para aplicar a regra de domínio do SELinux a si mesmo.

Para reduzir o tempo de inicialização, execute o re-exec() no processo init assim que possível.

Android 8.0 e versões mais recentes

No Android 8.0, a política do SELinux é dividida em componentes de plataforma e fornecedor para permitir atualizações independentes de política de plataforma/fornecedor, mantendo a compatibilidade.

A sepolicy da plataforma é dividida em partes privadas e públicas para exportar tipos e atributos específicos para gravadores de políticas de fornecedores. Os tipos/atributos públicos da plataforma têm garantia de serem mantidos como APIs estáveis para uma determinada versão da plataforma. A compatibilidade com tipos/atributos públicos de plataformas anteriores pode ser garantida em várias versões usando arquivos de mapeamento de plataforma.

Processo de build para o Android 8.0

A política do SELinux no Android 8.0 é feita combinando partes de /system e /vendor. A lógica para configurar isso adequadamente está em /platform/system/sepolicy/Android.mk.

A política existe nos seguintes locais:

Local Contém
system/sepolicy/public A API sepolicy da plataforma
system/sepolicy/private Detalhes da implementação da plataforma (os fornecedores podem ignorar)
system/sepolicy/vendor Arquivos de política e contexto que os fornecedores podem usar (podem ignorar se quiserem)
BOARD_SEPOLICY_DIRS sepolicy do fornecedor
BOARD_ODM_SEPOLICY_DIRS (Android 9 e versões mais recentes) Odm sepolicy
SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS (Android 11 e versões mais recentes) API sepolicy do system_ext
SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS (Android 11 e versões mais recentes) Detalhes da implementação do System_ext (os fornecedores podem ignorar)
PRODUCT_PUBLIC_SEPOLICY_DIRS (Android 11 e versões mais recentes) API sepolicy do produto
PRODUCT_PRIVATE_SEPOLICY_DIRS (Android 11 e versões mais recentes) Detalhes da implementação do produto (os fornecedores podem ignorar)

O sistema de build usa essa política e produz componentes de política do sistema, system_ext, produto, fornecedor e odm na partição correspondente. As etapas incluem:

  1. Converter políticas para o formato da linguagem intermediária comum (CIL) do SELinux, especificamente:
    1. política de plataforma pública (sistema + system_ext + produto)
    2. política privada e pública combinada
    3. pública + fornecedor e política de BOARD_SEPOLICY_DIRS
  2. Controle de versões da política fornecida pelo público como parte da política do fornecedor. Isso é feito usando a política pública de CIL produzida para informar à política combinada pública + fornecedor + BOARD_SEPOLICY_DIRS quais partes precisam ser transformadas em atributos que serão vinculados à política da plataforma.
  3. Criar um arquivo de mapeamento que vincule as partes da plataforma e do fornecedor. Inicialmente, isso apenas vincula os tipos da política pública aos atributos correspondentes na política do fornecedor. Depois, também vai fornecer a base para o arquivo mantido em versões futuras da plataforma, permitindo a compatibilidade com a política do fornecedor segmentando essa versão da plataforma.
  4. Combinar arquivos de política (descreva soluções no dispositivo e pré-compiladas).
    1. Combine o mapeamento, a plataforma e a política do fornecedor.
    2. Compile o arquivo de política binária de saída.

sepolicy pública da plataforma

A sepolicy pública da plataforma inclui tudo o que está definido em system/sepolicy/public. A plataforma pode presumir que os tipos e atributos definidos na política pública são APIs estáveis para uma determinada versão da plataforma. Isso forma a parte da sepolicy exportada pela plataforma em que os desenvolvedores de políticas de fornecedores (ou seja, de dispositivos) podem escrever políticas adicionais específicas do dispositivo.

Os tipos são versionados de acordo com a versão da política em que os arquivos do fornecedor são gravados, definida pela variável de build PLATFORM_SEPOLICY_VERSION. A política pública com controle de versão é incluída na política do fornecedor e (na forma original) na política da plataforma. Assim, a política final inclui a política de plataforma privada, a política pública do SELinux da plataforma atual, a política específica do dispositivo e a política pública com versão correspondente à versão da plataforma em que a política do dispositivo foi escrita.

sepolicy privada da plataforma

A sepolicy particular da plataforma inclui tudo o que está definido em /system/sepolicy/private. Essa parte da política forma tipos, permissões e atributos somente para plataforma necessários para a funcionalidade da plataforma. Elas não são exportadas para os gravadores de políticas vendor/device. Os criadores de políticas que não são da plataforma não podem escrever extensões de política com base em tipos/atributos/regras definidos na sepolicy privada da plataforma. Além disso, essas regras podem ser modificadas ou desaparecer como parte de uma atualização somente de framework.

Mapeamento particular da plataforma

O mapeamento privado da plataforma inclui declarações de política que mapeiam os atributos expostos na política pública da plataforma das versões anteriores para os tipos concretos usados na política pública de segurança atual da plataforma. Isso garante que a política do fornecedor, que foi escrita com base nos atributos públicos da plataforma das versões anteriores da política de segurança pública da plataforma, continue funcionando. O controle de versões é baseado na variável de build PLATFORM_SEPOLICY_VERSION definida no AOSP para uma determinada versão da plataforma. Há um arquivo de mapeamento separado para cada versão anterior da plataforma em que se espera que ela aceite a política do fornecedor. Para mais detalhes, consulte Compatibilidade.

Android 11 e versões mais recentes

system_ext e sepolicy do produto

No Android 11, as políticas system_ext e de produto são adicionadas. Assim como a sepolicy da plataforma, a política system_ext e a política de produto são divididas em pública e privada.

A política pública é exportada para o fornecedor. Os tipos e atributos se tornam uma API estável, e a política do fornecedor pode se referir a tipos e atributos na política pública. Os tipos são versionados de acordo com PLATFORM_SEPOLICY_VERSION, e a política versionada é incluída na política do fornecedor. A política original é incluída em cada partição system_ext e product.

A política de privacidade contém tipos, permissões e atributos somente do sistema_ext e somente do produto necessários para a funcionalidade das partições system_ext e de produto. A política particular é invisível para o fornecedor, o que significa que essas regras são internas e podem ser modificadas.

Mapeamento de system_ext e produto

system_ext e product podem exportar os tipos públicos designados para vendor. No entanto, a responsabilidade de manter a compatibilidade é de cada parceiro. Para compatibilidade, os parceiros podem fornecer os próprios arquivos de mapeamento, que mapeiam os atributos versionados de versões anteriores para tipos concretos usados na política de segurança pública atual.

  • Para instalar um arquivo de mapeamento para system_ext, coloque um arquivo cil contendo as informações de mapeamento desejadas em {SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil, e adicione system_ext_{ver}.cil a PRODUCT_PACKAGES.
  • Para instalar um arquivo de mapeamento de produto, coloque um arquivo cil com as informações de mapeamento desejadas em {PRODUCT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil e adicione product_{ver}.cil a PRODUCT_PACKAGES.

Consulte um exemplo que adiciona um arquivo de mapeamento da partição de produto do dispositivo Redbull.

Política do SELinux pré-compilada

Antes de init ativar o SELinux, ele coleta todos os arquivos CIL das partições (system, system_ext, product, vendor e odm) e os compila em uma política binária, o formato que pode ser carregado no kernel.init Como a compilação leva tempo (geralmente de 1 a 2 segundos), os arquivos CIL são pré-compilados no momento da criação e colocados em /vendor/etc/selinux/precompiled_sepolicy ou /odm/etc/selinux/precompiled_sepolicy, junto com os hashes sha256 dos arquivos CIL de entrada. Em tempo de execução, init verifica se algum arquivo de política foi atualizado comparando os hashes. Se nada tiver mudado, init vai carregar a política pré-compilada. Caso contrário, init será compilado na hora e usado em vez do pré-compilado.

Mais especificamente, uma política pré-compilada é usada se todas as condições a seguir forem atendidas. Aqui, {partition} representa a partição em que a política pré-compilada existe: vendor ou odm.

  • /system/etc/selinux/plat_sepolicy_and_mapping.sha256 e /{partition}/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256 existem e são idênticos.
  • /system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256 e /{partition}/etc/selinux/precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256 não existem. Ou ambos existem e são idênticos.
  • /product/etc/selinux/product_sepolicy_and_mapping.sha256 e /{partition}/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256 não existem. Ou ambos existem e são idênticos.

Se algum deles for diferente, o init vai voltar para o caminho de compilação no dispositivo. Consulte system/core/init/selinux.cpp para mais detalhes.