Controle de acesso discricionário (DAC, na sigla em inglês)

Os objetos e serviços do sistema de arquivos adicionados ao build geralmente precisam de IDs exclusivos separados, conhecidos como IDs do Android (AIDs). Atualmente, muitos recursos, como arquivos e serviços, usam AIDs principais (definidos pelo Android) desnecessariamente. Em muitos casos, é possível usar AIDs de OEM (definidos pelo OEM).

As versões anteriores do Android (Android 7.x e anteriores) estenderam o mecanismo de AIDs usando um arquivo android_filesystem_config.h específico do dispositivo para especificar os recursos do sistema de arquivos e/ou os AIDs personalizados do OEM. No entanto, esse sistema não era intuitivo, porque não permitia o uso de nomes agradáveis para AIDs OEM, exigindo que você especificasse o número bruto para campos de usuário e grupo sem uma maneira de associar um nome amigável ao AID numérico.

Versões mais recentes do Android (Android 8.0 e versões mais recentes) oferecem suporte a um novo método para estender os recursos do sistema de arquivos. Esse novo método oferece suporte para os seguintes recursos:

  • Vários locais de origem para os arquivos de configuração (ativa configurações de build extensíveis).
  • Verificação de sanidade dos valores de AID do OEM no tempo de build.
  • Geração de um cabeçalho AID do OEM personalizado que pode ser usado em arquivos de origem, conforme necessário.
  • Associação de um nome amigável com o valor real do AID do OEM. Suporta argumentos de string não numérica para usuário e grupo, ou seja, "foo" em vez de "2901".

Outras melhorias incluem a remoção da matriz android_ids[] de system/core/libcutils/include/private/android_filesystem_config.h. Essa matriz agora existe no Bionic como uma matriz gerada totalmente particular, com os acessadores com getpwnam() e getgrnam(). Isso tem o efeito colateral de produzir binários estáveis à medida que os AIDs do núcleo são modificados. Para ferramentas e um arquivo README com mais detalhes, consulte build/make/tools/fs_config.

Adicionar IDs do Android (AIDs)

O Android 8.0 removeu a matriz android_ids[] do Android Open Source Project (AOSP). Todos os nomes compatíveis com AID são gerados a partir do arquivo de cabeçalho system/core/libcutils/include/private/android_filesystem_config.h ao gerar a matriz android_ids[] do Bionic. Qualquer define correspondente a AID_* é detectado pela ferramenta e * se torna o nome em letras minúsculas.

Por exemplo, em private/android_filesystem_config.h:

#define AID_SYSTEM 1000

O resultado é:

  • Nome amigável: system
  • uid: 1000
  • gid: 1000

Para adicionar um novo AID principal do AOSP, basta adicionar o #define ao arquivo de cabeçalho android_filesystem_config.h. O AID é gerado no build e disponibilizado para interfaces que usam argumentos de usuário e grupo. A ferramenta valida se o novo AID está dentro dos intervalos de APP ou OEM. Ela também respeita as mudanças nesses intervalos e precisa ser reconfigurada automaticamente em caso de mudanças ou novos intervalos reservados pelo OEM.

Configurar AIDs

Para ativar o novo mecanismo de AIDs, defina TARGET_FS_CONFIG_GEN no arquivo BoardConfig.mk. Essa variável contém uma lista de arquivos de configuração, permitindo que você anexe arquivos conforme necessário.

Por convenção, os arquivos de configuração usam o nome config.fs, mas, na prática, você pode usar qualquer nome. Os arquivos config.fs estão no formato ini do ConfigParser do Python e incluem uma seção de caps (para configurar os recursos do sistema de arquivos) e uma seção de AIDs (para configurar AIDs OEM).

Configurar a seção de tampas

A seção de maiúsculas oferece suporte à configuração de recursos do sistema de arquivos em objetos do sistema de arquivos no build. O próprio sistema de arquivos também precisa oferecer suporte a essa funcionalidade.

Como a execução de um serviço estável como raiz no Android causa uma falha no conjunto de teste de compatibilidade (CTS), os requisitos anteriores para manter um recurso durante a execução de um processo ou serviço envolviam a configuração de recursos e, em seguida, o uso de setuid/setgid para um AID adequado. Com o caps, você pode pular esses requisitos e deixar que o kernel faça isso por você. Quando o controle é entregue a main(), seu processo já tem os recursos necessários para que seu serviço possa usar um usuário e um grupo não raiz (essa é a maneira preferencial de iniciar serviços privilegiados).

A seção de letras maiúsculas usa a seguinte sintaxe:

Seção Valor Definição
[path] O caminho do sistema de arquivos a ser configurado. Um caminho que termina em / é considerado um diretório, caso contrário, é um arquivo.

É um erro especificar várias seções com o mesmo [path] em arquivos diferentes. Nas versões do Python 3.2 ou anteriores, o mesmo arquivo pode conter seções que substituem a anterior. No Python 3.2, ele é definido como modo estrito.
mode Modo de arquivo octal Um modo de arquivo octal válido de pelo menos três dígitos. Se 3 for especificado, ele terá um prefixo 0. Caso contrário, o modo será usado como está.
user AID_<usuário> O C define para um AID válido ou o nome amigável (por exemplo, AID_RADIO e radio são aceitáveis). Para definir um AID personalizado, consulte a seção Como configurar o AID.
group AID_<group> Igual ao usuário.
caps cap* O nome declarado em bionic/libc/kernel/uapi/linux/capability.h sem o CAP_ inicial. É permitido usar letras maiúsculas e minúsculas. As letras maiúsculas também podem ser o bruto:
  • binário (0b0101)
  • octal (0455)
  • int (42)
  • hexadecimal (0xFF)
Separe várias letras maiúsculas usando espaços.

Para conferir um exemplo de uso, consulte Como usar os recursos do sistema de arquivos.

Configurar a seção AID

A seção AID contém AIDs do OEM e usa a seguinte sintaxe:

Seção Valor Definição
[AID_<name>] O <name> pode conter caracteres em maiúsculas, números e sublinhados. A versão em letras minúsculas é usada como o nome amigável. O arquivo principal gerado para inclusão de código usa o AID_<name> exato.

É um erro especificar várias seções com o mesmo AID_<name> (independentemente da maiúscula ou minúscula, com as mesmas restrições que [path]).

<name> precisa começar com um nome de partição para garantir que não haja conflito com diferentes fontes.
value <número> Uma string de número de estilo C válida (hexa, octal, binário e decimal).

É um erro especificar várias seções com a opção de mesmo valor.

As opções de valor precisam ser especificadas no intervalo correspondente à partição usada em <name>. A lista de partições válidas e os intervalos correspondentes são definidos em system/core/libcutils/include/private/android_filesystem_config.h. As opções são:
  • Partição do fornecedor
    • AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
    • AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
  • Partição do sistema
    • AID_SYSTEM_RESERVED_START(6000) - AID_SYSTEM_RESERVED_END(6499)
  • Partição ODM
    • AID_ODM_RESERVED_START(6500) - AID_ODM_RESERVED_END(6999)
  • Partição de produtos
    • AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • Partição System_ext
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

Para conferir exemplos de uso, consulte Como definir nomes de AID OEM e Como usar AIDs OEM.

Exemplos de uso

Os exemplos a seguir detalham como definir e usar um OEM AID e como ativar os recursos do sistema de arquivos. Os nomes de AID do OEM ([AID_name]) precisam começar com um nome de partição, como vendor_, para garantir que não entrem em conflito com nomes AOSP futuros ou outras partições.

Definir nomes de AID de OEM

Para definir um AID OEM, crie um arquivo config.fs e defina o valor do AID. Por exemplo, em device/x/y/config.fs, defina o seguinte:

[AID_VENDOR_FOO]
value: 2900

Depois de criar o arquivo, defina a variável TARGET_FS_CONFIG_GEN e aponte para ela em BoardConfig.mk. Por exemplo, em device/x/y/BoardConfig.mk, defina o seguinte:

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

Agora, seu AID personalizado pode ser consumido pelo sistema em um novo build.

Usar AIDs OEM

Para usar um AID OEM, no código C, inclua o oemaids_headers no Makefile associado e adicione #include "generated_oem_aid.h". Em seguida, comece a usar os identificadores declarados. Por exemplo, em my_file.c, adicione o seguinte:

#include "generated_oem_aid.h"


If (ipc->uid == AID_VENDOR_FOO) {
  // Do something
...

No arquivo Android.bp associado, adicione o seguinte:

header_libs: ["oemaids_headers"],

Se você estiver usando um arquivo Android.mk, adicione o seguinte:

LOCAL_HEADER_LIBRARIES := oemaids_headers

Usar nomes amigáveis

No Android 9, é possível usar o nome amigável para qualquer interface compatível com nomes de AID. Exemplo:

  • Em um comando chown em some/init.rc:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • Em uma service em some/init.rc:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

Como o mapeamento interno do nome amigável para o uid é realizado por /vendor/etc/passwd e /vendor/etc/group, a partição do fornecedor precisa ser montada.

Associar nomes amigáveis

O Android 9 inclui suporte para a associação de um nome amigável ao valor real do AID do OEM. É possível usar argumentos de string não numéricos para usuário e grupo, ou seja, "vendor_foo" em vez de "2901".

Converter de AID para nomes amigáveis

Para AIDs OEM, o Android 8.x exigia o uso de oem_#### com getpwnam e funções semelhantes, bem como em locais que processam pesquisas com getpwnam (como scripts init). No Android 9, é possível usar os amigos getpwnam e getgrnam no Bionic para converter de IDs do Android (AIDs) para nomes amigáveis e vice-versa.

Usar recursos do sistema de arquivos

Para ativar os recursos do sistema de arquivos, crie uma seção em limites no arquivo config.fs. Por exemplo, em device/x/y/config.fs, adicione esta seção:

[system/bin/foo_service]
mode: 0555
user: AID_VENDOR_FOO
group: AID_SYSTEM
caps: SYS_ADMIN | SYS_NICE

Depois de criar o arquivo, defina o TARGET_FS_CONFIG_GEN para apontar para esse arquivo em BoardConfig.mk. Por exemplo, em device/x/y/BoardConfig.mk, defina o seguinte:

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

Quando o serviço vendor_foo é executado, ele começa com os recursos CAP_SYS_ADMIN e CAP_SYS_NICE sem chamadas setuid e setgid. Além disso, a política SELinux do serviço vendor_foo não precisa mais de capacidade setuid e setgid e pode ser excluída.

Configurar substituições (Android 6.x-7.x)

O Android 6.0 realocou fs_config e definições de estrutura associadas (system/core/include/private/android_filesystem_config.h) para system/core/libcutils/fs_config.c, onde elas podem ser atualizadas ou substituídas por arquivos binários instalados em /system/etc/fs_config_dirs e /system/etc/fs_config_files. O uso de regras de correspondência e análise separadas para diretórios e arquivos (que podem usar expressões glob adicionais) permitiu que o Android processasse diretórios e arquivos em duas tabelas diferentes. As definições de estrutura em system/core/libcutils/fs_config.c não apenas permitiam a leitura de diretórios e arquivos no ambiente de execução, mas o host podia usar os mesmos arquivos durante o build para criar imagens do sistema de arquivos como ${OUT}/system/etc/fs_config_dirs e ${OUT}/system/etc/fs_config_files.

Embora o método de substituição de extensão do sistema de arquivos tenha sido substituído pelo sistema de configuração modular introduzido no Android 8.0, ainda é possível usar o método antigo, se necessário. As seções a seguir detalham como gerar e incluir arquivos de substituição e configurar o sistema de arquivos.

Gerar arquivos de substituição

É possível gerar os arquivos binários alinhados /system/etc/fs_config_dirs e /system/etc/fs_config_files usando a ferramenta fs_config_generate em build/tools/fs_config. A ferramenta usa uma função da biblioteca libcutils (fs_config_generate()) para gerenciar os requisitos do DAC em um buffer e define regras para um arquivo de inclusão para institucionalizar as regras do DAC.

Para usar, crie um arquivo de inclusão em device/vendor/device/android_filesystem_config.h que funcione como a substituição. O arquivo precisa usar o formato structure fs_path_config definido em system/core/include/private/android_filesystem_config.h com as seguintes inicializações de estrutura para símbolos de diretório e arquivo:

  • Para diretórios, use android_device_dirs[].
  • Para arquivos, use android_device_files[].

Quando não estiver usando android_device_dirs[] e android_device_files[], você poderá definir NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS e NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES (consulte o exemplo abaixo). Também é possível especificar o arquivo de substituição usando TARGET_ANDROID_FILESYSTEM_CONFIG_H na configuração da placa, com um nome de base forçado de android_filesystem_config.h.

Incluir arquivos de substituição

Para incluir arquivos, verifique se PRODUCT_PACKAGES inclui fs_config_dirs e/ou fs_config_files para que possa instalá-los em /system/etc/fs_config_dirs e /system/etc/fs_config_files, respectivamente. O sistema de build procura android_filesystem_config.h personalizados em $(TARGET_DEVICE_DIR), onde BoardConfig.mk existe. Se esse arquivo existir em outro lugar, defina a variável de configuração da placa TARGET_ANDROID_FILESYSTEM_CONFIG_H para apontar para esse local.

Configurar o sistema de arquivos

Para configurar o sistema de arquivos no Android 6.0 e versões mais recentes:

  1. Crie o arquivo $(TARGET_DEVICE_DIR)/android_filesystem_config.h.
  2. Adicione fs_config_dirs e/ou fs_config_files a PRODUCT_PACKAGES no arquivo de configuração do dispositivo (por exemplo, $(TARGET_DEVICE_DIR)/device.mk).

Exemplo de substituição

Este exemplo mostra um patch para substituir o daemon system/bin/glgps e adicionar suporte ao bloqueio de ativação no diretório device/vendor/device. Lembre-se do seguinte:

  • Cada entrada de estrutura é o modo, o uid, o gid, os recursos e o nome. system/core/include/private/android_filesystem_config.h é incluído automaticamente para fornecer as #defines do manifesto (AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND).
  • A seção android_device_files[] inclui uma ação para suprimir o acesso a system/etc/fs_config_dirs quando não especificado, o que serve como uma proteção adicional do DAC para a falta de conteúdo para substituições de diretório. No entanto, essa é uma proteção fraca. Se alguém tem controle sobre /system, essa pessoa geralmente pode fazer o que quiser.
diff --git a/android_filesystem_config.h b/android_filesystem_config.h
new file mode 100644
index 0000000..874195f
--- /dev/null
+++ b/android_filesystem_config.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/* This file is used to define the properties of the file system
+** images generated by build tools (eg: mkbootfs) and
+** by the device side of adb.
+*/
+
+#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+/* static const struct fs_path_config android_device_dirs[] = { }; */
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const struct fs_path_config android_device_files[] = {
+  { 00755, AID_ROOT, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND),
"system/bin/glgps" },
+#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+  { 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },
+#endif
+};


diff --git a/device.mk b/device.mk
index 0c71d21..235c1a7 100644
--- a/device.mk
+++ b/device.mk
@@ -18,7 +18,8 @@ PRODUCT_PACKAGES := \
     libwpa_client \
     hostapd \
     wpa_supplicant \
-    wpa_supplicant.conf
+    wpa_supplicant.conf \
+    fs_config_files

 ifeq ($(TARGET_PREBUILT_KERNEL),)
 ifeq ($(USE_SVELTE_KERNEL), true)

Migrar sistemas de arquivos de versões anteriores

Ao migrar sistemas de arquivos do Android 5.x e versões anteriores, não esqueça que o Android 6.x

  • Remove algumas inclusões, estruturas e definições inline.
  • Requer uma referência a libcutils em vez de ser executado diretamente de system/core/include/private/android_filesystem_config.h. Executáveis particulares do fabricante do dispositivo que dependem de system/code/include/private_filesystem_config.h para estruturas de arquivo ou diretório ou fs_config precisam adicionar dependências de biblioteca libcutils.
  • Requer que cópias da ramificação privada do fabricante do dispositivo de system/core/include/private/android_filesystem_config.h com conteúdo extra nos destinos atuais sejam movidas para device/vendor/device/android_filesystem_config.h.
  • Reserva o direito de aplicar controles de acesso obrigatórios (MAC, na sigla em inglês) do SELinux a arquivos de configuração no sistema de destino. As implementações que incluem executáveis de destino personalizados usando fs_config() precisam garantir o acesso.