Compatibilidade de políticas

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

O design da política SELinux baseada em Treble considera uma distinção binária entre a política da plataforma e do 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 têm garantia de disponibilidade para uma versão de plataforma. Esta política será exposta aos redatores 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 da plataforma exportada será escrita como atributos .
  • Para facilitar a redação de políticas, os tipos exportados serão transformados em atributos versionados como parte do processo de criação de políticas. 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 versionados correspondentes para cada versão da plataforma . Isso garante que quando os objetos são rotulados com um tipo, ele não quebra 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 informações de associação de atributos para cada tipo exportado em políticas públicas.

Propriedade e rotulagem de objetos

Ao personalizar a política no Android 8.0 e versões posteriores, a propriedade deve ser claramente definida para cada objeto para manter a política da plataforma e 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 falhar porque o nó do dispositivo errado foi criado.

As propriedades do sistema também têm potencial para nomear colisões que podem resultar em comportamento indefinido no sistema (bem como para rotulagem do SELinux). Colisões entre rótulos de plataforma e de fornecedor podem ocorrer para qualquer objeto que possua 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 tipos/atributos 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

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 de rotulagem de processo

Evitar colisões de rotulagem é melhor resolvido usando namespaces de propriedades. Para identificar facilmente as propriedades da plataforma e evitar conflitos de nome ao renomear ou adicionar propriedades da 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.
legível e 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 de fornecedor em arquivos init rc devem ter 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

Evitar colisões de arquivos é um desafio porque as políticas de plataforma e de fornecedor geralmente fornecem rótulos para todos os sistemas de arquivos. Ao contrário da nomenclatura 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 componentes /system por meio de file_contexts , service_contexts , etc. Se rótulos para componentes /system forem adicionados na política /vendor , uma atualização OTA somente da estrutura poderá não ser possível.

Fornecedor (/fornecedor)

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

/vendor Etiqueta fornecida pela plataforma Processos de plataforma dependendo da etiqueta
/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 (aplicadas através de neverallows ) ao rotular arquivos adicionais na partição vendor :

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

Procfs (/proc)

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

Recomendação: apenas rótulos de política de plataforma /proc . Se os processos 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 deverá rotulá-los explicitamente e, em vez disso, deverá usar o tipo proc genérico para adicionar regras para domínios do fornecedor. Isso permite que as atualizações da plataforma acomodem interfaces futuras do kernel expostas por meio procfs e as rotulem explicitamente conforme necessário.

Debugfs (/sys/kernel/debug)

Debugfs podem ser rotulados em file_contexts e genfscon . No Android 7.0 ao Android 10, a plataforma e o fornecedor rotulam debugfs .

No Android 11, debugfs não podem ser acessados ​​ou montados 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 sejam específicos do dispositivo. Caso contrário, apenas o fornecedor poderá rotular os arquivos.

tmpfs (/dev)

Arquivos em /dev podem ser rotulados em file_contexts . No Android 7.0, os arquivos de rótulos da plataforma e do fornecedor estão aqui.

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

Rootfs (/)

Arquivos em / podem ser rotulados em file_contexts . No Android 7.0, os arquivos de rótulos da plataforma e do fornecedor estão 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: Proibir rotulagem de fornecedor fora /data/vendor . Somente a plataforma pode rotular outras partes de /data .

Atributos de compatibilidade

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

A política é escrita principalmente em termos dos 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 for alterado em apenas uma dessas políticas, a outra poderá conter a política que ganhou ou perdeu acesso anteriormente confiável. 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;

Poderia 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 o 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 possui 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 tipos concretos nunca são usados. Na prática, isto é necessário apenas para as partes da política que se sobrepõem entre a plataforma e o fornecedor, que são definidas e fornecidas como política pública de plataforma que é construída como parte da política do fornecedor.

Definir políticas públicas como atributos versionados satisfaz dois objetivos de compatibilidade de políticas:

  • Certifique-se de que o código do fornecedor continue funcionando após a atualização da plataforma . Obtido adicionando 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 . Alcançado delineando claramente os conjuntos de políticas em atributos que podem ser removidos assim que a versão à qual 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.

Gravabilidade da política

Para cumprir 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 da plataforma e seus atributos. O tipo foo é mapeado para o atributo foo_v N , onde N é a versão de destino. vN corresponde à variável de compilação PLATFORM_SEPOLICY_VERSION e tem o formato MM.NN , onde MM corresponde ao número do SDK da plataforma e NN é uma versão específica da sepolicy da plataforma.

Os atributos em políticas públicas 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 estável a interface entre as duas partições. Os redatores de políticas de plataforma e de fornecedor podem continuar a redigir políticas como elas são redigidas 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 dispositivo do fornecedor (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 a que data está a política do fornecedor, incluir atributos aos seus tipos e definir a política correspondente aos atributos versionados.

Diferenças de políticas

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 nas 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 de plataforma

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

Mesmos tipos

Este cenário ocorre quando um objeto não altera os rótulos nas versões da política. Isso é o mesmo para os tipos de origem e destino e pode ser visto com /dev/binder , que é 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 do fornecedor v1 (CIL):

(typeattribute binder_device_v1)
(allow binder_device_v1 …)

Na política do fornecedor v2 (CIL):

(typeattribute binder_device_v2)
(allow binder_device_v2 …)
Novos tipos

Este cenário ocorre quando a plataforma adicionou 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 anteriormente não existia (como um novo processo de serviço), o código do fornecedor não interagiu diretamente com ele anteriormente, portanto, não existe nenhuma 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 direcionado a essa versão.
  • Endurecimento da política . Quando o tipo representa o fortalecimento da política, o novo atributo type deve vincular-se 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 do fornecedor v1 (CIL):

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

Na política do fornecedor v2 (CIL):

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

Este 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 a flexibilização da política, um tipo é removido e o objeto rotulado com esse tipo recebe um rótulo diferente e já existente. Isto representa uma fusão de mapeamentos de atributos: o código do fornecedor ainda deve ser capaz de acessar o objeto subjacente pelo atributo que costumava possuir, mas o restante do sistema agora deve ser capaz de acessá-lo com seu novo atributo.

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

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

Exemplo de versão 1: tipos recolhidos (removendo 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 do fornecedor v1 (CIL):

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

Na política do 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 do fornecedor v1 (CIL):

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

Na política do fornecedor v2 (CIL):

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

Este 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 de adição, localização e lista, os daemons do fornecedor que desejavam se registrar no servicemanager precisavam de permissões que não estavam disponíveis. No Android 8.0, somente a política da plataforma pode adicionar novas classes e permissões.

Para permitir que todos os domínios que poderiam 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 acesso a todos os tipos de interface (política pública), para garantir que a imagem do fornecedor obtenha acesso. Se isso resultar em uma política de segurança inaceitável (como pode ter acontecido com as alterações do servicemanager), uma atualização do fornecedor poderá ser potencialmente forçada.

Classe/permissões removidas

Este 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 as utilize mais. Isso é feito adicionando as definições ao arquivo de mapeamento correspondente.

Personalização do fornecedor para tipos novos/renomeados

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; entretanto, a plataforma fornecerá os atributos e tipos públicos que utiliza 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 customizáveis ​​(como init ).

Mudanças de atributos 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 podem.

Atributos do violador

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 vendor e coredomains . Os processos da plataforma e do fornecedor não devem usar arquivos em disco para comunicação (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 de binários de fornecedores possui 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 HALs HIDL.

      OU

    • coredomains que precisam de acesso aos binários do fornecedor devem ser movidos para a partição do fornecedor e, portanto, 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 a partir de tais aplicativos (veja serviços seguros abaixo). As duas principais razões para isso são:

  1. Os servidores HwBinder não realizam autenticação de cliente porque o HIDL atualmente não expõe as informações do 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 trata 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 system/core e têm acesso às camadas inferiores da pilha (até o hardware), aumentando assim as oportunidades para 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, cujo acesso é permitido aos aplicativos.
  • hal_omx_hwservice . Esta é uma versão HwBinder do serviço mediacodec Binder, cujo acesso é permitido aos aplicativos.
  • hal_codec2_hwservice . Esta é uma versão mais recente de hal_omx_hwservice .

Atributos utilizáveis

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

Recomendação:

  • Em vez disso, os aplicativos não confiáveis ​​devem se comunicar com um serviço do sistema que se comunica com o fornecedor HIDL HAL. Por exemplo, os aplicativos podem se comunicar com binderservicedomain e, em seguida mediaserver (que é um binderservicedomain ), por sua vez, se comunicar com hal_graphics_allocator .

    OU

  • Os aplicativos que precisam de acesso direto aos HALs vendor devem ter seu próprio domínio sepolicy definido pelo fornecedor.

Testes de atributos 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 (por exemplo, todos os arquivos em sysfs têm o atributo sysfs_type obrigatório).

Política pública-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íticas de plataforma que contém tipos e atributos utilizáveis ​​e regras sobre esses tipos e atributos que então se tornam parte da política do fornecedor (ou seja, vendor_sepolicy.cil ).

Tipos e regras são automaticamente traduzidos na política gerada pelo fornecedor em attribute_v N de modo que todos os tipos fornecidos pela plataforma sejam atributos com versão (no entanto, os atributos não têm 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 a funcionar e que as regras fornecidas para uma versão específica sejam incluídas. A combinação de políticas públicas de plataforma e políticas de fornecedores satisfaz o objetivo do modelo de arquitetura do Android 8.0 de permitir construções independentes de plataformas e fornecedores.

Mapeamento para cadeias de atributos

Ao usar atributos para mapear versões de política, um tipo é mapeado 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 a meta de ocultar informações de versão do redator da política significa gerar automaticamente os atributos com versão e atribuí-los aos tipos apropriados. No caso comum de tipos estáticos, isso é simples: 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 de políticas de plataforma devem determinar como criar o mapeamento em pontos de transição para objetos, o que requer a compreensão do relacionamento entre os objetos e seus rótulos atribuídos e a determinação de 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 ser atualizada.

Atualizações de versão

Para simplificar, a plataforma Android lança uma versão sepolicy quando um novo branch de lançamento é cortado. Conforme descrito acima, o número da versão está contido em PLATFORM_SEPOLICY_VERSION e tem o formato MM.nn , onde 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 em uma versão exigir uma alteração incompatível em system/sepolicy/public , mas não um aumento de API, então essa versão de sepolicy poderá ser: vN.1 . A versão presente em uma ramificação de desenvolvimento é uma 10000.0 que nunca deve ser usada em dispositivos de remessa.

O Android pode descontinuar a versão mais antiga durante a atualização. Para obter informações sobre quando descontinuar uma versão, o Android pode coletar o número de dispositivos com políticas de fornecedor que executam essa versão do Android e ainda recebem atualizações importantes da plataforma. Se o número for menor que um determinado limite, essa versão será obsoleta.

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 falha no cache da política.

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

System_ext política pública e pública 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. Assim como a política pública de plataforma, o fornecedor usa tipos e regras automaticamente traduzidos em atributos versionados, por exemplo, de type para 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 permanecer em N , o fornecedor poderá perder 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, caso pretendam oferecer suporte a N fornecedores com N+1 (ou posterior) system_ext e partições de produto.

Para fazer isso, espera-se que os parceiros:

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

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 será semelhante a:

(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 precisar ser mapeado para foo_type para N fornecedor, N .cil poderá 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 N+1 system_ext. O fornecedor N pode continuar acessando N+1 system_ext's foo_type e bar_type .

Rotulagem de contextos SELinux

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

Contextos de arquivo

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

  • Para evitar sobrecarga adicional de compilação no dispositivo durante a inicialização, file_contexts deixa de existir na forma binária. Em vez disso, eles são arquivos de texto de expressão regular legíveis, como {property, service}_contexts (como eram antes da versão 7.0).
  • Os file_contexts são divididos entre dois arquivos:
    • plat_file_contexts
      • file_context da plataforma Android 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 sepolicy.
      • Deve residir na partição system em /system/etc/selinux/plat_file_contexts no dispositivo e ser carregado pelo init no início junto com o fornecedor file_context .
    • vendor_file_contexts
      • file_context específico do dispositivo criado pela combinação de 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 vendor e carregado pelo init no início junto com a plataforma file_context .

Contextos de propriedade

No Android 8.0, property_contexts é dividido entre dois arquivos:

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

Contextos de serviço

No Android 8.0, 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 possui rótulos específicos do dispositivo.
    • Deve residir na partição 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 criado pela combinação service_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição vendor em /vendor/etc/selinux/vendor_service_contexts e ser carregado pelo servicemanager no início junto com a plataforma service_contexts .
    • Embora servicemanager procure 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 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 de dispositivo.
    • Deve residir na partição system em /system/etc/selinux/plat_hwservice_contexts e ser carregado pelo hwservicemanager no início junto com vendor_hwservice_contexts .
  • vendor_hwservice_contexts
    • hwservice_context específico do dispositivo criado combinando hwservice_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Deve residir na partição 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 criado combinando vndservice_contexts encontrados nos diretórios apontados por BOARD_SEPOLICY_DIRS no Boardconfig.mk do dispositivo.
    • Este arquivo deve residir na partição vendor em /vendor/etc/selinux/vndservice_contexts e ser carregado pelo vndservicemanager no início.

Contextos Seapp

No Android 8.0, 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 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 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 possui alterações específicas do dispositivo.
    • Deve residir na partição 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 vendor em /vendor/etc/selinux/.