Compatibilidade da política

Este artigo descreve como o Android lida com os problemas de compatibilidade de políticas com OTAs de plataforma, em que as configurações do SELinux da nova plataforma podem diferir das configurações do SELinux do fornecedor antigo.

O projeto de política SELinux baseado em agudos considera uma distinção binária entre política de plataforma e de fornecedor ; o esquema se torna mais complicado se as partições do fornecedor gerarem dependências, como platform < vendor < oem .

No Android 8.0 e superior, a política global do SELinux é dividida em componentes privados e públicos. Os componentes públicos consistem na política e na infraestrutura associada, que garantem a disponibilidade para uma versão da plataforma. Essa política será exposta aos criadores de políticas do fornecedor para permitir que os fornecedores criem um arquivo de política do fornecedor que, quando combinado com a política fornecida pela plataforma, resulta em uma política totalmente funcional para um dispositivo.

  • Para controle de versão, a política pública de plataforma exportada será escrita como atributos .
  • Para facilitar a escrita da política, os tipos exportados serão transformados em atributos com versão como parte do processo de criação da política. Os tipos públicos também podem ser usados ​​diretamente nas decisões de rotulagem fornecidas pelos arquivos de contexto do fornecedor.

O Android mantém um mapeamento entre os tipos concretos exportados na política da plataforma e os atributos de versão correspondentes para cada versão da plataforma . Isso garante que, quando os objetos forem rotulados com um tipo, ele não quebre o comportamento garantido pela política pública da plataforma em uma versão anterior. Esse mapeamento é mantido mantendo um arquivo de mapeamento atualizado para cada versão da plataforma , que mantém as informações de associação de atributos para cada tipo exportado na política pública.

Propriedade e rotulagem do objeto

Ao personalizar a política no Android 8.0 e superior, a propriedade deve ser claramente definida para cada objeto para manter a plataforma e a política do fornecedor separadas. Por exemplo, se o fornecedor rotular /dev/foo e a plataforma rotular /dev/foo em um OTA subsequente, haverá um comportamento indefinido. Para o SELinux, isso se manifesta como uma colisão de rotulagem. O nó do dispositivo pode ter apenas um único rótulo que resolve o rótulo aplicado por último. Como resultado:

  • Os processos que precisam de acesso ao rótulo aplicado sem sucesso perderão o acesso ao recurso.
  • Os processos que obtêm acesso ao arquivo podem ser interrompidos porque o nó de dispositivo incorreto foi criado.

As propriedades do sistema também têm potencial para colisões de nomes que podem resultar em comportamento indefinido no sistema (assim como para rotulagem do SELinux). Podem ocorrer colisões entre os rótulos da plataforma e do fornecedor para qualquer objeto que tenha um rótulo SELinux, incluindo propriedades, serviços, processos, arquivos e soquetes. Para evitar esses problemas, defina claramente a propriedade desses objetos.

Além das colisões de rótulos, os nomes de tipo/atributo do SELinux também podem colidir. Uma colisão de tipo/nome de atributo sempre resultará em um erro do compilador de política.

Namespace de tipo/atributo

O SELinux não permite múltiplas declarações do mesmo tipo/atributo. A política com declarações duplicadas não será compilada. Para evitar colisões de tipo e nome de atributo, todas as declarações de fornecedor devem ter namespace começando com np_ .

type foo, domain; → type np_foo, domain;

Propriedade do sistema e propriedade da rotulagem do processo

Evitar colisões de rotulagem é melhor resolvido usando namespaces de propriedade. Para identificar facilmente as propriedades da plataforma e evitar conflitos de nomes ao renomear ou adicionar propriedades de plataforma exportada, certifique-se de que todas as propriedades do fornecedor tenham seus próprios prefixos:

Tipo de Propriedade Prefixos aceitáveis
propriedades de controle ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
gravável vendor.
somente leitura ro.vendor.
ro.boot.
ro.hardware.
persistente persist.vendor.

Os fornecedores podem continuar a usar ro.boot.* (que vem do cmdline do kernel) e ro.hardware.* (uma propriedade óbvia relacionada ao hardware).

Todos os serviços do fornecedor nos arquivos init rc devem ter o vendor. para serviços em arquivos init rc de partições que não são do sistema. Regras semelhantes são aplicadas aos rótulos do SELinux para as propriedades do fornecedor ( vendor_ para as propriedades do fornecedor).

Propriedade do arquivo

Prevenir colisões de arquivos é um desafio porque a política de plataforma e de fornecedor geralmente fornece rótulos para todos os sistemas de arquivos. Ao contrário da nomeação de tipos, o namespace de arquivos não é prático, pois muitos deles são criados pelo kernel. Para evitar essas colisões, siga as orientações de nomenclatura para sistemas de arquivos nesta seção. Para o Android 8.0, estas são recomendações sem aplicação técnica. No futuro, essas recomendações serão aplicadas pelo Vendor Test Suite (VTS).

Sistema (/sistema)

Somente a imagem do sistema deve fornecer rótulos para /system componentes por meio de file_contexts , service_contexts , etc. Se rótulos para /system componentes forem adicionados na política /vendor , uma atualização OTA somente de estrutura pode não ser possível.

Fornecedor (/fornecedor)

A política AOSP SELinux já rotula partes da partição do vendor com as quais a plataforma interage, o que permite escrever regras SELinux para que os processos da plataforma possam conversar e/ou acessar partes da partição do vendor . Exemplos:

/vendor Rótulo fornecido pela plataforma Processos da plataforma dependendo do rótulo
/vendor(/. * )? vendor_file Todos os clientes HAL no framework, ueventd , etc.
/vendor/framework(/. * )? vendor_framework_file dex2oat , appdomain , etc.
/vendor/app(/. * )? vendor_app_file dex2oat , installd , idmap , etc.
/vendor/overlay(/. * ) vendor_overlay_file system_server , zygote , idmap , etc.

Como resultado, regras específicas devem ser seguidas (impostas por neverallows ) ao rotular arquivos adicionais na partição do vendor :

  • vendor_file deve ser o rótulo padrão para todos os arquivos na partição do vendor . A política da plataforma exige isso para acessar implementações de HAL de passagem.
  • Todos os novos exec_types adicionados na partição do vendor por meio do fornecedor SEPolicy devem ter o atributo vendor_file_type . Isso é aplicado através de neverallows.
  • Para evitar conflitos com futuras atualizações de plataforma/framework, evite rotular arquivos que não sejam exec_types na partição do vendor .
  • Todas as dependências de biblioteca para HALs do mesmo processo identificadas por AOSP devem ser rotuladas como same_process_hal_file.

Procfs (/proc)

Arquivos em /proc podem ser rotulados usando apenas o rótulo genfscon . No Android 7.0, tanto a plataforma quanto a política do fornecedor usavam genfscon para rotular arquivos em procfs .

Recomendação: somente rótulos de política de plataforma /proc . Se os processos do vendor precisarem de acesso a arquivos em /proc que estão atualmente rotulados com o rótulo padrão ( proc ), a política do fornecedor não deve rotulá-los explicitamente e deve usar o tipo proc genérico para adicionar regras para domínios de fornecedor. Isso permite que as atualizações da plataforma acomodem futuras interfaces de kernel expostas por meio de procfs e as rotulem explicitamente conforme necessário.

Debugfs (/sys/kernel/debug)

Debugfs pode ser rotulado em file_contexts e genfscon . No Android 7.0 ao Android 10, tanto a plataforma quanto o rótulo do fornecedor debugfs .

No Android 11, debugfs não pode ser acessado ou montado em dispositivos de produção. Os fabricantes de dispositivos devem remover debugfs .

Tracefs (/sys/kernel/debug/tracing)

Tracefs podem ser rotulados em file_contexts e genfscon . No Android 7.0, apenas a plataforma rotula tracefs .

Recomendação: Somente a plataforma pode rotular tracefs .

Sysfs (/sys)

Arquivos em /sys podem ser rotulados usando file_contexts e genfscon . No Android 7.0, tanto a plataforma quanto o fornecedor usam file_contexts e genfscon para rotular arquivos em sysfs .

Recomendação: A plataforma pode rotular nós sysfs que não são específicos do dispositivo. Caso contrário, apenas o fornecedor pode rotular os arquivos.

tmpfs (/dev)

Arquivos em /dev podem ser rotulados em file_contexts . No Android 7.0, arquivos de etiqueta de plataforma e fornecedor aqui.

Recomendação: O fornecedor pode rotular apenas arquivos em /dev/vendor (por exemplo, /dev/vendor/foo , /dev/vendor/socket/bar ).

Raiz (/)

Arquivos em / podem ser rotulados em file_contexts . No Android 7.0, arquivos de etiqueta de plataforma e fornecedor aqui.

Recomendação: Somente o sistema pode rotular arquivos em / .

Dados (/dados)

Os dados são rotulados por meio de uma combinação de file_contexts e seapp_contexts .

Recomendação: não permita a rotulagem do fornecedor fora /data/vendor . Somente a plataforma pode rotular outras partes de /data .

Atributos de compatibilidade

A política SELinux é uma interação entre os tipos de origem e destino para classes de objetos e permissões específicas. Cada objeto (processos, arquivos, etc.) afetado pela política do SELinux pode ter apenas um tipo, mas esse tipo pode ter vários atributos.

A política é escrita principalmente em termos de tipos existentes:

allow source_type target_type:target_class permission(s);

Isso funciona porque a política foi escrita com conhecimento de todos os tipos. No entanto, se a política do fornecedor e a política da plataforma usarem tipos específicos e o rótulo de um objeto específico mudar em apenas uma dessas políticas, a outra poderá conter a política que ganhou ou perdeu acesso anteriormente confiado. Por exemplo:

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

Pode ser alterado para:

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

Embora a política do fornecedor permanecesse a mesma, o v_domain perderia acesso devido à falta de política para o novo tipo sysfs_A .

Ao definir uma política em termos de atributos, podemos dar ao objeto subjacente um tipo que tenha um atributo correspondente à política tanto para a plataforma quanto para o código do fornecedor. Isso pode ser feito para todos os tipos para criar efetivamente uma política de atributos em que os tipos concretos nunca são usados. Na prática, isso é necessário apenas para as partes da política que se sobrepõem entre plataforma e fornecedor, que são definidas e fornecidas como política pública de plataforma que é criada como parte da política do fornecedor.

Definir a política pública como atributos com versão atende a duas metas de compatibilidade de política:

  • Certifique-se de que o código do fornecedor continue funcionando após a atualização da plataforma . Obtido pela adição de atributos a tipos concretos para objetos correspondentes àqueles nos quais o código do fornecedor dependia, preservando o acesso.
  • Capacidade de descontinuar a política . Obtido ao delinear claramente os conjuntos de políticas em atributos que podem ser removidos assim que a versão à qual eles correspondem não for mais suportada. O desenvolvimento pode continuar na plataforma, sabendo que a política antiga ainda está presente na política do fornecedor e será removida automaticamente quando/se for atualizada.

Capacidade de escrita da política

Para atingir o objetivo de não exigir conhecimento de alterações de versão específicas para o desenvolvimento de políticas, o Android 8.0 inclui um mapeamento entre os tipos de política pública de plataforma e seus atributos. O tipo foo é mapeado para o atributo foo_v N , em que N é a versão de destino. vN corresponde à variável de construção PLATFORM_SEPOLICY_VERSION e tem o formato MM.NN , em que MM corresponde ao número do SDK da plataforma e NN é uma versão específica da sepolicy da plataforma.

Os atributos na política pública não são versionados, mas existem como uma API na qual a plataforma e a política do fornecedor podem ser construídas para manter a interface entre as duas partições estável. Tanto os redatores de políticas da plataforma quanto do fornecedor podem continuar a escrever as políticas como estão escritas hoje.

Política pública de plataforma exportada como allow source_foo target_bar: class perm ; está incluído como parte da política do fornecedor. Durante a compilação (que inclui a versão correspondente) ela é transformada na política que irá para a parte do fornecedor do dispositivo (mostrada na Common Intermediate Language (CIL) transformada):

 (allow source_foo_vN target_bar_vN (class (perm)))

Como a política do fornecedor nunca está à frente da plataforma, ela não deve se preocupar com versões anteriores. No entanto, a política da plataforma precisará saber até onde está a política do fornecedor, incluir atributos para seus tipos e definir a política correspondente aos atributos com versão.

Diferenças de política

A criação automática de atributos adicionando _v N ao final de cada tipo não faz nada sem o mapeamento de atributos para tipos em diferenças de versão. O Android mantém um mapeamento entre versões para atributos e um mapeamento de tipos para esses atributos. Isso é feito nos arquivos de mapeamento mencionados acima com instruções, como (CIL):

(typeattributeset foo_vN (foo))

Atualizações da plataforma

A seção a seguir detalha os cenários para atualizações de plataforma.

Mesmos tipos

Esse cenário ocorre quando um objeto não altera os rótulos nas versões de política. Isso é o mesmo para os tipos de origem e destino e pode ser visto com /dev/binder , rotulado como binder_device em todas as versões. É representado na política transformada como:

binder_device_v1 … binder_device_vN

Ao atualizar de v1v2 , a política da plataforma deve conter:

type binder_device; -> (type binder_device) (in CIL)

No arquivo de mapeamento v1 (CIL):

(typeattributeset binder_device_v1 (binder_device))

No arquivo de mapeamento v2 (CIL):

(typeattributeset binder_device_v2 (binder_device))

Na política de fornecedor v1 (CIL):

(typeattribute binder_device_v1)
(allow binder_device_v1 …)

Na política de fornecedor v2 (CIL):

(typeattribute binder_device_v2)
(allow binder_device_v2 …)
Novos tipos

Esse cenário ocorre quando a plataforma adiciona um novo tipo, o que pode acontecer ao adicionar novos recursos ou durante o fortalecimento da política.

  • Novo recurso . Quando o tipo está rotulando um objeto que não existia anteriormente (como um novo processo de serviço), o código do fornecedor não interagiu diretamente com ele anteriormente, portanto, não existe uma política correspondente. O novo atributo correspondente ao tipo não possui um atributo na versão anterior e, portanto, não precisaria de uma entrada no arquivo de mapeamento destinado a essa versão.
  • Endurecimento da política . Quando o tipo representa proteção de política, o novo atributo de tipo deve se vincular novamente a uma cadeia de atributos correspondente ao anterior (semelhante ao exemplo anterior, alterando /sys/A de sysfs para sysfs_A ). O código do fornecedor depende de uma regra que permite o acesso a sysfs e precisa incluir essa regra como um atributo do novo tipo.

Ao atualizar de v1v2 , a política da plataforma deve conter:

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

No arquivo de mapeamento v1 (CIL):

(typeattributeset sysfs_v1 (sysfs sysfs_A))

No arquivo de mapeamento v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

Na política de fornecedor v1 (CIL):

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

Na política de fornecedor v2 (CIL):

(typeattribute sysfs_A_v2)
(allow … sysfs_A_v2 …)
(typeattribute sysfs_v2)
(allow … sysfs_v2 …)
Tipos removidos

Esse cenário (raro) ocorre quando um tipo é removido, o que pode acontecer quando o objeto subjacente:

  • Permanece, mas recebe um rótulo diferente.
  • É removido pela plataforma.

Durante o afrouxamento da política, um tipo é removido e o objeto rotulado com esse tipo recebe um rótulo diferente já existente. Isso representa uma fusão de mapeamentos de atributos: o código do fornecedor ainda deve poder acessar o objeto subjacente pelo atributo que costumava possuir, mas o restante do sistema deve agora poder acessá-lo com seu novo atributo.

Se o atributo para o qual foi trocado for novo, então a reetiquetagem é a mesma que no caso do novo tipo, exceto que quando um rótulo existente é usado, a adição do atributo antigo novo tipo faria com que outros objetos também rotulados com este tipo para ser recém-acessível. Isso é essencialmente o que é feito pela plataforma e é considerado uma compensação aceitável para manter a compatibilidade.

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

Exemplo de versão 1: recolhimento de tipos (remoção de sysfs_A)

Ao atualizar de v1v2 , a política da plataforma deve conter:

type sysfs; (type sysfs) (in CIL)

No arquivo de mapeamento v1 (CIL):

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

No arquivo de mapeamento v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))

Na política de fornecedor v1 (CIL):

(typeattribute sysfs_A_v1)
(allow … sysfs_A_v1 …)
(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

Na política de fornecedor v2 (CIL):

(typeattribute sysfs_v2)
(allow … sysfs_v2 …)

Exemplo de versão 2: removendo completamente (tipo foo)

Ao atualizar de v1v2 , a política da plataforma deve conter:

# nothing - we got rid of the type

No arquivo de mapeamento v1 (CIL):

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

No arquivo de mapeamento v2 (CIL):

# nothing - get rid of it

Na política de fornecedor v1 (CIL):

(typeattribute foo_v1)
(allow foo …)
(typeattribute sysfs_v1)
(allow sysfs_v1 …)

Na política de fornecedor v2 (CIL):

(typeattribute sysfs_v2)
(allow sysfs_v2 …)
Nova classe/permissões

Esse cenário ocorre quando uma atualização de plataforma introduz novos componentes de política que não existem nas versões anteriores. Por exemplo, quando o Android adicionou o gerenciador de objetos servicemanager que criou as permissões add, find e list, os daemons do fornecedor que desejavam se registrar no servicemanager precisavam de permissões que não estavam disponíveis. No Android 8.0, apenas a política da plataforma pode adicionar novas classes e permissões.

Para permitir que todos os domínios que possam ter sido criados ou estendidos pela política do fornecedor usem a nova classe sem obstrução, a política da plataforma precisa incluir uma regra semelhante a:

allow {domain -coredomain} *:new_class perm;

Isso pode até exigir uma política que permita o acesso a todos os tipos de interface (política pública), para garantir que a imagem do fornecedor tenha acesso. Se isso resultar em uma política de segurança inaceitável (como pode acontecer com as alterações do servicemanager), uma atualização do fornecedor pode ser forçada.

Classe/permissões removidas

Esse cenário ocorre quando um gerenciador de objetos é removido (como o gerenciador de objetos ZygoteConnection ) e não deve causar problemas. A classe e as permissões do gerenciador de objetos podem permanecer definidas na política até que a versão do fornecedor não a utilize mais. Isso é feito adicionando as definições ao arquivo de mapeamento correspondente.

Personalização do fornecedor para tipos novos/remarcados

Novos tipos de fornecedores estão no centro do desenvolvimento de políticas de fornecedores, pois são necessários para descrever novos processos, binários, dispositivos, subsistemas e dados armazenados. Como tal, é imperativo permitir a criação de tipos definidos pelo fornecedor.

Como a política do fornecedor é sempre a mais antiga no dispositivo, não há necessidade de converter automaticamente todos os tipos de fornecedores em atributos na política. A plataforma não depende de nada rotulado na política do fornecedor porque a plataforma não tem conhecimento disso; no entanto, a plataforma fornecerá os atributos e tipos públicos que usa para interagir com objetos rotulados com esses tipos (como domain , sysfs_type , etc.). Para que a plataforma continue a interagir corretamente com esses objetos, os atributos e tipos devem ser aplicados adequadamente e regras específicas podem precisar ser adicionadas aos domínios personalizáveis ​​(como init ).

Alterações de atributo para Android 9

Os dispositivos atualizados para o Android 9 podem usar os atributos a seguir, mas os dispositivos iniciados com o Android 9 não devem.

Atributos do infrator

O Android 9 inclui estes atributos relacionados ao domínio:

  • data_between_core_and_vendor_violators . Atributo para todos os domínios que violam o requisito de não compartilhar arquivos por caminho entre o vendor e coredomains . Os processos da plataforma e do fornecedor não devem usar arquivos em disco para se comunicar (ABI instável). Recomendação:
    • O código do fornecedor deve usar /data/vendor .
    • O sistema não deve usar /data/vendor .
  • system_executes_vendor_violators . Atributo para todos os domínios do sistema (exceto domínios init e shell domains ) que violam o requisito de não executar binários do fornecedor. A execução dos binários do fornecedor tem uma API instável. A plataforma não deve executar binários de fornecedores diretamente. Recomendação:
    • Essas dependências de plataforma em binários de fornecedores devem estar por trás de HIDL HALs.

      OU

    • coredomains que precisam de acesso aos binários do fornecedor devem ser movidos para a partição do fornecedor e, assim, deixar de ser coredomain .

Atributos não confiáveis

Aplicativos não confiáveis ​​que hospedam código arbitrário não devem ter acesso aos serviços HwBinder, exceto aqueles considerados suficientemente seguros para acesso de tais aplicativos (veja serviços seguros abaixo). As duas principais razões para isso são:

  1. Servidores HwBinder não executam autenticação de cliente porque HIDL atualmente não expõe informações de UID do chamador. Mesmo que o HIDL tenha exposto esses dados, muitos serviços HwBinder operam em um nível inferior ao dos aplicativos (como HALs) ou não devem depender da identidade do aplicativo para autorização. Assim, por segurança, a suposição padrão é que todo serviço HwBinder trate todos os seus clientes como igualmente autorizados a realizar as operações oferecidas pelo serviço.
  2. Os servidores HAL (um subconjunto de serviços HwBinder) contêm código com maior taxa de incidência de problemas de segurança do que os componentes do system/core e têm acesso às camadas inferiores da pilha (até o hardware), aumentando assim as oportunidades de contornar o modelo de segurança do Android .

Serviços seguros

Os serviços seguros incluem:

  • same_process_hwservice . Esses serviços (por definição) são executados no processo do cliente e, portanto, têm o mesmo acesso que o domínio do cliente no qual o processo é executado.
  • coredomain_hwservice . Esses serviços não apresentam riscos associados ao motivo nº 2.
  • hal_configstore_ISurfaceFlingerConfigs . Este serviço foi projetado especificamente para uso por qualquer domínio.
  • hal_graphics_allocator_hwservice . Essas operações também são oferecidas pelo serviço surfaceflinger Binder, que os aplicativos têm permissão para acessar.
  • hal_omx_hwservice . Esta é uma versão HwBinder do serviço mediacodec Binder, que os aplicativos têm permissão para acessar.
  • hal_codec2_hwservice . Esta é uma versão mais recente do hal_omx_hwservice .

Atributos utilizáveis

Todos os hwservices não considerados seguros possuem o atributo untrusted_app_visible_hwservice . Os servidores HAL correspondentes possuem o atributo untrusted_app_visible_halserver . Dispositivos iniciados com Android 9 NÃO DEVEM usar nenhum atributo untrusted .

Recomendação:

  • Aplicativos não confiáveis ​​devem falar com um serviço de sistema que fale com o fornecedor HIDL HAL. Por exemplo, os aplicativos podem conversar com binderservicedomain , então mediaserver (que é um binderservicedomain ) por sua vez fala com o hal_graphics_allocator .

    OU

  • Os aplicativos que precisam de acesso direto às HALs do vendor devem ter seu próprio domínio de política de segurança definido pelo fornecedor.

Testes de atributo de arquivo

O Android 9 inclui testes de tempo de compilação que garantem que todos os arquivos em locais específicos tenham os atributos apropriados (como, todos os arquivos em sysfs têm o atributo sysfs_type necessário).

Política pública de plataforma

A política pública de plataforma é o núcleo da conformidade com o modelo de arquitetura do Android 8.0 sem simplesmente manter a união das políticas de plataforma da v1 e v2. Os fornecedores são expostos a um subconjunto de política de plataforma que contém tipos e atributos utilizáveis ​​e regras sobre esses tipos e atributos que se tornam parte da política de fornecedor (ou seja, vendor_sepolicy.cil ).

Tipos e regras são traduzidos automaticamente na política gerada pelo fornecedor em attribute_v N de forma que todos os tipos fornecidos pela plataforma sejam atributos com versão (no entanto, os atributos não são com versão). A plataforma é responsável por mapear os tipos concretos que fornece nos atributos apropriados para garantir que a política do fornecedor continue funcionando e que as regras fornecidas para uma determinada versão sejam incluídas. A combinação de política pública de plataforma e política de fornecedor atende ao objetivo do modelo de arquitetura do Android 8.0 de permitir compilações independentes de plataforma e fornecedor.

Mapeamento para cadeias de atributos

Ao usar atributos para mapear para versões de política, um tipo mapeia para um atributo ou vários atributos, garantindo que os objetos rotulados com o tipo sejam acessíveis por meio de atributos correspondentes aos seus tipos anteriores.

Manter uma meta de ocultar informações de versão do escritor de política significa gerar automaticamente os atributos com versão e atribuí-los aos tipos apropriados. No caso comum de tipos estáticos, isso é direto: type_foo mapeia para type_foo_v1 .

Para uma alteração de rótulo de objeto como sysfssysfs_A ou mediaserveraudioserver , criar esse mapeamento não é trivial (e é descrito nos exemplos acima). Os mantenedores da política da plataforma devem determinar como criar o mapeamento em pontos de transição para objetos, o que requer entender o relacionamento entre objetos e seus rótulos atribuídos e determinar quando isso ocorre. Para compatibilidade com versões anteriores, essa complexidade precisa ser gerenciada no lado da plataforma, que é a única partição que pode aumentar.

Atualizações de versão

Para simplificar, a plataforma Android libera uma versão de sepolicy quando uma nova ramificação de lançamento é cortada. Conforme descrito acima, o número da versão está contido em PLATFORM_SEPOLICY_VERSION e tem o formato MM.nn , em que MM corresponde ao valor do SDK e nn é um valor privado mantido em /platform/system/sepolicy. Por exemplo, 19.0 para Kitkat, 21.0 para Lollipop, 22.0 para Lollipop-MR1 23.0 para Marshmallow, 24.0 para Nougat, 25.0 para Nougat-MR1, 26.0 para Oreo, 27.0 para Oreo-MR1 e 28.0 para Android 9. Uprevs não são sempre números inteiros. Por exemplo, se um aumento de MR para uma versão exigir uma alteração incompatível em system/sepolicy/public , mas não um aumento de API, essa versão de sepolicy poderá ser: vN.1 . A versão presente em uma ramificação de desenvolvimento é uma 10000.0 nunca usada em dispositivos de envio.

O Android pode descontinuar a versão mais antiga ao atualizar. Para saber quando suspender o uso de uma versão, o Android pode coletar o número de dispositivos com políticas do fornecedor que executam essa versão do Android e ainda recebem as principais atualizações da plataforma. Se o número for menor que um determinado limite, essa versão será preterida.

Impacto no desempenho de vários atributos

Conforme descrito em https://github.com/SELinuxProject/cil/issues/9 , um grande número de atributos atribuídos a um tipo resulta em problemas de desempenho no caso de uma falha de cache de política.

Como isso foi confirmado como um problema no Android, foram feitas alterações no Android 8.0 para remover atributos adicionados à política pelo compilador de políticas, bem como para remover atributos não utilizados. Essas alterações resolveram regressões de desempenho.

Política pública do System_ext e do produto

A partir do Android 11, as partições system_ext e product podem exportar seus tipos públicos designados para a partição do fornecedor. Como a política pública de plataforma, o fornecedor usa tipos e regras automaticamente traduzidos nos atributos versionados, por exemplo, de type em type_ N , onde N é a versão da plataforma na qual a partição do fornecedor é construída.

Quando as partições system_ext e product são baseadas na mesma versão de plataforma N , o sistema de compilação gera arquivos de mapeamento base para system_ext/etc/selinux/mapping/ N .cil e product/etc/selinux/mapping/ N .cil , que contêm identidade mapeamentos de type para type_ N . O fornecedor pode acessar type com o atributo versionado type_ N .

Caso apenas as partições system_ext e product sejam atualizadas, digamos N para N+1 (ou posterior), enquanto o fornecedor permanece em N , o fornecedor pode perder o acesso aos tipos de partições system_ext e product. Para evitar quebras, as partições system_ext e product devem fornecer arquivos de mapeamento de tipos concretos em atributos type_ N . Cada parceiro é responsável por manter os arquivos de mapeamento, se eles forem oferecer suporte a N fornecedores com N+1 (ou posterior) system_ext e partições de produto.

Para isso, espera-se que os parceiros:

  1. Copie os arquivos de mapeamento de base gerados de N system_ext e partições do produto para sua árvore de origem.
  2. Altere os arquivos de mapeamento conforme necessário.
  3. Instale os arquivos de mapeamento em partições do system_ext e do produto N+1 (ou posterior).

Por exemplo, suponha que N system_ext tenha um tipo público chamado foo_type . Então system_ext/etc/selinux/mapping/ N .cil na partição N system_ext ficará assim:

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

Se bar_type for adicionado a N+1 system_ext, e se bar_type deve ser mapeado para foo_type para N fornecedor, N .cil pode ser atualizado de

(typeattributeset foo_type_N (foo_type))

para

(typeattributeset foo_type_N (foo_type bar_type))

e então instalado na partição de N+1 system_ext. N fornecedor pode continuar acessando foo_type e bar_type de N+1 bar_type .

Rotulagem de contextos SELinux

Para suportar a distinção entre sepolicy de plataforma e fornecedor, o sistema cria arquivos de contexto SELinux de forma diferente para mantê-los separados.

Contextos de arquivo

O Android 8.0 introduziu as seguintes alterações para file_contexts :

  • Para evitar sobrecarga de compilação adicional no dispositivo durante a inicialização, file_contexts deixa de existir no formato binário. Em vez disso, eles são arquivos de texto de expressão regular legíveis, como {property, service}_contexts (como eram pré-7.0).
  • Os file_contexts são divididos entre dois arquivos:
    • plat_file_contexts
      • plataforma Android file_context que não possui rótulos específicos do dispositivo, exceto para rotular partes da partição /vendor que devem ser rotuladas com precisão para garantir o funcionamento adequado dos arquivos de sepolicy.
      • Deve residir na partição do system em /system/etc/selinux/plat_file_contexts no dispositivo e ser carregado por init no início junto com o file_context do fornecedor.
    • vendor_file_contexts
      • file_context específico do dispositivo construído combinando file_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
      • Deve ser instalado em /vendor/etc/selinux/vendor_file_contexts na partição do vendor e ser carregado pelo init no início junto com a plataforma file_context .

Contextos de propriedade

No Android 8.0, o property_contexts é dividido entre dois arquivos:

  • plat_property_contexts
    • property_context da plataforma Android que não tem rótulos específicos do dispositivo.
    • Deve residir na partição do system em /system/etc/selinux/plat_property_contexts e ser carregado por init no início junto com o fornecedor property_contexts .
  • vendor_property_contexts
    • property_contexts property_context nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição do vendor em /vendor/etc/selinux/vendor_property_contexts e ser carregado pelo init no início junto com o property_context da plataforma

Contextos de serviço

No Android 8.0, o service_contexts é dividido entre os seguintes arquivos:

  • plat_service_contexts
    • service_context específico da plataforma Android para o servicemanager . O service_context não tem rótulos específicos do dispositivo.
    • Deve residir na partição do system em /system/etc/selinux/plat_service_contexts e ser carregado pelo servicemanager no início junto com o fornecedor service_contexts .
  • vendor_service_contexts
    • service_context específico do dispositivo construído combinando service_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição do vendor em /vendor/etc/selinux/vendor_service_contexts e ser carregado pelo servicemanager no início junto com a plataforma service_contexts .
    • Embora o servicemanager procure por esse arquivo no momento da inicialização, para um dispositivo TREBLE totalmente compatível, o vendor_service_contexts NÃO DEVE existir. Isso ocorre porque toda interação entre o vendor e os processos system DEVE passar por hwservicemanager / hwbinder .
  • plat_hwservice_contexts
    • Plataforma Android hwservice_context para hwservicemanager que não possui rótulos específicos do dispositivo.
    • Deve residir na partição do system em /system/etc/selinux/plat_hwservice_contexts e ser carregado pelo hwservicemanager no início junto com o vendor_hwservice_contexts .
  • vendor_hwservice_contexts
    • O hwservice_context específico do dispositivo construído combinando hwservice_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição do vendor em /vendor/etc/selinux/vendor_hwservice_contexts e ser carregado pelo hwservicemanager no início junto com o plat_service_contexts .
  • vndservice_contexts
    • service_context específico do dispositivo para o vndservicemanager construído combinando vndservice_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS no Boardconfig.mk do dispositivo.
    • Este arquivo deve residir na partição do vendor em /vendor/etc/selinux/vndservice_contexts e ser carregado pelo vndservicemanager no início.

Contextos do Seapp

No Android 8.0, o seapp_contexts é dividido entre dois arquivos:

  • plat_seapp_contexts
    • Plataforma Android seapp_context que não possui alterações específicas do dispositivo.
    • Deve residir na partição do system em /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • Extensão específica do dispositivo para a plataforma seapp_context construída combinando seapp_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição do vendor em /vendor/etc/selinux/vendor_seapp_contexts .

Permissões MAC

No Android 8.0, o mac_permissions.xml é dividido entre dois arquivos:

  • Plataforma mac_permissions.xml
    • Plataforma Android mac_permissions.xml que não tem alterações específicas do dispositivo.
    • Deve residir na partição do system em /system/etc/selinux/.
  • mac_permissions.xml sem plataforma
    • Extensão específica do dispositivo para a plataforma mac_permissions.xml construída a partir de mac_permissions.xml encontrada nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição do vendor em /vendor/etc/selinux/.