Control de acceso discrecional (DAC)

Los objetos y servicios del sistema de archivos que se agregan a la compilación suelen necesitar IDs únicos y separados, conocidos como IDs de Android (AIDs). Actualmente, muchos recursos, como archivos y servicios, usan AIDs centrales (definidos por Android) de forma innecesaria. En muchos casos, puedes usar AIDs de OEM (definidos por el OEM) en su lugar.

Las versiones anteriores de Android (Android 7.x y versiones anteriores) extendían el mecanismo de AID con un archivo android_filesystem_config.h específico del dispositivo para especificar las capacidades del sistema de archivos o los AID personalizados del OEM. Sin embargo, este sistema no era intuitivo, ya que no admitía el uso de nombres descriptivos para los AID del OEM, lo que requería que especificaras el valor numérico sin procesar para los campos de usuario y grupo sin una forma de asociar un nombre descriptivo con el AID numérico.

Las versiones más recientes de Android (Android 8.0 y versiones posteriores) admiten un nuevo método para extender las capacidades del sistema de archivos. Este nuevo método admite lo siguiente:

  • Múltiples ubicaciones de origen para los archivos de configuración (permite configuraciones de compilación extensibles).
  • Se realiza una verificación de integridad en tiempo de compilación de los valores de AID del OEM.
  • Generación de un encabezado AID de OEM personalizado que se puede usar en los archivos fuente según sea necesario.
  • Asociación de un nombre descriptivo con el valor de AID del OEM real. Admite argumentos de cadenas no numéricas para el usuario y el grupo, es decir, "foo" en lugar de "2901".

Entre las mejoras adicionales, se incluye la eliminación del array android_ids[] de system/core/libcutils/include/private/android_filesystem_config.h. Este array ahora existe en Bionic como un array generado completamente privado, con descriptores de acceso con getpwnam() y getgrnam(). (Esto tiene el efecto secundario de producir archivos binarios estables a medida que se modifican los AID principales). Para obtener herramientas y un archivo README con más detalles, consulta build/make/tools/fs_config.

Cómo agregar IDs de Android (AID)

Android 8.0 quitó el array android_ids[] del Proyecto de código abierto de Android (AOSP). En cambio, todos los nombres compatibles con AID se generan a partir del archivo de encabezado system/core/libcutils/include/private/android_filesystem_config.h cuando se genera el array android_ids[] de Bionic. La herramienta selecciona cualquier define que coincida con AID_*, y * se convierte en el nombre en minúsculas.

Por ejemplo, en private/android_filesystem_config.h:

#define AID_SYSTEM 1000

Se convierte en lo siguiente:

  • Nombre descriptivo: sistema
  • uid: 1000
  • gid: 1000

Para agregar un nuevo AID principal del AOSP, simplemente agrega #define al archivo de encabezado android_filesystem_config.h. El AID se genera durante la compilación y está disponible para las interfaces que usan argumentos de usuario y grupo. La herramienta valida que el nuevo AID no se encuentre dentro de los rangos de APP o OEM. También respeta los cambios en esos rangos y debería reconfigurarse automáticamente en caso de cambios o nuevos rangos reservados para OEM.

Configura los AIDs

Para habilitar el nuevo mecanismo de AID, configura TARGET_FS_CONFIG_GEN en el archivo BoardConfig.mk. Esta variable contiene una lista de archivos de configuración, lo que te permite agregar archivos según sea necesario.

Por convención, los archivos de configuración usan el nombre config.fs, pero, en la práctica, puedes usar cualquier nombre. Los archivos config.fs están en el formato ini de ConfigParser de Python y contienen una sección de capacidades (para configurar las capacidades del sistema de archivos) y una sección de AIDs (para configurar los AIDs del OEM).

Cómo configurar la sección de topes

La sección de capacidades admite la configuración de capacidades del sistema de archivos en objetos del sistema de archivos dentro de la compilación (el sistema de archivos en sí también debe admitir esta funcionalidad).

Dado que ejecutar un servicio estable como administrador en Android provoca una falla en el conjunto de pruebas de compatibilidad (CTS), los requisitos anteriores para conservar una capacidad mientras se ejecuta un proceso o servicio implicaban configurar capacidades y, luego, usar setuid/setgid para un AID adecuado para ejecutar. Con los límites, puedes omitir estos requisitos y dejar que el kernel lo haga por ti. Cuando el control se entrega a main(), tu proceso ya tiene las capacidades que necesita para que tu servicio pueda usar un usuario y un grupo no raíz (esta es la forma preferida de iniciar servicios con privilegios).

La sección de límites usa la siguiente sintaxis:

Sección Valor Definición
[path] Es la ruta de acceso del sistema de archivos que se configurará. Una ruta que termina en / se considera un directorio; de lo contrario, se considera un archivo.

Es un error especificar varias secciones con el mismo [path] en diferentes archivos. En las versiones de Python <= 3.2, el mismo archivo puede contener secciones que anulan la sección anterior. En Python 3.2, se establece en modo estricto.
mode Modo de archivo octal Modo de archivo octal válido de al menos 3 dígitos. Si se especifica 3, se le agrega un 0 como prefijo; de lo contrario, el modo se usa tal como está.
user AID_<user> Puede ser la C define para un AID válido o el nombre descriptivo (p.ej., tanto AID_RADIO como radio son aceptables). Para definir un AID personalizado, consulta la sección sobre cómo configurar el AID.
group AID_<group> Es igual al usuario.
caps cap* El nombre tal como se declaró en bionic/libc/kernel/uapi/linux/capability.h, sin el CAP_ inicial. Se permite el uso de mayúsculas y minúsculas combinadas. Las tapas también pueden ser sin procesar:
  • binario (0b0101)
  • octal (0455)
  • int (42)
  • hex (0xFF)
Separa varias tapas con espacios.

Para ver un ejemplo de uso, consulta Cómo usar las capacidades del sistema de archivos.

Configura la sección de AID

La sección AID contiene los AID del OEM y usa la siguiente sintaxis:

Sección Valor Definición
[AID_<name>] El <name> puede contener caracteres en mayúscula, números y guiones bajos. La versión en minúsculas se usa como el nombre descriptivo. El archivo de encabezado generado para la inclusión de código usa el AID_<name> exacto.

Es un error especificar varias secciones con el mismo AID_<name> (no distingue mayúsculas de minúsculas y tiene las mismas restricciones que [path]).

<name> debe comenzar con un nombre de partición para garantizar que no entre en conflicto con diferentes fuentes.
value <número> Es una cadena de números válida de estilo C (hexadecimal, octal, binaria y decimal).

Es un error especificar varias secciones con la misma opción de valor.

Las opciones de valor deben especificarse en el rango correspondiente a la partición utilizada en <name>. La lista de particiones válidas y sus rangos correspondientes se define en system/core/libcutils/include/private/android_filesystem_config.h. Las opciones son las siguientes:
  • Partición del proveedor
    • AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
    • AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
  • Partición del sistema
    • AID_SYSTEM_RESERVED_START(6000) - AID_SYSTEM_RESERVED_END(6499)
  • Partición ODM
    • AID_ODM_RESERVED_START(6500) - AID_ODM_RESERVED_END(6999)
  • Partición de producto
    • AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • Partición system_ext
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

Para ver ejemplos de uso, consulta Cómo definir nombres de AID de OEM y Cómo usar AID de OEM.

Ejemplos de uso

En los siguientes ejemplos, se detalla cómo definir y usar un AID del OEM, y cómo habilitar las capacidades del sistema de archivos. Los nombres de AID del OEM ([AID_nombre]) deben comenzar con un nombre de partición, como "vendor_", para garantizar que no entren en conflicto con futuros nombres de AOSP o con otras particiones.

Cómo definir nombres de AID de OEM

Para definir un AID del OEM, crea un archivo config.fs y establece el valor del AID. Por ejemplo, en device/x/y/config.fs, configura lo siguiente:

[AID_VENDOR_FOO]
value: 2900

Después de crear el archivo, establece la variable TARGET_FS_CONFIG_GEN y apunta a ella en BoardConfig.mk. Por ejemplo, en device/x/y/BoardConfig.mk, configura lo siguiente:

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

Ahora, el sistema en general puede consumir tu AID personalizado en una nueva compilación.

Usa AID de OEM

Para usar un AID del OEM, en tu código C, incluye oemaids_headers en tu Makefile asociado y agrega #include "generated_oem_aid.h". Luego, comienza a usar los identificadores declarados. Por ejemplo, en my_file.c, agrega lo siguiente:

#include "generated_oem_aid.h"


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

En el archivo Android.bp asociado, agrega lo siguiente:

header_libs: ["oemaids_headers"],

Si usas un archivo Android.mk, agrega lo siguiente:

LOCAL_HEADER_LIBRARIES := oemaids_headers

Usa nombres fáciles de usar

En Android 9, puedes usar el nombre descriptivo para cualquier interfaz que admita nombres de AID. Por ejemplo:

  • En un comando chown en some/init.rc, haz lo siguiente:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • En un service en some/init.rc, haz lo siguiente:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

Dado que la asignación interna del nombre descriptivo al UID se realiza mediante /vendor/etc/passwd y /vendor/etc/group, se debe activar la partición del proveedor.

Asocia nombres descriptivos

Android 9 incluye compatibilidad para asociar un nombre descriptivo con el valor real del AID del OEM. Puedes usar argumentos de cadena no numéricos para el usuario y el grupo, es decir, "vendor_foo" en lugar de "2901".

Cómo convertir de AID a nombres fáciles de usar

En el caso de los AID del OEM, Android 8.x requería el uso de oem_#### con getpwnam y funciones similares, así como en lugares que controlan las búsquedas con getpwnam (como las secuencias de comandos de init). En Android 9, puedes usar los amigos getpwnam y getgrnam en Bionic para convertir IDs de Android (AIDs) en nombres descriptivos y viceversa.

Usa las funciones del sistema de archivos

Para habilitar las funciones del sistema de archivos, crea una sección de capacidades en el archivo config.fs. Por ejemplo, en device/x/y/config.fs, agrega la siguiente sección:

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

Después de crear el archivo, configura TARGET_FS_CONFIG_GEN para que apunte a ese archivo en BoardConfig.mk. Por ejemplo, en device/x/y/BoardConfig.mk, configura lo siguiente:

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

Cuando se ejecuta el servicio vendor_foo, comienza con las capacidades CAP_SYS_ADMIN y CAP_SYS_NICE sin llamadas a setuid ni setgid. Además, la política de SELinux del servicio vendor_foo ya no necesita las capacidades setuid y setgid, y se puede borrar.

Cómo configurar anulaciones (Android 6.x a 7.x)

Android 6.0 reubicó fs_config y las definiciones de estructura asociadas (system/core/include/private/android_filesystem_config.h) en system/core/libcutils/fs_config.c, donde los archivos binarios instalados en /system/etc/fs_config_dirs y /system/etc/fs_config_files podían actualizarlos o anularlos. El uso de reglas independientes de coincidencia y análisis para directorios y archivos (que podrían usar expresiones glob adicionales) permitió que Android controlara directorios y archivos en dos tablas diferentes. Las definiciones de estructura en system/core/libcutils/fs_config.c no solo permitían la lectura en tiempo de ejecución de directorios y archivos, sino que el host podía usar los mismos archivos durante el tiempo de compilación para construir imágenes del sistema de archivos como ${OUT}/system/etc/fs_config_dirs y ${OUT}/system/etc/fs_config_files.

Si bien el método de anulación para extender el sistema de archivos se reemplazó por el sistema de configuración modular que se introdujo en Android 8.0, aún puedes usar el método anterior si lo deseas. En las siguientes secciones, se detalla cómo generar e incluir archivos de anulación, y cómo configurar el sistema de archivos.

Cómo generar archivos de anulación

Puedes generar los archivos binarios alineados /system/etc/fs_config_dirs y /system/etc/fs_config_files con la herramienta fs_config_generate en build/tools/fs_config. La herramienta usa una función de biblioteca libcutils (fs_config_generate()) para administrar los requisitos de la DAC en un búfer y define reglas para un archivo de inclusión para institucionalizar las reglas de la DAC.

Para usarlo, crea un archivo de inclusión en device/vendor/device/android_filesystem_config.h que actúe como anulación. El archivo debe usar el formato structure fs_path_config definido en system/core/include/private/android_filesystem_config.h con las siguientes inicializaciones de estructura para los símbolos de directorio y archivo:

  • Para los directorios, usa android_device_dirs[].
  • Para los archivos, usa android_device_files[].

Cuando no se usan android_device_dirs[] y android_device_files[], puedes definir NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS y NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES (consulta el ejemplo a continuación). También puedes especificar el archivo de anulación con TARGET_ANDROID_FILESYSTEM_CONFIG_H en la configuración de la placa, con un nombre base obligatorio de android_filesystem_config.h.

Cómo incluir archivos de anulación

Para incluir archivos, asegúrate de que PRODUCT_PACKAGES incluya fs_config_dirs o fs_config_files para que pueda instalarlos en /system/etc/fs_config_dirs y /system/etc/fs_config_files, respectivamente. El sistema de compilación busca android_filesystem_config.h personalizado en $(TARGET_DEVICE_DIR), donde existe BoardConfig.mk. Si este archivo existe en otro lugar, configura la variable de configuración de la placa TARGET_ANDROID_FILESYSTEM_CONFIG_H para que apunte a esa ubicación.

Configura el sistema de archivos

Para configurar el sistema de archivos en Android 6.0 y versiones posteriores, haz lo siguiente:

  1. Crea el archivo $(TARGET_DEVICE_DIR)/android_filesystem_config.h.
  2. Agrega fs_config_dirs o fs_config_files a PRODUCT_PACKAGES en el archivo de configuración de la placa (p.ej., $(TARGET_DEVICE_DIR)/device.mk).

Ejemplo de anulación

En este ejemplo, se muestra un parche para anular el daemon system/bin/glgps y agregar compatibilidad con el bloqueo de activación en el directorio device/vendor/device. Ten en cuenta lo siguiente:

  • Cada entrada de estructura es el modo, el UID, el GID, las capacidades y el nombre. system/core/include/private/android_filesystem_config.h se incluye automáticamente para proporcionar las definiciones de preprocesador del manifiesto (AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND).
  • La sección android_device_files[] incluye una acción para suprimir el acceso a system/etc/fs_config_dirs cuando no se especifica, lo que sirve como protección adicional de DAC por falta de contenido para las anulaciones de directorios. Sin embargo, esta es una protección débil. Si alguien tiene control sobre /system, por lo general, puede hacer lo que quiera.
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)

Migra sistemas de archivos desde versiones anteriores

Cuando migres sistemas de archivos desde Android 5.x y versiones anteriores, ten en cuenta que Android 6.x

  • Se quitan algunas inclusiones, estructuras y definiciones intercaladas.
  • Requiere una referencia a libcutils en lugar de ejecutarse directamente desde system/core/include/private/android_filesystem_config.h. Los ejecutables privados del fabricante del dispositivo que dependen de system/code/include/private_filesystem_config.h para las estructuras de archivos o directorios, o de fs_config, deben agregar dependencias de la biblioteca libcutils.
  • Se requieren copias de la rama privada del fabricante del dispositivo de system/core/include/private/android_filesystem_config.h con contenido adicional en los destinos existentes para migrar a device/vendor/device/android_filesystem_config.h.
  • Se reserva el derecho de aplicar controles de acceso obligatorio (MAC) de SELinux a los archivos de configuración del sistema de destino. Las implementaciones que incluyen ejecutables de destino personalizados con fs_config() deben garantizar el acceso.