Compatibilidade com a política

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ção vendor. A política da plataforma exige isso para acessar implementações de HAL de passagem.
  • Todos os novos exec_types adicionados na partição vendor pelo SEPolicy do fornecedor precisam ter o atributo vendor_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ção vendor.
  • 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 como sysfs por padrão.
  • A partir do nível 202504 da API do fornecedor, /sys/class/udc é rotulado sysfs_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.

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 de sysfs para sysfs_A). O código do fornecedor depende de uma regra que permite o acesso a sysfs e precisa incluir essa regra como um atributo do novo tipo.

Ao 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 entre vendor e coredomains. 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.
  • Atributo system_executes_vendor_violators. para todos os domínios do sistema (exceto init e shell 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 ser coredomain.

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:

  1. 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.
  2. Os servidores HAL (um subconjunto de serviços HwBinder) contêm código com maior taxa de incidência de problemas de segurança do que os componentes system/core e têm acesso às camadas 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ção surfaceflinger, que os apps podem acessar.
  • hal_omx_hwservice: essa é uma versão do HwBinder do serviço de Binder mediacodec, que os apps podem acessar.
  • hal_codec2_hwservice. Esta é uma versão mais recente de hal_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 é um binderservicedomain) se comunica com o hal_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 sysfssysfs_A ou mediaserveraudioserver, 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:

  1. Copie os arquivos de mapeamento de base gerados das partições N system_ext e product para a árvore de origem.
  2. Edite os arquivos de mapeamento conforme necessário.
  3. Instale os arquivos de mapeamento nas partições system_ext e product de N+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 por init no início, junto com o file_context do fornecedor.
    • vendor_file_contexts
      • file_context específico do dispositivo criado combinando file_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
      • Precisa ser instalado em /vendor/etc/selinux/vendor_file_contexts na partição vendor e ser carregado por init no início com a plataforma file_context.

Contextos de propriedade

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

  • plat_property_contexts
    • property_context da plataforma Android que não tem marcadores específicos do dispositivo.
    • Precisa residir na partição system em /system/etc/selinux/plat_property_contexts e ser carregada por init no início, junto com o property_contexts do fornecedor.
  • vendor_property_contexts
    • property_context específico do dispositivo criado combinando property_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Precisa residir na partição vendor em /vendor/etc/selinux/vendor_property_contexts e ser carregada por init no início, junto com a plataforma property_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 o servicemanager. O service_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 por servicemanager no início, junto com o service_contexts do fornecedor.
  • vendor_service_contexts
    • service_context específico do dispositivo criado combinando service_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Precisa residir na partição vendor em /vendor/etc/selinux/vendor_service_contexts e ser carregada por servicemanager no início, junto com a plataforma service_contexts.
    • Embora o servicemanager procure esse arquivo na inicialização, para um dispositivo TREBLE totalmente compatível, o vendor_service_contexts NÃO PODE existir. Isso ocorre porque toda interação entre os processos vendor e system precisa passar por hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • Plataforma Android hwservice_context para hwservicemanager 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 por hwservicemanager no início, junto com o vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context específico do dispositivo criado combinando hwservice_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Precisa residir na partição vendor em /vendor/etc/selinux/vendor_hwservice_contexts e ser carregada por hwservicemanager no início com o plat_service_contexts.
  • vndservice_contexts
    • service_context específico do dispositivo para o vndservicemanager criado combinando vndservice_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS no Boardconfig.mk do dispositivo.
    • Esse arquivo precisa residir na partição vendor em /vendor/etc/selinux/vndservice_contexts e ser carregado por vndservicemanager 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 combinando seapp_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Precisa estar na partição vendor em /vendor/etc/selinux/vendor_seapp_contexts.

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 de mac_permissions.xml encontrada nos diretórios apontados por BOARD_SEPOLICY_DIRS nos arquivos Boardconfig.mk do dispositivo.
    • Precisa estar na partição vendor em /vendor/etc/selinux/.