Este artigo descreve como o Android lida com os problemas de compatibilidade de políticas com atualizações OTA da plataforma, em que as novas configurações do SELinux da plataforma podem ser diferentes das antigas do fornecedor.
O design de política do SELinux baseado em Treble considera uma distinção binária
entre a política da plataforma e a do fornecedor. O esquema fica
mais complicado se as partições do fornecedor gerarem dependências, como
platform
< vendor
< oem
.
No Android 8.0 e versões mais recentes, a política global do SELinux é dividida em componentes públicos e privados. Os componentes públicos consistem na política e na infraestrutura associada, que são garantidas para uma versão da plataforma. Essa política será exposta aos autores de políticas de fornecedores para que eles possam criar 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 o controle de versão, a política pública da plataforma exportada será gravada como atributos.
- Para facilitar a criação de políticas, os tipos exportados serão transformados em atributos com versões como parte do processo de criação de políticas. Os tipos públicos também podem ser usados diretamente em decisões de rotulagem fornecidas pelos arquivos de contextos 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, o comportamento garantido pela política pública da plataforma em uma versão anterior não seja interrompido. Esse mapeamento é mantido atualizando um arquivo de mapeamento 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 de objetos
Ao personalizar a política no Android 8.0 e versões mais recentes, a propriedade precisa ser claramente definida
para que a política da plataforma e do fornecedor sejam separadas. Por exemplo, se
o fornecedor rotular /dev/foo
e a plataforma rotular
/dev/foo
em uma OTA subsequente, haverá um comportamento indefinido. No
SELinux, isso se manifesta como uma colisão de marcação. O nó do dispositivo pode ter apenas um
rótulo, que é resolvido para o rótulo aplicado por último. Como resultado:
- Os processos que precisam de acesso ao rótulo aplicado sem sucesso vão perder o acesso ao recurso.
- Os processos que têm acesso ao arquivo podem falhar porque o nó de dispositivo errado foi criado.
As propriedades do sistema também podem ter colisões de nomenclatura que podem resultar em comportamento indefinido no sistema (bem como na rotulagem do SELinux). Colisões entre rótulos de plataforma e de fornecedor podem ocorrer em 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 resulta em um erro do compilador de políticas.
Namespace de tipo/atributo
O SELinux não permite várias declarações do mesmo tipo/atributo. A política
com declarações duplicadas vai falhar na compilação. Para evitar conflitos de tipo e
nome de atributo, todas as declarações do fornecedor precisam ter um namespace
começando com vendor_
.
type foo, domain; → type vendor_foo, domain;
Propriedade do sistema e propriedade de rotulagem de processos
A melhor forma de evitar conflitos de marcação é usar namespaces de propriedade. Para identificar facilmente as propriedades da plataforma e evitar conflitos de nome ao renomear ou adicionar propriedades exportadas da plataforma, verifique se todas as propriedades do fornecedor têm os próprios prefixos:
Tipo de propriedade | Prefixos aceitáveis |
---|---|
propriedades de controle | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor.
|
leitura/gravação | vendor. |
somente leitura | ro.vendor. ro.boot. ro.hardware.
|
persistente | persist.vendor. |
Os fornecedores podem continuar usando ro.boot.*
(que vem do kernel
cmdline) e ro.hardware.*
(uma propriedade óbvia relacionada ao hardware).
Todos os serviços do fornecedor em arquivos init rc precisam 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
Impedir colisões de arquivos é um desafio porque a política da plataforma e do fornecedor geralmente fornecem rótulos para todos os sistemas de arquivos. Ao contrário da nomenclatura de tipo, o namespace de arquivos não é prático, já que 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 aplicação técnica. No futuro, essas recomendações serão aplicadas pelo Conjunto de teste de fornecedor (VTS, na sigla em inglês).
Sistema (/system)
Somente a imagem do sistema precisa 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 do framework poderá não ser possível.
Fornecedor (/vendor)
A política do SELinux do AOSP já rotula partes da partição vendor
com que a plataforma interage, o que permite gravar regras do SELinux para que os processos
da plataforma possam se comunicar e/ou acessar partes da partição vendor
. Exemplos:
Caminho /vendor |
Rótulo fornecido pela plataforma | Processos da plataforma dependendo do rótulo |
---|---|---|
/vendor(/.*)?
|
vendor_file
|
Todos os clientes HAL no framework, ueventd etc.
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat , appdomain etc.
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat , installd , idmap etc.
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server , zygote , idmap etc.
|
Como resultado, regras específicas precisam ser seguidas (aplicadas por
neverallows
) ao rotular outros arquivos na partição
vendor
:
vendor_file
precisa ser o rótulo padrão para todos os arquivos na partiçãovendor
. A política da plataforma exige isso para acessar implementações de HAL de passagem.- Todos os novos
exec_types
adicionados na partiçãovendor
pelo SEPolicy do fornecedor precisam ter o atributovendor_file_type
. Isso é aplicado com o neverallows. - Para evitar conflitos com futuras atualizações de plataforma/framework, evite rotular
arquivos diferentes de
exec_types
na partiçãovendor
. - Todas as dependências de biblioteca para HALs de mesmo processo identificados pelo AOSP precisam ser
marcadas como
same_process_hal_file.
.
Procfs (/proc)
Os arquivos em /proc
podem ser rotulados usando apenas o rótulo
genfscon
. No Android 7.0, a
plataforma
e a política do
fornecedor
usaram genfscon
para rotular arquivos em procfs
.
Recomendação:use apenas rótulos de política da plataforma /proc
.
Se os processos vendor
precisarem acessar arquivos em /proc
que
estão rotulados com o rótulo padrão (proc
), a política do fornecedor
não deve rotular explicitamente esses arquivos 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 pelo
procfs
e as rotule explicitamente conforme necessário.
Debugfs (/sys/kernel/debug)
Debugfs
pode ser rotulado em file_contexts
e
genfscon
. No Android 7.0 ao Android 10, a plataforma e o rótulo do fornecedor
debugfs
.
No Android 11, o debugfs
não pode ser
acessado ou montado em dispositivos de produção. Os fabricantes de dispositivos precisam
remover debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Tracefs
pode ser rotulado em file_contexts
e
genfscon
. No Android 7.0, apenas os rótulos da plataforma
são tracefs
.
Recomendação:apenas a plataforma pode rotular tracefs
.
Sysfs (/sys)
Os arquivos em /sys
podem ser rotulados usando file_contexts
e genfscon
. No Android 7.0, a plataforma e o fornecedor usam
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 poderá rotular os arquivos.
tmpfs (/dev)
Os arquivos em /dev
podem ser rotulados em file_contexts
. No
Android 7.0, os arquivos de rótulo de plataforma e de fornecedor estão aqui.
Recomendação:o fornecedor só pode rotular arquivos em
/dev/vendor
(por exemplo, /dev/vendor/foo
,
/dev/vendor/socket/bar
).
Rootfs (/)
Os arquivos em /
podem ser rotulados em file_contexts
. No Android
7.0, os arquivos de rótulo de plataforma e de fornecedor estão aqui.
Recomendação:apenas o sistema pode rotular arquivos em /
.
Dados (/data)
Os dados são rotulados por uma combinação de file_contexts
e
seapp_contexts
.
Recomendação:não permita a rotulagem do fornecedor fora de
/data/vendor
. Somente a plataforma pode rotular outras partes de
/data
.
Versão dos identificadores do Genfs
A partir do nível da API do fornecedor 202504, os identificadores SELinux
mais recentes atribuídos com genfscon
em
system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil
são opcionais para partições
mais antigas do fornecedor. Isso permite que partições de fornecedores mais antigas mantenham a implementação do SEPolicy atual. Isso
é controlado pela variável Makefile BOARD_GENFS_LABELS_VERSION
, que é armazenada em
/vendor/etc/selinux/genfs_labels_version.txt
.
Exemplo:
-
No nível 202404 da API do fornecedor, o nó
/sys/class/udc
é rotulado comosysfs
por padrão. -
A partir do nível 202504 da API do fornecedor,
/sys/class/udc
é rotuladosysfs_udc
.
No entanto, /sys/class/udc
pode estar em uso por partições do fornecedor usando o nível 202404 da API,
com o rótulo padrão sysfs
ou um rótulo específico do fornecedor. Marcar /sys/class/udc
como sysfs_udc
incondicionalmente pode interromper a compatibilidade com essas
partições do fornecedor. Ao marcar BOARD_GENFS_LABELS_VERSION
, a plataforma continua usando os
rótulos e as permissões anteriores para as partições de fornecedores mais antigas.
O BOARD_GENFS_LABELS_VERSION
pode ser maior ou igual ao nível da API do fornecedor. Por
exemplo, partições de fornecedores que usam o nível 202404 da API podem definir BOARD_GENFS_LABELS_VERSION
como 202504 para adotar novos identificadores introduzidos em 202504. Consulte a lista de
rótulos de genfs específicos para 202504.
Ao rotular nós genfscon
, a plataforma precisa considerar partições de fornecedores mais antigas e
implementar mecanismos de fallback para compatibilidade quando necessário. A plataforma pode usar bibliotecas exclusivas
para consultar a versão dos rótulos de genfs.
-
Em nativo, use
libgenfslabelsversion
. Consultegenfslabelsversion.h
para conferir o arquivo de cabeçalho delibgenfslabelsversion
. -
No Java, use
android.os.SELinux.getGenfsLabelsVersion()
.
Atributos de compatibilidade
A política do SELinux é uma interação entre tipos de origem e de destino para classes de objetos e permissões específicas. Todos os objetos (processos, arquivos etc.) afetados pela política do SELinux podem ter apenas um tipo, mas esse tipo pode ter vários atributos.
A política é escrita principalmente em termos de tipos existentes:
allow source_type target_type:target_class permission(s);
Isso funciona porque a política foi escrita com conhecimento de todos os tipos. No entanto, se a política do fornecedor e a política da plataforma usarem tipos específicos e o rótulo de um objeto específico mudar em apenas uma dessas políticas, a outra poderá conter uma política que ganhou ou perdeu o acesso anteriormente usado. Exemplo:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Pode ser alterado para:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Embora a política do fornecedor permaneça a mesma, o v_domain
perderá o acesso devido à falta de política para o novo tipo
sysfs_A
.
Ao definir uma política em termos de atributos, podemos atribuir ao objeto subjacente um tipo que tenha um atributo correspondente à política para a plataforma e o código do fornecedor. Isso pode ser feito para todos os tipos para criar uma política de atributo, 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ítica pública da plataforma, que é criada como parte da política do fornecedor.
A definição de política pública como atributos com versão atende a duas metas de compatibilidade de políticas:
- Garantir que o código do fornecedor continue funcionando após a atualização da plataforma. É possível fazer isso adicionando atributos a tipos concretos para objetos correspondentes aos que o código do fornecedor dependia, preservando o acesso.
- Possibilidade de desativar a política. Isso é feito delimitando claramente os conjuntos de políticas em atributos que podem ser removidos assim que a versão a que eles correspondem não tiver mais suporte. 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 o upgrade for feito.
Gravação de políticas
Para atingir o objetivo de não exigir conhecimento de mudanças específicas da versão para
o desenvolvimento de políticas, o Android 8.0 inclui um mapeamento entre os tipos de política
pública da plataforma e os atributos delas. O tipo foo
é mapeado
para o atributo foo_vN
, em que N
é a
versão de destino. vN
corresponde à
variável de build PLATFORM_SEPOLICY_VERSION
e tem o formato
MM.NN
, em que MM
corresponde ao número do SDK da plataforma
e NN
é uma versão específica da 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 em que a política da plataforma e do fornecedor pode ser criada para manter a interface entre as duas partições estável. Os redatores de políticas da plataforma e do fornecedor podem continuar a escrever a política como está escrita hoje.
A política pública da plataforma exportada como allow source_foo target_bar:class
perm;
é incluída como parte da política do fornecedor. Durante a
compilação (que inclui a
versão correspondente), ela é transformada na política que vai ser enviada para a
parte do fornecedor do dispositivo (mostrada no Common Intermediate
Language (CIL) transformado):
(allow source_foo_vN target_bar_vN (class (perm)))
Como a política do fornecedor nunca está à frente da plataforma, ela não precisa se preocupar com versões anteriores. No entanto, a política da plataforma precisa saber até onde a política do fornecedor é antiga, incluir atributos aos tipos e definir a política correspondente aos atributos com versão.
Diferenças de políticas
A criação automática de atributos adicionando _vN
ao final
de cada tipo não faz nada sem o mapeamento de atributos para tipos em diferenças
de versão. O Android mantém um mapeamento entre versões de 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))
Upgrade da plataforma
A seção a seguir detalha os cenários de upgrades de plataforma.
Mesmos tipos
Esse cenário ocorre quando um objeto não muda 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. Ela é representada na política transformada como:
binder_device_v1 … binder_device_vN
Ao fazer upgrade de v1
para v2
, a política da plataforma precisa
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 o endurecimento de políticas.
- Novo recurso. Quando o tipo está rotulando um objeto que não existia antes (como um novo processo de serviço), o código do fornecedor não interagia diretamente com ele, então nenhuma política correspondente existe. O novo atributo correspondente ao tipo não tem um atributo na versão anterior e, portanto, não precisa de uma entrada no arquivo de mapeamento que segmenta essa versão.
- Aprimoramento da política. Quando o tipo representa o
aumento da política, o novo atributo de tipo precisa ser vinculado a uma cadeia de atributos
correspondentes ao anterior (semelhante ao exemplo anterior, mudando
/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 fazer upgrade de v1
para v2
, a política da plataforma precisa
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
Esse cenário (raro) ocorre quando um tipo é removido, o que pode acontecer quando o objeto:
- 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 que já existe. Isso representa uma mesclagem de mapeamentos de atributos: o código do fornecedor ainda precisa ser capaz de acessar o objeto subjacente pelo atributo que ele tinha, mas o restante do sistema agora precisa ser capaz de acessá-lo com o novo atributo.
Se o atributo para o qual ele foi alterado for novo, a nova marcação será igual ao caso de novo tipo, exceto que, quando um rótulo existente for usado, a adição do novo tipo de atributo antigo fará com que outros objetos também rotulados com esse tipo sejam acessados. Isso é basicamente o que a plataforma faz, e é considerado um trade-off aceitável para manter a compatibilidade.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Exemplo de versão 1: tipos de redução (remoção de sysfs_A)
Ao fazer upgrade de v1
para v2
, a política da plataforma precisa
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: remoção completa (tipo foo)
Ao fazer upgrade de v1
para v2
, a política da plataforma precisa
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
Esse cenário ocorre quando um upgrade 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 de adição, pesquisa e
listagem, os demônios do fornecedor que queriam se registrar com o
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 esta:
allow {domain -coredomain} *:new_class perm;
Isso pode até exigir uma política que permita o acesso a todos os tipos de interface (política pública) para garantir que a imagem do fornecedor tenha acesso. Se isso resultar em uma política de segurança inaceitável (como pode acontecer com as mudanças do servicemanager), um upgrade do fornecedor poderá ser forçado.
Classe/permissões removidas
Esse cenário ocorre quando um gerenciador de objetos é removido (como o
gerenciador de objetos ZygoteConnection
) e não deve causar problemas. A
classe do gerenciador de objetos e as permissões podem permanecer definidas na política até que a
versão do fornecedor não as use mais. Para isso, adicione as definições
ao arquivo de mapeamento correspondente.
Personalização do fornecedor para tipos novos/remarcados
Os novos tipos de fornecedores são o núcleo do desenvolvimento de políticas de fornecedores, já que são necessários para descrever novos processos, binários, dispositivos, subsistemas e dados armazenados. Por isso, é necessário permitir a criação de tipos definidos pelo fornecedor.
Como a política do fornecedor é sempre a mais antiga no dispositivo, não é necessário
converter automaticamente todos os tipos de fornecedor em atributos na política. A plataforma
não depende de nada rotulado na política do fornecedor porque não tem
conhecimento sobre ela. No entanto, a plataforma fornece os atributos e os tipos
públicos que ela usa para interagir com objetos rotulados com esses tipos (como
domain
, sysfs_type
etc.). Para que a plataforma
continue a interagir corretamente com esses objetos, os atributos e tipos
precisam ser aplicados de forma adequada, e regras específicas podem precisar ser adicionadas aos
domínios personalizáveis (como init
).
Mudanças de atributo para o Android 9
Os dispositivos que fazem upgrade para o Android 9 podem usar os atributos a seguir, mas os dispositivos que são 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 entrevendor
ecoredomains
. Os processos da plataforma e do fornecedor não podem usar arquivos no disco para se comunicar (ABI instável). Recomendação:- O código do fornecedor precisa usar
/data/vendor
. - O sistema não pode usar
/data/vendor
.
- O código do fornecedor precisa usar
- Atributo
system_executes_vendor_violators
. para todos os domínios do sistema (excetoinit
eshell domains
) que violam o requisito de não executar binários do fornecedor. A execução de binários do fornecedor tem uma API instável. A plataforma não pode executar binários do fornecedor diretamente. Recomendação:- Essas dependências de plataforma em binários do fornecedor precisam estar por trás das HALs HIDL.
OU
- Os
coredomains
que precisam de acesso aos binários do fornecedor precisam ser movidos para a partição do fornecedor e, portanto, deixar de sercoredomain
.
- Essas dependências de plataforma em binários do fornecedor precisam estar por trás das HALs HIDL.
Atributos não confiáveis
Apps não confiáveis que hospedam códigos arbitrários não podem ter acesso aos serviços do HwBinder, exceto aqueles considerados suficientemente seguros para acesso por esses apps (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 de UID do autor da chamada. Mesmo que o HIDL tenha exposto esses dados, muitos serviços do HwBinder operam em um nível abaixo do dos apps (como HALs) ou não dependem da identidade do app para autorização. Portanto, para garantir a segurança, a suposição padrão é que todos os serviços HwBinder tratem todos os clientes como igualmente autorizados a realizar 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 os componentes
system/core
e têm acesso às camadas mais baixas da pilha (até o hardware), aumentando as oportunidades de ignorar 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 em que o processo é executado.coredomain_hwservice
. Esses serviços não apresentam riscos associados ao motivo 2.hal_configstore_ISurfaceFlingerConfigs
. Esse serviço foi projetado especificamente para uso em qualquer domínio.hal_graphics_allocator_hwservice
. Essas operações também são oferecidas pelo serviço de vinculaçãosurfaceflinger
, que os apps podem acessar.hal_omx_hwservice
: essa é uma versão do HwBinder do serviço de Bindermediacodec
, que os apps podem acessar.hal_codec2_hwservice
. Esta é uma versão mais recente dehal_omx_hwservice
.
Atributos utilizáveis
Todos os hwservices
que não são considerados seguros têm o atributo
untrusted_app_visible_hwservice
. Os servidores HAL correspondentes têm
o atributo untrusted_app_visible_halserver
. Os dispositivos lançados
com o Android 9 NÃO PODEM usar nenhum
atributo untrusted
.
Recomendação:
- Em vez disso, os apps não confiáveis precisam se comunicar com um serviço do sistema que se comunica com o
HAL HIDL do fornecedor. Por exemplo, os apps podem se comunicar com
binderservicedomain
e, em seguida,mediaserver
(que é umbinderservicedomain
) se comunica com ohal_graphics_allocator
.OU
- Os apps que precisam de acesso direto aos HALs
vendor
precisam ter o próprio domínio de sepolicy definido pelo fornecedor.
Testes de atributos de arquivo
O Android 9 inclui testes de tempo de build que garantem que todos os arquivos em locais
específicos tenham os atributos adequados. Por exemplo, todos os arquivos em
sysfs
têm o atributo sysfs_type
obrigatório.
Política pública da plataforma
A política pública da 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 da v2. Os fornecedores são expostos a um subconjunto da política da plataforma que
contém tipos e atributos e regras utilizáveis sobre esses tipos e atributos,
que depois se tornam parte da política do fornecedor (ou seja,
vendor_sepolicy.cil
).
Os tipos e as regras são traduzidos automaticamente na política gerada pelo fornecedor
em attribute_vN
, 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 ela fornece para os atributos
adequados para garantir que a política do fornecedor continue funcionando e que as regras
fornecidas para uma versão específica sejam incluídas. A combinação da
política pública da plataforma e da política do fornecedor atende à meta do modelo de arquitetura
do Android 8.0 de permitir builds independentes da plataforma e do fornecedor.
Mapeamento para cadeias de atributos
Ao usar atributos para mapear para versões de políticas, um tipo é mapeado para um ou vários atributos, garantindo que os objetos rotulados com o tipo sejam acessíveis por atributos correspondentes aos tipos anteriores.
Manter uma meta para ocultar informações de versão do roteador de políticas significa
gerar automaticamente os atributos versionados e atribuí-los aos
tipos apropriados. No caso comum de tipos estáticos, isso é simples:
type_foo
é mapeado para type_foo_v1
.
Para uma mudança de rótulo de objeto, como sysfs
→ sysfs_A
ou
mediaserver
→ audioserver
, a criação desse mapeamento não é
trivial (e é descrita nos exemplos acima). Os mantenedores de políticas da plataforma
precisam determinar como criar o mapeamento nos pontos de transição dos objetos, o que
exige entender a relação entre os objetos e os rótulos
atribuídos a eles 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 sepolicy quando uma nova
ramificação de lançamento é cortada. Conforme descrito acima, o número da versão está contido em
PLATFORM_SEPOLICY_VERSION
e tem o formato MM.nn
,
em que MM
corresponde ao valor do SDK e nn
é um
valor privado mantido em /platform/system/sepolicy.
. Por
exemplo, 19.0
para Kitkat, 21.0
para Lollipop,
22.0
para Lollipop-MR1, 23.0
para Marshmallow, 24.0
para Nougat, 25.0
para Nougat-MR1, 26.0
para Oreo, 27.0
para Oreo-MR1 e
28.0
para Android 9.
Os Uprevs nem sempre são números inteiros. Por
exemplo, se um aumento de MR em uma versão exigir uma mudança incompatível em
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 é uma 10000.0
que nunca será usada em dispositivos de envio.
O Android pode descontinuar a versão mais antiga ao fazer upgrade. Para saber quando descontinuar uma versão, o Android pode coletar o número de dispositivos com políticas do fornecedor que executam essa versão do Android e ainda recebem atualizações principais da plataforma. Se o número for menor que um determinado limite, essa versão será descontinuada.
Impacto no desempenho de vários atributos
Conforme descrito em https://github.com/SELinuxProject/cil/issues/9, um grande número de atributos atribuídos a um tipo resulta em problemas de desempenho no caso de uma falha de cache de política.
Isso foi confirmado como um problema no Android. Por isso, mudanças foram feitas no Android 8.0 para remover atributos adicionados à política pelo compilador de políticas e para remover atributos não usados. Essas mudanças resolveram regressões de desempenho.
Política pública de system_ext e do produto
A partir do Android 11, as partições system_ext
e product
podem
exportar os 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 traduzidos automaticamente para
os atributos com versão, por exemplo, de type
para
type_N
, em que N
é a versão
da plataforma para a qual a partição do fornecedor é criada.
Quando as partições system_ext
e product
são baseadas na mesma versão da plataforma
N
, o sistema de build gera arquivos de mapeamento de base para
system_ext/etc/selinux/mapping/N.cil
e
product/etc/selinux/mapping/N.cil
, que contêm mapeamentos de
identidade de type
para type_N
. O fornecedor pode
acessar type
com o atributo com versão type_N
.
Caso apenas as partições system_ext
e product
sejam atualizadas, por exemplo,
N
para N+1
(ou mais recente), enquanto o
fornecedor permanece em N
, ele pode perder o acesso aos
tipos das partições system_ext
e product
. Para evitar falhas, as partições
system_ext
e product
precisam fornecer arquivos de mapeamento de tipos concretos
para atributos type_N
. Cada parceiro é
responsável por manter os arquivos de mapeamento, se eles forem compatíveis com
o fornecedor N
com N+1
(ou mais recente)
system_ext
e partições product
.
Para isso, os parceiros precisam:
- Copie os arquivos de mapeamento de base gerados das partições
N
system_ext
eproduct
para a árvore de origem. - Edite os arquivos de mapeamento conforme necessário.
-
Instale os
arquivos de mapeamento nas partições
system_ext
eproduct
deN+1
(ou mais recente).
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 system_ext
N
vai ficar assim:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
Se bar_type
for adicionado ao system_ext de N+1
e
bar_type
precisar ser mapeado para foo_type
para o
fornecedor N
, N.cil
poderá ser atualizado de
(typeattributeset foo_type_N (foo_type))
a
(typeattributeset foo_type_N (foo_type bar_type))
e depois instalada na partição N+1
system_ext.
O fornecedor N
pode continuar acessando N+1
foo_type
e bar_type
do system_ext.
Marcação de contextos do SELinux
Para oferecer suporte à distinção entre a política de segurança da plataforma e do fornecedor, o sistema cria arquivos de contexto do SELinux de maneira diferente para mantê-los separados.
Contextos de arquivos
O Android 8.0 apresentou as seguintes mudanças para file_contexts
:
- Para evitar uma 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). - O
file_contexts
é dividido em dois arquivos:plat_file_contexts
file_context
da plataforma Android que não tem rótulos específicos do dispositivo, exceto para rotular partes da partição/vendor
que precisam ser rotuladas com precisão para garantir o funcionamento adequado dos arquivos sepolicy.- Precisa residir na partição
system
em/system/etc/selinux/plat_file_contexts
no dispositivo e ser carregada porinit
no início, junto com ofile_context
do fornecedor.
vendor_file_contexts
file_context
específico do dispositivo criado combinandofile_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo.- Precisa ser instalado em
/vendor/etc/selinux/vendor_file_contexts
na partiçãovendor
e ser carregado porinit
no início com a plataformafile_context
.
Contextos de propriedade
No Android 8.0, o property_contexts
é dividido entre dois arquivos:
plat_property_contexts
property_context
da plataforma Android que não tem marcadores específicos do dispositivo.- Precisa residir na partição
system
em/system/etc/selinux/plat_property_contexts
e ser carregada porinit
no início, junto com oproperty_contexts
do fornecedor.
vendor_property_contexts
property_context
específico do dispositivo criado combinandoproperty_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo.- Precisa residir na partição
vendor
em/vendor/etc/selinux/vendor_property_contexts
e ser carregada porinit
no início, junto com a plataformaproperty_context
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 marcadores específicos do dispositivo.- Precisa residir na partição
system
em/system/etc/selinux/plat_service_contexts
e ser carregada porservicemanager
no início, junto com oservice_contexts
do fornecedor.
vendor_service_contexts
service_context
específico do dispositivo criado combinandoservice_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo.- Precisa residir na partição
vendor
em/vendor/etc/selinux/vendor_service_contexts
e ser carregada porservicemanager
no início, junto com a plataformaservice_contexts
. - Embora o
servicemanager
procure esse arquivo na inicialização, para um dispositivoTREBLE
totalmente compatível, ovendor_service_contexts
NÃO PODE existir. Isso ocorre porque toda interação entre os processosvendor
esystem
precisa passar porhwservicemanager
/hwbinder
.
plat_hwservice_contexts
- Plataforma Android
hwservice_context
parahwservicemanager
que não tem rótulos específicos do dispositivo. - Precisa residir na partição
system
em/system/etc/selinux/plat_hwservice_contexts
e ser carregada porhwservicemanager
no início, junto com ovendor_hwservice_contexts
.
- Plataforma Android
vendor_hwservice_contexts
hwservice_context
específico do dispositivo criado combinandohwservice_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo.- Precisa residir na partição
vendor
em/vendor/etc/selinux/vendor_hwservice_contexts
e ser carregada porhwservicemanager
no início com oplat_service_contexts
.
vndservice_contexts
service_context
específico do dispositivo para ovndservicemanager
criado combinandovndservice_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
noBoardconfig.mk
do dispositivo.- Esse arquivo precisa residir na partição
vendor
em/vendor/etc/selinux/vndservice_contexts
e ser carregado porvndservicemanager
no início.
Contextos do Seapp
No Android 8.0, o seapp_contexts
é dividido entre dois arquivos:
plat_seapp_contexts
seapp_context
da plataforma Android que não tem mudanças específicas para cada dispositivo.- Precisa estar na partição
system
em/system/etc/selinux/plat_seapp_contexts.
vendor_seapp_contexts
- Extensão específica do dispositivo para
seapp_context
da plataforma criada combinandoseapp_contexts
encontrado nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Precisa estar na partição
vendor
em/vendor/etc/selinux/vendor_seapp_contexts
.
- Extensão específica do dispositivo para
Permissões de MAC
No Android 8.0, o mac_permissions.xml
é dividido entre dois arquivos:
- Plataforma
mac_permissions.xml
mac_permissions.xml
da plataforma Android que não tem mudanças específicas para cada dispositivo.- Precisa estar 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
criada a partir demac_permissions.xml
encontrada nos diretórios apontados porBOARD_SEPOLICY_DIRS
nos arquivosBoardconfig.mk
do dispositivo. - Precisa estar na partição
vendor
em/vendor/etc/selinux/.
- Extensão específica do dispositivo para a plataforma