Compatibilidade com a política

Nesta página, descrevemos como o Android lida com os problemas de compatibilidade de políticas com atualizações OTA (pela rede) da plataforma, em que as novas configurações do SELinux da plataforma podem ser diferentes das configurações antigas do SELinux do fornecedor.

Propriedade e rotulagem de objetos

A propriedade precisa ser claramente definida para cada objeto, mantendo separadas as políticas da plataforma e do fornecedor. Por exemplo, se a política do fornecedor rotular /dev/foo e a política da plataforma rotular /dev/foo em uma OTA subsequente, haverá um comportamento indefinido, como uma negação inesperada ou, mais gravemente, uma falha de inicialização. Para o SELinux, isso se manifesta como uma colisão de rotulagem. O nó do dispositivo pode ter apenas um rótulo que é resolvido para o último rótulo aplicado. Como resultado:

  • Os processos que precisam de acesso ao rótulo que não foi aplicado perdem o acesso ao recurso.
  • Os processos que ganham acesso ao arquivo podem falhar porque o nó de dispositivo errado foi criado.

Colisões entre rótulos de plataforma e fornecedor podem ocorrer em qualquer objeto que tenha um rótulo do SELinux, incluindo propriedades, serviços, processos, arquivos e sockets. Para evitar esses problemas, defina claramente a propriedade desses objetos.

Namespaces de tipo/atributo

Além de colisões de rótulos, os nomes de tipos e atributos do SELinux também podem entrar em conflito. O SELinux não permite várias declarações dos mesmos tipos e atributos. Uma política com declarações duplicadas não é compilada. Para evitar colisões de tipo e nome de atributo, é altamente recomendável que todas as declarações de fornecedor comecem com o prefixo vendor_. Por exemplo, os fornecedores precisam usar type vendor_foo, domain; em vez de type foo, domain;.

Propriedade do arquivo

Evitar colisões para arquivos é um desafio porque a política da plataforma e do fornecedor geralmente fornece rótulos para todos os sistemas de arquivos. Ao contrário da nomenclatura de tipos, 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. No Android 8.0, essas são recomendações sem aplicação técnica. No futuro, essas recomendações serão aplicadas pelo Vendor Test Suite (VTS).

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 à política do fornecedor, uma atualização OTA somente de framework talvez não seja 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 escrever regras do SELinux para que os processos da plataforma possam se comunicar ou acessar partes da partição vendor (link em inglês). Exemplos:

/vendor path Rótulo fornecido pela plataforma Processos da plataforma dependendo do rótulo
/vendor(/.*)? vendor_file Todos os clientes HAL na estrutura, 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 arquivos adicionais na partição vendor:

  • vendor_file precisa ser o marcador padrão de todos os arquivos na partição vendor. A política da plataforma exige isso para acessar implementações de HAL de transferência direta.
  • Todos os novos exec_types adicionados na partição vendor pela política do fornecedor precisam ter o atributo vendor_file_type. Isso é imposto por "neverallows".
  • Para evitar conflitos com futuras atualizações de plataforma/framework, não rotule 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 rotuladas como same_process_hal_file..

Procfs (/proc)

Os arquivos em /proc podem ser rotulados usando apenas o rótulo genfscon. No Android 7.0, as políticas de plataforma e fornecedor usavam genfscon para rotular arquivos em procfs.

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

Debugfs (/sys/kernel/debug)

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

No Android 11, debugfs não pode ser acessado ou ativado 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 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, 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, somente o fornecedor poderá rotular arquivos.

tmpfs (/dev)

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

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

Rootfs (/)

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

Recomendação:somente 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 rótulos do Genfs

A partir do nível da API do fornecedor 202504, os rótulos mais recentes do SELinux atribuídos com genfscon em system/sepolicy/compat/plat_sepolicy_genfs_ver.cil são opcionais para partições vendor mais antigas. Isso permite que partições vendor mais antigas mantenham a implementação atual da SEPolicy. Isso é controlado pela variável BOARD_GENFS_LABELS_VERSION do Makefile, que é armazenada em /vendor/etc/selinux/genfs_labels_version.txt.

Exemplo:

  • No nível da API do fornecedor 202404, 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 como sysfs_udc.

No entanto, /sys/class/udc pode estar em uso por partições vendor usando o nível da API 202404, com o rótulo sysfs padrão ou um rótulo específico do fornecedor. Rotular incondicionalmente /sys/class/udc como sysfs_udc pode prejudicar a compatibilidade com essas partições vendor. Ao marcar BOARD_GENFS_LABELS_VERSION, a plataforma continua usando os rótulos e as permissões anteriores para as partições vendor mais antigas.

BOARD_GENFS_LABELS_VERSION pode ser maior ou igual ao nível da API do fornecedor. Por exemplo, as partições vendor que usam o nível da API 202404 podem definir BOARD_GENFS_LABELS_VERSION como 202504 para adotar novos rótulos introduzidos em 202504. Consulte a lista de rótulos genfs específicos de 202504.

Ao rotular nós genfscon, a plataforma precisa considerar partições vendor mais antigas e implementar mecanismos de substituição para compatibilidade quando necessário. A plataforma pode usar bibliotecas exclusivas para consultar a versão das rotulagens genfs.

Política pública da plataforma

A política do SELinux da plataforma é dividida em privada e pública. A política pública da plataforma consiste em tipos e atributos que estão sempre disponíveis para um nível da API do fornecedor, atuando como uma API entre a plataforma e o fornecedor. Essa política é exposta aos gravadores de políticas de fornecedores para permitir que eles criem arquivos de políticas de fornecedores que, quando combinados com a política privada da plataforma, resultam em uma política totalmente funcional para um dispositivo. A política pública da plataforma é definida em system/sepolicy/public.

Por exemplo, um tipo vendor_init, que representa o processo de inicialização no contexto do fornecedor, é definido em system/sepolicy/public/vendor_init.te:

type vendor_init, domain;

Os fornecedores podem consultar o tipo vendor_init para escrever regras de política personalizadas:

# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)

Atributos de compatibilidade

A política do SELinux é uma interação entre tipos de origem e destino para classes e permissões de objetos específicos. Cada objeto (por exemplo, processos, arquivos) 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. Aqui, vendor_init e debugfs são tipos:

allow vendor_init debugfs:dir { mounton };

Isso funciona porque a política foi escrita com conhecimento de todos os tipos. No entanto, se as políticas do fornecedor e 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 em que se baseava anteriormente. Por exemplo, suponha que a política da plataforma rotule os nós sysfs como sysfs:

/sys(/.*)? u:object_r:sysfs:s0

A política de fornecedores concede acesso a /sys/usb, rotulado como sysfs:

allow vendor_init sysfs:chr_file rw_file_perms;

Se a política da plataforma for alterada para rotular /sys/usb como sysfs_usb, a política do fornecedor vai permanecer a mesma, mas vendor_init vai perder o acesso a /sys/usb devido à falta de política para o novo tipo sysfs_usb:

/sys/usb u:object_r:sysfs_usb:s0

Para resolver esse problema, o Android introduz um conceito de atributos com versões. No tempo de compilação, o sistema de build traduz automaticamente os tipos públicos da plataforma usados na política do fornecedor para esses atributos versionados. Essa tradução é ativada por arquivos de mapeamento que associam um atributo com versão a um ou mais tipos públicos da plataforma.

Por exemplo, suponha que /sys/usb seja rotulado como sysfs na política da plataforma 202504, e a política do fornecedor 202504 conceda acesso vendor_init a /sys/usb. Nesse caso:

  • A política do fornecedor grava uma regra allow vendor_init sysfs:chr_file rw_file_perms; porque /sys/usb é rotulado como sysfs na política da plataforma 202504. Quando o sistema de build compila a política do fornecedor, ele traduz automaticamente a regra para allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. Os atributos vendor_init_202504 e sysfs_202504 correspondem aos tipos vendor_init e sysfs, que são os tipos definidos pela plataforma.
  • O sistema de build gera um arquivo de mapeamento de identidade /system/etc/selinux/mapping/202504.cil. Como as partições system e vendor usam a mesma versão 202504, o arquivo de mapeamento contém mapeamentos de identidade de type_202504 para type. Por exemplo, vendor_init_202504 é mapeado para vendor_init e sysfs_202504 é mapeado para sysfs:
    (typeattributeset sysfs_202504 (sysfs))
    (typeattributeset vendor_init_202504 (vendor_init))
    ...

Quando a versão é atualizada de 202504 para 202604, um novo arquivo de mapeamento para partições vendor de 202504 é criado em system/sepolicy/private/compat/202504/202504.cil, que é instalado em /system/etc/selinux/mapping/202504.cil para as partições system de 202604 ou mais recentes. Inicialmente, esse arquivo contém mapeamentos de identidade, conforme descrito anteriormente. Se um novo rótulo sysfs_usb para /sys/usb for adicionado à política da plataforma 202604, o arquivo de mapeamento será atualizado para mapear sysfs_202504 para sysfs_usb:

(typeattributeset sysfs_202504 (sysfs sysfs_usb))
(typeattributeset vendor_init_202504 (vendor_init))
...

Com essa atualização, a regra de política do fornecedor convertida allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms; concede automaticamente acesso vendor_init ao novo tipo sysfs_usb.

Para manter a compatibilidade com partições vendor mais antigas, sempre que um novo tipo público for adicionado, ele precisará ser mapeado para pelo menos um dos atributos com versão no arquivo de mapeamento system/sepolicy/private/compat/ver/ver.cil, ou ser listado em system/sepolicy/private/compat/ver/ver.ignore.cil para indicar que não há um tipo correspondente nas versões anteriores do fornecedor.

A combinação da política da plataforma, da política do fornecedor e do arquivo de mapeamento permite que o sistema seja atualizado sem atualizar a política do fornecedor. Além disso, a conversão em atributos versionados acontece automaticamente. Assim, a política do fornecedor não precisa cuidar do controle de versões, mantendo o uso dos tipos públicos no estado em que se encontra.

Política pública do sistema_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 vendor. Assim como a política pública da plataforma, a política do fornecedor usa tipos e regras traduzidos automaticamente para os atributos versionados, por exemplo, de type para type_ver, em que ver é o nível da API do fornecedor da partição vendor.

Quando as partições system_ext e product são baseadas na mesma versão da plataforma ver, o sistema de build gera arquivos de mapeamento de base para system_ext/etc/selinux/mapping/ver.cil e product/etc/selinux/mapping/ver.cil, que contêm mapeamentos de identidade de type para type_ver. A política do fornecedor pode acessar type com o atributo versionado type_ver.

Se apenas as partições system_ext e product forem atualizadas, digamos, de ver para ver+1 (ou posterior), enquanto a partição vendor permanecer em ver, a política do fornecedor poderá 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_ver. Cada parceiro é responsável por manter os arquivos de mapeamento, caso ofereçam suporte à partição ver vendor com ver+1 (ou posterior) system_ext e product.

Para instalar arquivos de mapeamento nas partições system_ext e product, os implementadores ou fornecedores de dispositivos precisam:

  1. Copie os arquivos de mapeamento de base gerados das partições ver, system_ext e product para a árvore de origem delas.
  2. Faça alterações nos arquivos de mapeamento conforme necessário.
  3. Instale os arquivos de mapeamento para ver+1 (ou posterior) system_ext e partições product.

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

(typeattributeset foo_type_202504 (foo_type))
(expandtypeattribute foo_type_202504 true)
(typeattribute foo_type_202504)

Se bar_type for adicionado ao system_ext 202604 e se bar_type precisar ser mapeado para foo_type na partição vendor 202504, 202504.cil poderá ser atualizado de (typeattributeset foo_type_202504 (foo_type)) para (typeattributeset foo_type_202504 (foo_type bar_type)) e instalado na partição system_ext 202604. A partição 202504 vendor pode continuar acessando o foo_type e o bar_type de 202604 system_ext.

Mudanças de atributos no Android 9

Os dispositivos que forem atualizados para o Android 9 podem usar os seguintes atributos, mas os dispositivos lançados com o Android 9 não podem.

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 a exigência de não compartilhar arquivos por caminho entre vendor e coredomains. Os processos de plataforma e fornecedor não devem 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 deve usar /data/vendor.
  • system_executes_vendor_violators. Atributo 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 deve 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 do HIDL.

      OU

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

Atributos não confiáveis

Apps não confiáveis que hospedam código arbitrário não devem ter acesso a serviços do HwBinder, exceto aqueles considerados suficientemente seguros para acesso por esses apps (consulte os serviços seguros abaixo). Os dois principais motivos são:

  1. Os servidores HwBinder não realizam a autenticação do cliente porque o HIDL não expõe informações de UID do caller. Mesmo que o HIDL exponha esses dados, muitos serviços do HwBinder operam em um nível abaixo dos apps (como HALs) ou não podem depender da identidade do app para autorização. Portanto, para garantir a segurança, a proposição padrão é que todo serviço do HwBinder trate 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 uma taxa de incidência maior 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 assim 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 nº 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 Binder mediacodec, que os apps podem acessar.
  • hal_codec2_hwservice, que é uma versão mais recente de hal_omx_hwservice.

Atributos utilizáveis

Todos os hwservices nã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 o 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 a HAL HIDL do fornecedor. Por exemplo, os apps podem conversar com binderservicedomain, e mediaserver (que é um binderservicedomain) conversa com o hal_graphics_allocator.

    OU

  • Os apps que precisam de acesso direto aos HALs vendor devem 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 apropriados (por exemplo, todos os arquivos em sysfs têm o atributo sysfs_type obrigatório).

Rotulagem de contextos do SELinux

Para oferecer suporte à distinção entre a política do SELinux da plataforma e 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 mudanças para file_contexts:

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

Contextos de propriedade

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

  • plat_property_contexts
    • Plataforma Android property_context sem rótulos específicos do dispositivo.
    • Precisa estar na partição system em /system/etc/selinux/plat_property_contexts e ser carregado pelo init no início junto com o property_contexts do fornecedor.
  • vendor_property_contexts
    • property_context específico do dispositivo criado combinando property_contexts encontrados 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_property_contexts e ser carregado 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 rótulos específicos do dispositivo.
    • Precisa estar na partição system em /system/etc/selinux/plat_service_contexts e ser carregado 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 estar na partição vendor em /vendor/etc/selinux/vendor_service_contexts e ser carregado pelo servicemanager no início, junto com a plataforma service_contexts.
    • Embora 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 sem rótulos específicos do dispositivo.
    • Precisa estar na partição system em /system/etc/selinux/plat_hwservice_contexts e ser carregado 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 estar na partição vendor em /vendor/etc/selinux/vendor_hwservice_contexts e ser carregado por hwservicemanager no início junto com o plat_service_contexts.
  • vndservice_contexts
    • service_context específico do dispositivo para o vndservicemanager criado combinando vndservice_contexts encontrado nos diretórios apontados por BOARD_SEPOLICY_DIRS no Boardconfig.mk do dispositivo.
    • Esse arquivo precisa estar 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 em dois arquivos:

  • plat_seapp_contexts
    • Plataforma Android seapp_context sem mudanças específicas do dispositivo.
    • Precisa estar na partição system em /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • Extensão específica do dispositivo para a plataforma seapp_context criada combinando seapp_contexts encontrados 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 MAC

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

  • Plataforma mac_permissions.xml
    • Plataforma Android mac_permissions.xml sem mudanças específicas do dispositivo.
    • Precisa estar na partição system em /system/etc/selinux/.
  • Não relacionada à plataforma mac_permissions.xml
    • Extensão específica do dispositivo para a plataforma mac_permissions.xml criada com base em 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/.

Mudanças na memória compartilhada para o Android 17

A partir do Android 17, os dispositivos lançados com as seguintes propriedades precisam ativar o recurso de política memfd_class e atualizar a política relacionada à memória compartilhada para oferecer suporte a objetos de classe memfd_file:

  • Nível da API do fornecedor 202604 ou mais recente para dar aos fornecedores e OEMs a oportunidade de atualizar a política de fornecedores e oferecer suporte a memfd. Ele também permite que os dispositivos atuais sejam atualizados para versões mais recentes do Android sem exigir uma atualização da partição do fornecedor.
  • android16-6.12 ou um kernel mais recente, já que eles são compatíveis com o recurso memfd_class, necessário para implementar uma política refinada para memfd.

Ativar a capacidade da política memfd_class

Até recentemente, o SELinux rotulava um memfd como um arquivo do mesmo tipo que o sistema de arquivos de suporte, o tmpfs. Isso impossibilitou distinguir um memfd de outro arquivo em uma montagem tmpfs do ponto de vista da política. Agora, o SELinux rotula um memfd com o contexto de segurança do processo de alocação, e os memfds são tratados como objetos de classe memfd_file. Essa funcionalidade é protegida pela capacidade da política memfd_class para preservar a compatibilidade com versões anteriores em ambientes de espaço do usuário mais antigos.

Para ativar a capacidade da política memfd_class, crie um arquivo policy_capabilities em BOARD_VENDOR_SEPOLICY_DIRS. O arquivo precisa conter a seguinte entrada:

# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;

Em seguida, recrie as imagens e atualize para o dispositivo para verificar se o recurso está ativado.

Verificar se o recurso de política memfd_class está ativado

Use o comando a seguir para verificar o status da capacidade da política memfd_class:

adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'

Se o resultado for 1, o recurso da política memfd_class estará ativado. Caso contrário, ele não será ativado.

Fazer a transição da política atual para memfd

Alguns processos usavam a macro tmpfs_domain() na política para acessar e criar namespaces para os memfds. Por exemplo:

# foo.te
tmpfs_domain(foo)

Isso significa:

# foo.te
type_transition foo tmpfs:file foo_tmpfs;
allow foo foo_tmpfs:file { read write getattr map };

e permite processar o processo de acesso bar do processo foo como segue:memfds

# bar.te
allow bar foo_tmpfs:file { read write getattr map };

Com o recurso de política memfd_class ativado, a macro tmpfs_domain() não é mais necessária, já que a política da plataforma foi atualizada para permitir que qualquer processo crie e use o próprio memfds, conforme mostrado aqui:

# system/sepolicy/private/domain.te
allow domain self:memfd_file { create read write getattr map };

e memfds criado pelo processo foo pode ser acessado pelo processo bar da seguinte maneira:

# bar.te
allow bar foo:memfd_file { read write getattr map };

A política da plataforma foi atualizada para considerar os usos atuais do memfd. No entanto, a política específica do fornecedor e do dispositivo que usa rótulos tmpfs precisa ser atualizada para usar memfd_file. Se a política for compartilhada entre SoCs ou dispositivos que não têm o nível 202604 da API do fornecedor ou mais recente, é recomendável manter a política legada tmpfs junto com a nova política memfd_file para compatibilidade.

Identificar negações de AVC relacionadas a memfd

As negações relacionadas a Memfd podem ser recuperadas usando o seguinte comando:

adb shell logcat -d -b events | grep memfd

negações de avc com tmpfs como destino

O exemplo a seguir mostra uma negação de avc encontrada por um processo que tentou gravar em um memfd sem permissão para isso:

audit(0.0:539): avc:  denied  { write } for  comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0

Quando o recurso de política memfd_class está ativado, o contexto de destino de um memfd é o contexto de segurança do processo de alocação, não tmpfs, e a classe de destino é memfd_file, não file. Portanto, se você estiver observando negações de avc relacionadas a memfd, em que o memfd em questão é rotulado como um arquivo tmpfs, o recurso de política memfd_class não está ativado.

negações de avc com memfd_file como a classe de destino

O exemplo a seguir mostra uma negação de avc encontrada por um processo que tenta gravar em um memfd sem permissão para isso. O recurso de política memfd_class estava ativado, assim como uma linha adicional que o logd emite após a negação com a mesma marca de tempo:

audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file

auditd  : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)

O carimbo de data/hora correspondente indica que o Decoded path for … log está relacionado à negação de avc com o carimbo de data/hora 0.0.86. Esse registro decodifica a string hexadecimal do valor do caminho na negação avc e fornece o nome da região de memória memfd, o que pode ser útil para entender qual buffer está sendo compartilhado. O contexto de origem e o contexto de destino são úteis para entender quais processos precisam compartilhar memória. No exemplo anterior, fica claro que o processo mediaserver precisa acessar o memfds de mediaextractor. Portanto, a política adequada é:

# mediaserver.te
allow mediaserver mediaextractor:memfd_file { getattr read write map };

Atualizações do domínio de segurança no Android 17

A API ASharedMemory_create() no Android 17 implementa lógica condicional para selecionar entre o driver ashmem legado e o framework memfd para alocações de memória compartilhada.

Para dispositivos que atendem aos requisitos de memfd (nível 202604 da API do fornecedor ou mais recente e kernel android16-6.12 ou mais recente), a API avalia o targetSdkVersion do app de chamada. Se a versão do SDK de destino for 37 ou mais recente, um memfd será alocado. Isso permite que os desenvolvedores corrijam os problemas encontrados ao fazer upgrade da versão do SDK de destino.

Se o dispositivo não atender aos pré-requisitos do memfd's, o ASharedMemory vai usar o ashmem. Isso mantém a compatibilidade para dispositivos atualizados com partições ou kernels de fornecedores mais antigos.

Para aplicar essa transição, a política do SELinux da plataforma impede que apps destinados à versão 37 ou mais recente do SDK nos domínios de segurança platform_app, priv_app e untrusted_app abram /dev/ashmem e invoquem comandos ioctl ashmem em memfd. Isso é feito dividindo esses domínios de app com base na versão do SDK de destino. Isso apresenta os domínios de segurança platform_app_36, priv_app_36 e untrusted_app_34, que, junto com outros domínios de apps, mantêm as permissões de abertura do ashmem e a capacidade de invocar comandos ioctl do ashmem em memfds.

Em uma versão futura do Android, o conjunto de apps que mantêm permissões para abrir o dispositivo ashmem e invocar comandos ioctl ashmem em memfds será reduzido apenas a platform_app_36, priv_app_36 e untrusted_app_34, além de domínios de apps não confiáveis para versões mais antigas do SDK.

As políticas personalizadas do fornecedor ou OEM do SELinux para apps que fixam a versão do SDK de destino precisam ser atualizadas para se alinhar a essas mudanças de domínio, conforme detalhado nas seções a seguir.

Atualizações do domínio SELinux platform_app

O domínio platform_app é dividido com base no targetSdkVersion do app. Os apps da plataforma destinados à versão 37 ou mais recente do SDK recebem o domínio platform_app, enquanto aqueles destinados à versão 36 ou anterior usam platform_app_36. O domínio platform_app_36 mantém a capacidade de abrir /dev/ashmem para compatibilidade com versões anteriores. Para simplificar o gerenciamento de políticas nos dois domínios, use o atributo platform_app_all.

Considere o caso em que o app da plataforma sample-plat-app precisa ler e gravar de e para /dev/foo_device. A política SELinux do fornecedor pode ser semelhante a esta:

# This will only allow sample-plat-app to access the device if it
# is placed in the platform_app domain (i.e. target SDK version is 37 or higher).
allow platform_app foo_device:chr_file rw_file_perms;

No entanto, se sample-plat-app for fixado na versão 36 do SDK de destino, ele será colocado no domínio platform_app_36, e a política do SELinux anterior não será aplicada. A seguinte negação de AVC será observada:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Para corrigir isso, a política pode ser atualizada da seguinte forma, já que o app sempre deve ter acesso ao nó do dispositivo:

# This allows sample-plat-app to access the device independent of
# target SDK version.
allow platform_app_all foo_device:chr_file rw_file_perms;

Há situações em que o platform_app_all pode não funcionar. Por exemplo, se a macro hal_client_domain() for usada com platform_app_all, a política não será compilada. Isso acontece porque platform_app_all é um atributo, e hal_client_domain() tentaria anexar outro atributo a ele, o que não é possível:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

Nesses cenários, é necessário usar o tipo platform_app_36 diretamente. Portanto, sua política tem o seguinte conteúdo:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

# platform_app_36.te
hal_client_domain(platform_app_36, hal_foo)

Atualizações do domínio SELinux priv_app

O domínio priv_app é dividido com base no targetSdkVersion do app. Os apps privilegiados destinados à versão 37 do SDK ou mais recente recebem o domínio priv_app, enquanto aqueles destinados à versão 36 ou anterior usam priv_app_36. O domínio priv_app_36 mantém a capacidade de abrir /dev/ashmem para compatibilidade com versões anteriores. Para simplificar o gerenciamento de políticas nos dois domínios, use o atributo priv_app_all.

Considere o caso em que o app da plataforma sample-priv-app precisa ler e gravar de e para /dev/foo_device. A política SELinux do fornecedor pode ser semelhante a esta:

# This will only allow sample-priv-app to access the device if it
# is placed in the priv_app domain (i.e. target SDK version is 37 or higher).
allow priv_app foo_device:chr_file rw_file_perms;

No entanto, se sample-priv-app for fixado na versão 36 do SDK de destino, ele será colocado no domínio priv_app_36, e a política do SELinux anterior não será aplicada. A seguinte negação de AVC será observada:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Para corrigir isso, a política pode ser atualizada da seguinte forma, já que o app sempre deve ter acesso ao nó do dispositivo:

# This allows sample-priv-app to access the device independent of
# target SDK version.
allow priv_app_all foo_device:chr_file rw_file_perms;

Há situações em que o priv_app_all pode não funcionar. Por exemplo, se a macro hal_client_domain() for usada com priv_app_all, a política não será compilada. Isso acontece porque priv_app_all é um atributo, e hal_client_domain() tentaria anexar outro atributo a ele, o que não é possível:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

Nesses cenários, é necessário usar o tipo priv_app_36 diretamente. Assim, os arquivos de política vão ficar assim:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

# priv_app_36.te
hal_client_domain(priv_app_36, hal_foo)

Atualizações do domínio SELinux untrusted_app

O domínio untrusted_app é dividido com base no targetSdkVersion do app. Os apps não confiáveis destinados à versão 37 do SDK ou mais recente recebem o domínio untrusted_app, enquanto aqueles destinados às versões 34 a 36, inclusive, recebem o novo domínio untrusted_app_34. O domínio untrusted_app_34, assim como os domínios untrusted_app_X, em que "X" é uma versão mais antiga do SDK de destino, mantêm a capacidade de abrir `/dev/ashmem` para compatibilidade com versões anteriores.