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 design da política do SELinux baseado em Treble considera uma distinção binária entre plataforma e política 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, cuja disponibilidade é garantida para uma versão da plataforma. Esta política será exposta aos redatores de política 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á gravada como atributos .
- Para facilitar a redação da política, os tipos exportados serão transformados em atributos com versão como parte do processo de construçã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 versionados correspondentes para cada versão da plataforma . Isso garante que, quando os objetos são rotulados com um tipo, não interrompa 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 para qualquer rótulo aplicado por último. Como resultado:
- Os processos que precisam acessar o rótulo aplicado sem êxito perderão o acesso ao recurso.
- Os processos que obtêm acesso ao arquivo podem ser interrompidos porque o nó de 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 fornecedor podem ocorrer 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 nome de tipo/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 falhará na compilação. Para evitar conflitos de tipo e nome de atributo, todas as declarações do fornecedor devem ter namespace começando com np_
.
type foo, domain; → type np_foo, domain;
Propriedade do sistema e propriedade de 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 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. |
leitura-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 kernel cmdline) e ro.hardware.*
(uma propriedade óbvia relacionada ao hardware).
Todos os serviços do fornecedor nos arquivos init rc devem ter vendor.
para serviços em arquivos init rc de partições que não sejam 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 plataforma e a política do fornecedor geralmente fornecem rótulos para todos os sistemas de arquivos. Ao contrário da nomenclatura de tipos, o namespace dos 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, essas são recomendações sem imposiçã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 vendor
com as quais a plataforma interage, o que permite escrever regras do SELinux para que os processos da plataforma possam se comunicar e/ou acessar partes da partição vendor
. Exemplos:
/vendor | Rótulo fornecido pela plataforma | Processos de 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 (aplicadas por meio 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çãovendor
. A política da plataforma exige isso para acessar as implementações HAL de passagem. - Todos os novos
exec_types
adicionados na partiçãovendor
por meio do fornecedor SEPolicy devem ter o atributovendor_file_type
. Isso é imposto 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çãovendor
. - Todas as dependências de biblioteca para HALs de mesmo processo identificadas pelo 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, a plataforma e 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 vendor
precisarem de acesso a arquivos em /proc
atualmente rotulados com o rótulo padrão ( proc
), a política do fornecedor não deve rotulá-los explicitamente e, em vez disso, deve usar o tipo proc
genérico para adicionar regras para domínios do fornecedor. Isso permite que as atualizações da plataforma acomodem futuras interfaces 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, tanto a plataforma quanto o rótulo do fornecedor 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)
Os 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, os arquivos de rótulos de plataforma e 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 de plataforma e 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: não permitir a rotulagem do fornecedor fora de /data/vendor
. Somente a plataforma pode rotular outras partes de /data
.
Atributos de compatibilidade
A política do SELinux é uma interação entre os tipos de origem e destino para classes e permissões de objeto 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 for alterado em apenas uma dessas políticas, a outra poderá conter a política que obteve ou perdeu o 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 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 tipos concretos nunca são usados. Na prática, isso é 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íticas públicas de plataforma construídas como parte da política do fornecedor.
Definir política pública como atributos com versão satisfaz dois objetivos 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 depreciar 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 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íticas públicas 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 está no formato MM.NN
, em que MM
corresponde ao número do SDK da plataforma e NN
é uma versão específica da política de segurança da plataforma.
Os atributos na política pública não têm versão, 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. Os redatores de políticas de plataformas e fornecedores podem continuar a redigir políticas como sã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 de plataforma precisará saber o quão antiga é a política do fornecedor, incluir atributos em 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 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 acima mencionados 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 v1
→ v2
, a política de 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
Esse cenário ocorre quando a plataforma adiciona um novo tipo, o que pode acontecer ao adicionar novos recursos ou durante a proteção 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 interagia 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 proteção de política, o novo atributo de tipo deve ser vinculado a uma cadeia de atributos correspondente ao anterior (semelhante ao exemplo anterior, alterando
/sys/A
desysfs
parasysfs_A
). O código do fornecedor depende de uma regra que permite o acesso asysfs
e precisa incluir essa regra como um atributo do novo tipo.
Ao atualizar de v1
→ v2
, a política de 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 já existente. Isso 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 ele foi trocado for novo, a reetiquetagem é a mesma que no novo caso de tipo, exceto que, quando um rótulo existente é usado, a adição do novo tipo de atributo antigo causaria outros objetos também rotulados com esse 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 …)
Versão de exemplo 1: tipos recolhidos (removendo sysfs_A)
Ao atualizar de v1
→ v2
, a política de 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 …)
Versão de exemplo 2: removendo completamente (tipo foo)
Ao atualizar de v1
→ v2
, a política de 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 em versões anteriores. Por exemplo, quando o Android adicionou o gerenciador de objetos servicemanager
que criou as permissões adicionar, localizar e listar, daemons de fornecedores 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 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 o acesso para 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 acontecer com as alterações do gerenciador de serviços), uma atualização do fornecedor pode ser 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/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 interagindo 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 atributos para o Android 9
Os dispositivos atualizados para o Android 9 podem usar os seguintes atributos, 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 entrevendor
ecoredomains
. 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
.
- O código do fornecedor deve usar
-
system_executes_vendor_violators
. Atributo para todos os domínios do sistema (exceto domíniosinit
eshell domains
) que violam o requisito de não executar binários do fornecedor. A execução de binários do fornecedor tem API instável. A plataforma não deve executar binários do fornecedor 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, portanto, deixar de sercoredomain
.
- Essas dependências de plataforma em binários de fornecedores devem estar por trás de HIDL HALs.
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 (consulte os serviços seguros abaixo). As duas principais razões para isso são:
- Os servidores HwBinder não executam a autenticação do cliente porque o HIDL atualmente não expõe as informações do UID do chamador. Mesmo que o HIDL expusesse tais 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.
- 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 componentes
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 é projetado especificamente para uso por qualquer domínio. -
hal_graphics_allocator_hwservice
. Essas operações também são oferecidas pelo serviçosurfaceflinger
Binder, que os aplicativos têm permissão para acessar. -
hal_omx_hwservice
. Esta é uma versão HwBinder do serviçomediacodec
Binder, que os aplicativos têm permissão para acessar. -
hal_codec2_hwservice
. Esta é uma versão mais recente dohal_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
. Os dispositivos iniciados com o Android 9 NÃO DEVEM usar nenhum atributo untrusted
.
Recomendação:
- 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
, entãomediaserver
(que é umbinderservicedomain
), por sua vez, se comunica com ohal_graphics_allocator
.OU
- Os aplicativos que precisam de acesso direto aos HALs
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
obrigatório).
Plataforma-política pública
A política pública de plataforma é o núcleo da conformidade com o modelo de arquitetura Android 8.0 sem simplesmente manter a união das políticas de plataforma de v1 e v2. Os fornecedores são expostos a um subconjunto da política da plataforma que contém tipos e atributos utilizáveis e regras sobre esses tipos e atributos que se tornam parte da política do fornecedor (ou seja, vendor_sepolicy.cil
).
Tipos e regras são convertidos 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 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 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 satisfaz o 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 é mapeado para um atributo ou vários atributos, garantindo que os objetos rotulados com o tipo sejam acessíveis por meio de atributos correspondentes a seus tipos anteriores.
Manter uma meta para ocultar as 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 é direto: type_foo
mapeia para type_foo_v1
.
Para uma alteração de rótulo de objeto, como sysfs
→ sysfs_A
ou mediaserver
→ audioserver
, criar esse mapeamento não é trivial (e é descrito nos exemplos acima). Os mantenedores da política da plataforma devem determinar como criar o mapeamento nos pontos de transição para os objetos, o que requer entender o relacionamento entre os 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 ser atualizada.
Atualizações de versão
Para simplificar, a plataforma Android lança uma versão de política segura 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 está no 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 em uma versão exigir uma alteração incompatível no system/sepolicy/public
mas não um aumento de API, essa versão de política de segurança poderá ser: vN.1
. A versão presente em uma ramificação de desenvolvimento é um 10000.0
que nunca deve ser usado em dispositivos de remessa.
O Android pode depreciar a versão mais antiga ao atualizar. Para informações sobre quando substituir uma versão, o Android pode coletar o número de dispositivos com políticas de fornecedor executando essa versão do Android e ainda recebendo as principais atualizações 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 de política.
Isso foi confirmado como um problema no Android, então alterações foram feitas 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 as regressões de desempenho.
System_ext public e política pública de 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 da plataforma, o fornecedor usa tipos e regras convertidos automaticamente nos atributos com versão, por exemplo, de type
para type_ N
, em que 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 for oferecer suporte a N
fornecedor com N+1
(ou posterior) system_ext e partições de produto.
Para isso, espera-se que os parceiros:
- Copie os arquivos de mapeamento base gerados de
N
system_ext e partições de produto para sua árvore de origem. - Corrija os arquivos de mapeamento conforme necessário.
- Instale os arquivos de mapeamento para
N+1
(ou posterior) system_ext e partições do 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 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. O fornecedor N
pode continuar acessando foo_type
e bar_type
de N+1
system_ext.
Rotulagem de contextos do SELinux
Para oferecer suporte à distinção entre plataforma e política de segurança do fornecedor, o sistema cria arquivos de contexto do SELinux de maneira 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 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 porinit
no início junto com o fornecedorfile_context
.
-
-
vendor_file_contexts
-
file_context
específico do dispositivo criado pela combinaçãofile_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve ser instalado em
/vendor/etc/selinux/vendor_file_contexts
na partiçãovendor
e carregado peloinit
no início junto com ofile_context
da plataforma.
-
-
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
system
em/system/etc/selinux/plat_property_contexts
e ser carregado porinit
no início junto com oproperty_contexts
do fornecedor.
-
-
vendor_property_contexts
-
property_context
específico do dispositivo criado pela combinaçãoproperty_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve residir na partição
vendor
em/vendor/etc/selinux/vendor_property_contexts
e ser carregado peloinit
no início junto com oproperty_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 oservicemanager
. Oservice_context
não tem rótulos específicos do dispositivo. - Deve residir na partição
system
em/system/etc/selinux/plat_service_contexts
e ser carregado peloservicemanager
no início junto com o fornecedorservice_contexts
.
-
-
vendor_service_contexts
-
service_context
específico do dispositivo criado pela combinaçãoservice_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve residir na partição
vendor
em/vendor/etc/selinux/vendor_service_contexts
e ser carregado peloservicemanager
no início junto com a plataformaservice_contexts
. - Embora
servicemanager
procure esse arquivo no momento da inicialização, para um dispositivoTREBLE
totalmente compatível, ovendor_service_contexts
NÃO DEVE existir. Isso ocorre porque toda a interação entrevendor
e os processossystem
DEVE passar porhwservicemanager
/hwbinder
.
-
-
plat_hwservice_contexts
- Plataforma Android
hwservice_context
parahwservicemanager
que não possui rótulos específicos do dispositivo. - Deve residir na partição
system
em/system/etc/selinux/plat_hwservice_contexts
e ser carregado pelohwservicemanager
no início junto com ovendor_hwservice_contexts
.
- Plataforma Android
-
vendor_hwservice_contexts
-
hwservice_context
específico do dispositivo criado pela combinaçãohwservice_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve residir na partição
vendor
em/vendor/etc/selinux/vendor_hwservice_contexts
e ser carregado pelohwservicemanager
no início junto com oplat_service_contexts
.
-
-
vndservice_contexts
-
service_context
específico do dispositivo para ovndservicemanager
criado pela combinação devndservice_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
noBoardconfig.mk
do dispositivo. - Este arquivo deve residir na partição
vendor
em/vendor/etc/selinux/vndservice_contexts
e ser carregado pelovndservicemanager
no início.
-
Contextos 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
system
em/system/etc/selinux/plat_seapp_contexts.
- Plataforma Android
-
vendor_seapp_contexts
- Extensão específica do dispositivo para a plataforma
seapp_context
criada pela combinação deseapp_contexts
encontrados nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve residir na partição
vendor
em/vendor/etc/selinux/vendor_seapp_contexts
.
- Extensão específica do dispositivo para a plataforma
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/.
- Plataforma Android
- Não plataforma
mac_permissions.xml
- Extensão específica do dispositivo para a plataforma
mac_permissions.xml
criada a partir domac_permissions.xml
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Deve residir na partição
vendor
em/vendor/etc/selinux/.
- Extensão específica do dispositivo para a plataforma
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 design da política do SELinux baseado em Treble considera uma distinção binária entre plataforma e política 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, cuja disponibilidade é garantida para uma versão da plataforma. Esta política será exposta aos redatores de política 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á gravada como atributos .
- For ease of policy writing, exported types will be transformed into versioned attributes as part of the policy build process. Public types may also be used directly in labeling decisions provided by vendor contexts files.
Android maintains a mapping between exported concrete types in platform policy and the corresponding versioned attributes for each platform version . This ensures that when objects are labeled with a type, it does not break behavior guaranteed by the platform-public policy in a previous version. This mapping is maintained by keeping a mapping file up-to-date for each platform version , which keeps attribute membership information for each type exported in public policy.
Object ownership and labeling
When customizing policy in Android 8.0 and higher, ownership must be clearly defined for each object to keep platform and vendor policy separate. For example, if the vendor labels /dev/foo
and the platform then labels /dev/foo
in a subsequent OTA, there will be undefined behavior. For SELinux, this manifests as a labeling collision. The device node can have only a single label which resolves to whichever label is applied last. As a result:
- Processes that need access to the unsuccessfully applied label will lose access to the resource.
- Processes that gain access to the file may break because the wrong device node was created.
System properties also have potential for naming collisions that could result in undefined behavior on the system (as well as for SELinux labeling). Collisions between platform and vendor labels can occur for any object that has an SELinux label, including properties, services, processes, files, and sockets. To avoid these issues, clearly define ownership of these objects.
In addition to label collisions, SELinux type/attribute names may also collide. A type/attribute name collision will always result in a policy compiler error.
Type/attribute namespacing
SELinux does not allow multiple declarations of the same type/attribute. Policy with duplicate declarations will fail to compilation. To avoid type and attribute name collisions, all vendor declarations should be namespaced starting with np_
.
type foo, domain; → type np_foo, domain;
System property and process labeling ownership
Avoiding labeling collisions is best solved using property namespaces. To easily identify platform properties and avoid name conflicts when renaming or adding exported-platform properties, ensure all vendor properties have their own prefixes:
Property type | Acceptable prefixes |
---|---|
control properties | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor. |
read-writable | vendor. |
read-only | ro.vendor. ro.boot. ro.hardware. |
persistent | persist.vendor. |
Vendors can continue to use ro.boot.*
(which comes from the kernel cmdline) and ro.hardware.*
(an obvious hardware-related property).
All the vendor services in init rc files should have vendor.
for services in init rc files of non-system partitions. Similar rules are applied to the SELinux labels for the vendor properties ( vendor_
for the vendor properties).
File ownership
Preventing collisions for files is challenging because platform and vendor policy both commonly provide labels for all filesystems. Unlike type naming, namespacing of files is not practical since many of them are created by the kernel. To prevent these collisions, follow the naming guidance for filesystems in this section. For Android 8.0, these are recommendations without technical enforcement. In the future, these recommendations will be enforced by the Vendor Test Suite (VTS).
System (/system)
Only the system image must provide labels for /system
components through file_contexts
, service_contexts
, etc. If labels for /system
components are added in /vendor
policy, a framework-only OTA update may not be possible.
Vendor (/vendor)
The AOSP SELinux policy already labels parts of vendor
partition the platform interacts with, which enables writing SELinux rules for platform processes to be able to talk and/or access parts of vendor
partition. Examples:
/vendor path | Platform-provided label | Platform processes depending on the label |
---|---|---|
/vendor(/. * )? | vendor_file | All HAL clients in 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. |
As a result, specific rules must be followed (enforced through neverallows
) when labelling additional files in vendor
partition:
-
vendor_file
must be the default label for all files invendor
partition. The platform policy requires this to access passthrough HAL implementations. - All new
exec_types
added invendor
partition through vendor SEPolicy must havevendor_file_type
attribute. This is enforced through neverallows. - To avoid conflicts with future platform/framework updates, avoid labelling files other than
exec_types
invendor
partition. - All library dependencies for AOSP-identified same process HALs must be labelled as
same_process_hal_file.
Procfs (/proc)
Files in /proc
may be labeled using only the genfscon
label. In Android 7.0, both the platform and vendor policy used genfscon
to label files in procfs
.
Recommendation: Only platform policy labels /proc
. If vendor
processes need access to files in /proc
that are currently labeled with the default label ( proc
), vendor policy should not explicitly label them and should instead use the generic proc
type to add rules for vendor domains. This allows the platform updates to accommodate future kernel interfaces exposed through procfs
and label them explicitly as needed.
Debugfs (/sys/kernel/debug)
Debugfs
can be labeled in both file_contexts
and genfscon
. In Android 7.0 to Android 10, both platform and vendor label debugfs
.
In Android 11, debugfs
can't be accessed or mounted on production devices. Device manufacturers should remove debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Tracefs
can be labeled in both file_contexts
and genfscon
. In Android 7.0, only the platform labels tracefs
.
Recommendation: Only platform may label tracefs
.
Sysfs (/sys)
Files in /sys
may be labeled using both file_contexts
and genfscon
. In Android 7.0, both platform and vendor use file_contexts
and genfscon
to label files in sysfs
.
Recommendation: The platform may label sysfs
nodes that are not device-specific. Otherwise, only vendor may label files.
tmpfs (/dev)
Files in /dev
may be labeled in file_contexts
. In Android 7.0, both platform and vendor label files here.
Recommendation: Vendor may label only files in /dev/vendor
(eg, /dev/vendor/foo
, /dev/vendor/socket/bar
).
Rootfs (/)
Files in /
may be labeled in file_contexts
. In Android 7.0, both platform and vendor label files here.
Recommendation: Only system may label files in /
.
Data (/data)
Data is labeled through a combination of file_contexts
and seapp_contexts
.
Recommendation: Disallow vendor labeling outside /data/vendor
. Only platform may label other parts of /data
.
Compatibility attributes
SELinux policy is an interaction between source and target types for specific object classes and permissions. Every object (processes, files, etc.) affected by SELinux policy may have only one type, but that type may have multiple attributes.
Policy is written mostly in terms of existing types:
allow source_type target_type:target_class permission(s);
This works because the policy was written with knowledge of all types. However, if the vendor policy and platform policy use specific types, and the label of a specific object changes in only one of those policies, the other may contain policy that gained or lost access previously relied upon. 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;
Could be changed to:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Although the vendor policy would remain the same, the v_domain
would lose access due to the lack of policy for the new sysfs_A
type.
By defining a policy in terms of attributes, we can give the underlying object a type that has an attribute corresponding to policy for both the platform and vendor code. This can be done for all types to effectively create an attribute-policy wherein concrete types are never used. In practice, this is required only for the portions of policy that overlap between platform and vendor, which are defined and provided as platform public policy that gets built as part of the vendor policy.
Defining public policy as versioned attributes satisfies two policy compatibility goals:
- Ensure vendor code continues to work after platform update . Achieved by adding attributes to concrete types for objects corresponding to those on which vendor code relied, preserving access.
- Ability to deprecate policy . Achieved by clearly delineating policy sets into attributes that can be removed as soon as the version to which they correspond no longer is supported. Development can continue in the platform, knowing the old policy is still present in the vendor policy and will be automatically removed when/if it upgrades.
Policy writability
To meet the goal of not requiring knowledge of specific version changes for policy development, Android 8.0 includes a mapping between platform-public policy types and their attributes. Type foo
is mapped to attribute foo_v N
, where N
is the version targeted. vN
corresponds to the PLATFORM_SEPOLICY_VERSION
build variable and is of the form MM.NN
, where MM
corresponds to the platform SDK number and NN
is a platform sepolicy specific version.
Attributes in public policy are not versioned, but rather exist as an API on which platform and vendor policy can build to keep the interface between the two partitions stable. Both platform and vendor policy writers can continue to write policy as it is written today.
Platform-public policy exported as allow source_foo target_bar: class perm ;
is included as part of the vendor policy. During compilation (which includes the corresponding version) it is transformed into the policy that will go to the vendor portion of the device (shown in the transformed Common Intermediate Language (CIL)):
(allow source_foo_vN target_bar_vN (class (perm)))
As vendor policy is never ahead of the platform, it should not be concerned with prior versions. However, platform policy will need to know how far back vendor policy is, include attributes to its types, and set policy corresponding to versioned attributes.
Policy diffs
Automatically creating attributes by adding _v N
to the end of each type does nothing without mapping of attributes to types across version diffs. Android maintains a mapping between versions for attributes and a mapping of types to those attributes. This is done in the aforementioned mapping files with statements, such as (CIL):
(typeattributeset foo_vN (foo))
Platform upgrades
The following section details scenarios for platform upgrades.
Same types
This scenario occurs when an object does not change labels in policy versions. This is the same for source and target types and can be seen with /dev/binder
, which is labeled binder_device
across all releases. It is represented in transformed policy as:
binder_device_v1 … binder_device_vN
When upgrading from v1
→ v2
, the platform policy must contain:
type binder_device; -> (type binder_device) (in CIL)
In the v1 mapping file (CIL):
(typeattributeset binder_device_v1 (binder_device))
In the v2 mapping file (CIL):
(typeattributeset binder_device_v2 (binder_device))
In the v1 vendor policy (CIL):
(typeattribute binder_device_v1) (allow binder_device_v1 …)
In the v2 vendor policy (CIL):
(typeattribute binder_device_v2) (allow binder_device_v2 …)
New types
This scenario occurs when the platform has added a new type, which can happen when adding new features or during policy hardening.
- New feature . When the type is labeling an object that was previously non-existent (such as a new service process), the vendor code did not previously interact with it directly so no corresponding policy exists. The new attribute corresponding to the type does not have an attribute in the previous version, and so would not need an entry in the mapping file targeting that version.
- Policy hardening . When the type represents policy hardening, the new type attribute must link back to a chain of attributes corresponding to the previous one (similar to the previous example changing
/sys/A
fromsysfs
tosysfs_A
). Vendor code relies on a rule enabling access tosysfs
, and needs to include that rule as an attribute of the new type.
When upgrading from v1
→ v2
, the platform policy must contain:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
In the v1 mapping file (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
In the v2 mapping file (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
In the v1 vendor policy (CIL):
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Removed types
This (rare) scenario occurs when a type is removed, which can happen when the underlying object:
- Remains but gets a different label.
- Is removed by the platform.
During policy loosening, a type is removed and the object labeled with that type is given a different, already-existing label. This represents a merging of attribute mappings: The vendor code must still be able to access the underlying object by the attribute it used to possess, but the rest of the system must now be able to access it with its new attribute.
If the attribute to which it has been switched is new, then relabeling is the same as in the new type case, except that when an existing label is used, the addition of the old attribute new type would cause other objects also labeled with this type to be newly accessible. This is essentially what is done by the platform and is deemed to be an acceptable tradeoff to maintain compatibility.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Example Version 1: Collapsing types (removing sysfs_A)
When upgrading from v1
→ v2
, the platform policy must contain:
type sysfs; (type sysfs) (in CIL)
In the v1 mapping file (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))
In the v2 mapping file (CIL):
(typeattributeset sysfs_v2 (sysfs))
In the v1 vendor policy (CIL):
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Example Version 2: Removing completely (foo type)
When upgrading from v1
→ v2
, the platform policy must contain:
# nothing - we got rid of the type
In the v1 mapping file (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
In the v2 mapping file (CIL):
# nothing - get rid of it
In the v1 vendor policy (CIL):
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_v2) (allow sysfs_v2 …)
New class/permissions
This scenario occurs when a platform upgrade introduces new policy components that do not exist in previous versions. For example, when Android added the servicemanager
object manager that created the add, find, and list permissions, vendor daemons wanting to register with the servicemanager
needed permissions that were not available. In Android 8.0, only the platform policy may add new classes and permissions.
To allow all domains that could have been created or extended by vendor policy to use the new class without obstruction, the platform policy needs to include a rule similar to:
allow {domain -coredomain} *:new_class perm;
This may even require policy allowing access for all interface (public policy) types, to be sure vendor image gains access. If this results in unacceptable security policy (as it may have with the servicemanager changes), a vendor upgrade could potentially be forced.
Removed class/permissions
This scenario occurs when an object manager is removed (such as the ZygoteConnection
object manager) and should not cause issues. The object manager class and permissions could remain defined in policy until the vendor version no longer uses it. This is done by adding the definitions to the corresponding mapping file.
Vendor customization for new/relabeled types
New vendor types are at the core of vendor policy development as they are needed to describe new processes, binaries, devices, subsystems, and stored data. As such, it is imperative to allow the creation of vendor-defined types.
As vendor policy is always the oldest on the device, there is no need to automatically convert all vendor types to attributes in policy. The platform does not rely on anything labeled in vendor policy because the platform has no knowledge of it; however, the platform will provide the attributes and public types it uses to interact with objects labeled with these types (such as domain
, sysfs_type
, etc.). For the platform to continue to interact correctly with these objects, the attributes and types must be appropriately applied and specific rules may need to be added to the customizable domains (such as init
).
Attribute changes for Android 9
Devices upgrading to Android 9 can use the following attributes, but devices launching with Android 9 must not.
Violator attributes
Android 9 includes these domain-related attributes:
-
data_between_core_and_vendor_violators
. Attribute for all domains that violate the requirement of not sharing files by path betweenvendor
andcoredomains
. Platform and vendor processes shouldn't use on-disk files to communicate (unstable ABI). Recommendation:- Vendor code should use
/data/vendor
. - System should not use
/data/vendor
.
- Vendor code should use
-
system_executes_vendor_violators
. Attribute for all system domains (exceptinit
andshell domains
) that violate the requirement of not executing vendor binaries. Execution of vendor binaries has unstable API. Platform shouldn't execute vendor binaries directly. Recommendation:- Such platform dependencies on vendor binaries must be behind HIDL HALs.
OR
-
coredomains
that need access to vendor binaries should be moved to the vendor partition and thus, stop beingcoredomain
.
- Such platform dependencies on vendor binaries must be behind HIDL HALs.
Untrusted attributes
Untrusted apps that host arbitrary code shouldn't have access to HwBinder services, except those considered sufficiently safe for access from such apps (see safe services below). The two main reasons for this are:
- HwBinder servers do not perform client authentication because HIDL currently does not expose caller UID information. Even if HIDL did expose such data, many HwBinder services either operate at a level below that of apps (such as, HALs) or must not rely on app identity for authorization. Thus, to be safe, the default assumption is that every HwBinder service treats all its clients as equally authorized to perform operations offered by the service.
- HAL servers (a subset of HwBinder services) contain code with higher incidence rate of security issues than
system/core
components and have access to the lower layers of the stack (all the way down to hardware) thus increasing opportunities for bypassing the Android security model.
Safe services
Safe services include:
-
same_process_hwservice
. These services (by definition) run in the process of the client and thus have the same access as the client domain in which the process runs. -
coredomain_hwservice
. These services do not pose risks associated with reason #2. -
hal_configstore_ISurfaceFlingerConfigs
. This service is specifically designed for use by any domain. -
hal_graphics_allocator_hwservice
. These operations are also offered bysurfaceflinger
Binder service, which apps are permitted to access. -
hal_omx_hwservice
. This is a HwBinder version of themediacodec
Binder service, which apps are permitted to access. -
hal_codec2_hwservice
. This is a newer version ofhal_omx_hwservice
.
Useable attributes
All hwservices
not considered safe have the attribute untrusted_app_visible_hwservice
. The corresponding HAL servers have the attribute untrusted_app_visible_halserver
. Devices launching with Android 9 MUST NOT use either untrusted
attribute.
Recommendation:
- Untrusted apps should instead talk to a system service that talks to the vendor HIDL HAL. For example, apps can talk to
binderservicedomain
, thenmediaserver
(which is abinderservicedomain
) in turn talks to thehal_graphics_allocator
.OR
- Apps that need direct access to
vendor
HALs should have their own vendor-defined sepolicy domain.
File attribute tests
Android 9 includes build time tests that ensure all files in specific locations have the appropriate attributes (such as, all files in sysfs
have the required sysfs_type
attribute).
Platform-public policy
The platform-public policy is the core of conforming to the Android 8.0 architecture model without simply maintaining the union of platform policies from v1 and v2. Vendors are exposed to a subset of platform policy that contains useable types and attributes and rules on those types and attributes which then becomes part of vendor policy (ie vendor_sepolicy.cil
).
Types and rules are automatically translated in the vendor-generated policy into attribute_v N
such that all platform-provided types are versioned attributes (however attributes are not versioned). The platform is responsible for mapping the concrete types it provides into the appropriate attributes to ensure that vendor policy continues to function and that the rules provided for a particular version are included. The combination of platform-public policy and vendor policy satisfies the Android 8.0 architecture model goal of allowing independent platform and vendor builds.
Mapping to attribute chains
When using attributes to map to policy versions, a type maps to an attribute or multiple attributes, ensuring objects labeled with the type are accessible via attributes corresponding to their previous types.
Maintaining a goal to hide version information from the policy writer means automatically generating the versioned attributes and assigning them to the appropriate types. In the common case of static types, this is straightforward: type_foo
maps to type_foo_v1
.
For an object label change such as sysfs
→ sysfs_A
or mediaserver
→ audioserver
, creating this mapping is non-trivial (and is described in the examples above). Platform policy maintainers must determine how to create the mapping at transition points for objects, which requires understanding the relationship between objects and their assigned labels and determining when this occurs. For backwards compatibility, this complexity needs to be managed on the platform side, which is the only partition that may uprev.
Version uprevs
For simplicity, the Android platform releases an sepolicy version when a new release branch is cut. As described above, the version number is contained in PLATFORM_SEPOLICY_VERSION
and is of the form MM.nn
, where MM
corresponds to the SDK value and nn
is a private value maintained in /platform/system/sepolicy.
For example, 19.0
for Kitkat, 21.0
for Lollipop, 22.0
for Lollipop-MR1 23.0
for Marshmallow, 24.0
for Nougat, 25.0
for Nougat-MR1, 26.0
for Oreo, 27.0
for Oreo-MR1, and 28.0
for Android 9. Uprevs aren't always whole numbers. For example, if an MR bump to a versions necessitates an incompatible change in system/sepolicy/public
but not an API bump, then that sepolicy version could be: vN.1
. The version present in a development branch is a never-to-be-used-in-shipping-devices 10000.0
.
Android may deprecate oldest version when upreving. For input on when to deprecate a version, Android may collect the number of devices with vendor policies running that Android version and still receiving major platform updates. If the number is less than a certain threshold, that version is deprecated.
Performance impact of multiple attributes
As described in https://github.com/SELinuxProject/cil/issues/9 , a large number of attributes assigned to a type result in performance issues in the event of a policy cache miss.
This was confirmed to be an issue in Android, so changes were made to Android 8.0 to remove attributes added to the policy by the policy compiler, as well as to remove unused attributes. These changes resolved performance regressions.
System_ext public and product public policy
Starting from Android 11, the system_ext and product partitions are allowed to export their designated public types to the vendor partition. Like platform public policy, the vendor uses types and rules automatically translated into the versioned attributes, eg from type
into type_ N
, where N
is the version of the platform which the vendor partition is built against.
When the system_ext and product partitions are based on the same platform version N
, the build system generates base mapping files to system_ext/etc/selinux/mapping/ N .cil
and product/etc/selinux/mapping/ N .cil
, which contain identity mappings from type
to type_ N
. The vendor can access type
with the versioned attribute type_ N
.
In case that only the system_ext and product partitions are updated, say N
to N+1
(or later), while the vendor stays at N
, the vendor may lose access to the types of the system_ext and product partitions. To prevent breakage, the system_ext and product partitions should provide mapping files from concrete types into type_ N
attributes. Each partner is responsible for maintaining the mapping files, if they are going to support N
vendor with N+1
(or later) system_ext and product partitions.
To do that, partners are expected to:
- Copy the generated base mapping files from
N
system_ext and product partitions to their source tree. - Amend the mapping files as needed.
- Install the mapping files to
N+1
(or later) system_ext and product partitions.
For example, suppose that N
system_ext has one public type named foo_type
. Then system_ext/etc/selinux/mapping/ N .cil
in the N
system_ext partition will look like:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
If bar_type
is added to N+1
system_ext, and if bar_type
should be mapped to foo_type
for N
vendor, N .cil
can be updated from
(typeattributeset foo_type_N (foo_type))
to
(typeattributeset foo_type_N (foo_type bar_type))
and then installed to N+1
system_ext's partition. N
vendor can continue accessing to N+1
system_ext's foo_type
and bar_type
.
SELinux contexts labeling
To support the distinction between platform and vendor sepolicy, the system builds SELinux context files differently to keep them separate.
File contexts
Android 8.0 introduced the following changes for file_contexts
:
- To avoid additional compilation overhead on device during boot,
file_contexts
cease to exist in the binary form. Instead, they are readable, regular expression text file such as{property, service}_contexts
(as they were pre-7.0). - The
file_contexts
are split between two files:-
plat_file_contexts
- Android platform
file_context
that has no device-specific labels, except for labeling parts of/vendor
partition that must be labeled precisely to ensure proper functioning of the sepolicy files. - Must reside in
system
partition at/system/etc/selinux/plat_file_contexts
on device and be loaded byinit
at the start along with the vendorfile_context
.
- Android platform
-
vendor_file_contexts
- Device-specific
file_context
built by combiningfile_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must be installed at
/vendor/etc/selinux/vendor_file_contexts
invendor
partition and be loaded byinit
at the start along with the platformfile_context
.
- Device-specific
-
Property contexts
In Android 8.0, the property_contexts
is split between two files:
-
plat_property_contexts
- Android platform
property_context
that has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_property_contexts
and be loaded byinit
at the start along with the vendorproperty_contexts
.
- Android platform
-
vendor_property_contexts
- Device-specific
property_context
built by combiningproperty_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_property_contexts
and be loaded byinit
at the start along with the platformproperty_context
- Device-specific
Service contexts
In Android 8.0, the service_contexts
is split between the following files:
-
plat_service_contexts
- Android platform-specific
service_context
for theservicemanager
. Theservice_context
has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_service_contexts
and be loaded byservicemanager
at the start along with the vendorservice_contexts
.
- Android platform-specific
-
vendor_service_contexts
- Device-specific
service_context
built by combiningservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_service_contexts
and be loaded byservicemanager
at the start along with the platformservice_contexts
. - Although
servicemanager
looks for this file at boot time, for a fully compliantTREBLE
device, thevendor_service_contexts
MUST NOT exist. This is because all interaction betweenvendor
andsystem
processes MUST go throughhwservicemanager
/hwbinder
.
- Device-specific
-
plat_hwservice_contexts
- Android platform
hwservice_context
forhwservicemanager
that has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_hwservice_contexts
and be loaded byhwservicemanager
at the start along with thevendor_hwservice_contexts
.
- Android platform
-
vendor_hwservice_contexts
- Device-specific
hwservice_context
built by combininghwservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_hwservice_contexts
and be loaded byhwservicemanager
at the start along with theplat_service_contexts
.
- Device-specific
-
vndservice_contexts
- Device-specific
service_context
for thevndservicemanager
built by combiningvndservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
. - This file must reside in
vendor
partition at/vendor/etc/selinux/vndservice_contexts
and be loaded byvndservicemanager
at the start.
- Device-specific
Seapp contexts
In Android 8.0, the seapp_contexts
is split between two files:
-
plat_seapp_contexts
- Android platform
seapp_context
that has no device-specific changes. - Must reside in
system
partition at/system/etc/selinux/plat_seapp_contexts.
- Android platform
-
vendor_seapp_contexts
- Device-specific extension to platform
seapp_context
built by combiningseapp_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_seapp_contexts
.
- Device-specific extension to platform
MAC permissions
In Android 8.0, the mac_permissions.xml
is split between two files:
- Platform
mac_permissions.xml
- Android platform
mac_permissions.xml
that has no device-specific changes. - Must reside in
system
partition at/system/etc/selinux/.
- Android platform
- Non-Platform
mac_permissions.xml
- Device-specific extension to platform
mac_permissions.xml
built frommac_permissions.xml
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/.
- Device-specific extension to platform