Conceptos de SELinux

Revise esta página para familiarizarse con los conceptos de SELinux.

Control de acceso obligatorio

Security Enhanced Linux (SELinux) es un sistema de control de acceso obligatorio (MAC) para el sistema operativo Linux. Como sistema MAC, se diferencia del conocido sistema de control de acceso discrecional (DAC) de Linux. En un sistema DAC, existe un concepto de propiedad, según el cual el propietario de un recurso en particular controla los permisos de acceso asociados con él. Esto generalmente es poco claro y está sujeto a una escalada de privilegios no intencionada. Sin embargo, un sistema MAC consulta a una autoridad central para tomar una decisión sobre todos los intentos de acceso.

SELinux se ha implementado como parte del marco del Módulo de seguridad de Linux (LSM), que reconoce varios objetos del kernel y las acciones confidenciales realizadas en ellos. En el punto en el que se realizaría cada una de estas acciones, se llama a una función de enlace LSM para determinar si la acción debe permitirse o no en función de la información almacenada en un objeto de seguridad opaco. SELinux proporciona una implementación para estos ganchos y gestión de estos objetos de seguridad, que se combinan con su propia política, para determinar las decisiones de acceso.

Junto con otras medidas de seguridad de Android, la política de control de acceso de Android limita en gran medida el daño potencial de las máquinas y cuentas comprometidas. El uso de herramientas como los controles de acceso obligatorios y discrecionales de Android le brinda una estructura para garantizar que su software se ejecute solo en el nivel de privilegio mínimo. Esto mitiga los efectos de los ataques y reduce la probabilidad de que procesos erróneos sobrescriban o incluso transmitan datos.

En Android 4.3 y superiores, SELinux proporciona un control de acceso obligatorio (MAC) sobre los entornos tradicionales de control de acceso discrecional (DAC). Por ejemplo, el software normalmente debe ejecutarse como cuenta de usuario raíz para escribir en dispositivos de bloques sin formato. En un entorno Linux tradicional basado en DAC, si el usuario root se ve comprometido, ese usuario puede escribir en cada dispositivo de bloque sin formato. Sin embargo, SELinux se puede utilizar para etiquetar estos dispositivos de modo que el proceso al que se le asignó el privilegio de raíz pueda escribir solo en aquellos especificados en la política asociada. De esta manera, el proceso no puede sobrescribir datos ni configuraciones del sistema fuera del dispositivo de bloque sin formato específico.

Consulte Casos de uso para obtener más ejemplos de amenazas y formas de abordarlas con SELinux.

Niveles de aplicación

SELinux se puede implementar en distintos modos:

  • Permisivo : la política de seguridad de SELinux no se aplica, solo se registra.
  • Aplicación : la política de seguridad se aplica y se registra. Los fallos aparecen como errores EPERM.

Esta elección es binaria y determina si su política toma medidas o simplemente le permite recopilar fallas potenciales. El permisivo es especialmente útil durante la implementación.

Tipos, atributos y reglas

Android depende del componente Type Enforcement (TE) de SELinux para su política. Significa que todos los objetos (como archivos, procesos o sockets) tienen un tipo asociado. Por ejemplo, de forma predeterminada, una aplicación tendrá el tipo untrusted_app . Para un proceso, su tipo también se conoce como dominio . Es posible anotar un tipo con uno o varios atributos . Los atributos son útiles para hacer referencia a varios tipos al mismo tiempo.

Los objetos se asignan a clases (por ejemplo, un archivo, un directorio, un enlace simbólico, un socket) y los diferentes tipos de acceso para cada clase están representados por permisos . Por ejemplo, el permiso open existe para el file de clase. Si bien los tipos y atributos se actualizan periódicamente como parte de la política SELinux de Android, los permisos y las clases se definen estáticamente y rara vez se actualizan como parte de una nueva versión de Linux.

Una regla de política tiene la siguiente forma: allow source target : class permissions ; dónde:

  • Fuente : el tipo (o atributo) del tema de la regla. ¿Quién solicita el acceso?
  • Destino : el tipo (o atributo) del objeto. ¿A qué se solicita el acceso?
  • Clase : el tipo de objeto (por ejemplo, archivo, socket) al que se accede.
  • Permisos : la operación (o conjunto de operaciones) (por ejemplo, lectura, escritura) que se está realizando.

Un ejemplo de regla es:

allow untrusted_app app_data_file:file { read write };

Esto dice que las aplicaciones pueden leer y escribir archivos etiquetados app_data_file . Existen otros tipos de aplicaciones. Por ejemplo, isolated_app se utiliza para servicios de aplicaciones con isolatedProcess=true en su manifiesto. En lugar de repetir la regla para ambos tipos, Android usa un atributo llamado appdomain para todos los tipos que cubren aplicaciones:

# Associate the attribute appdomain with the type untrusted_app.
typeattribute untrusted_app, appdomain;

# Associate the attribute appdomain with the type isolated_app.
typeattribute isolated_app, appdomain;

allow appdomain app_data_file:file { read write };

Cuando se escribe una regla que especifica un nombre de atributo, ese nombre se expande automáticamente a la lista de dominios o tipos asociados con el atributo. Algunos atributos notables son:

  • domain : atributo asociado con todos los tipos de procesos,
  • file_type : atributo asociado con todos los tipos de archivos.

macros

Para el acceso a archivos en particular, hay muchos tipos de permisos a considerar. Por ejemplo, el permiso read no es suficiente para abrir el archivo o llamar a stat . Para simplificar la definición de reglas, Android proporciona un conjunto de macros para manejar los casos más comunes. Por ejemplo, para incluir los permisos que faltan, como open , la regla anterior podría reescribirse como:

allow appdomain app_data_file:file rw_file_perms;

Consulte los archivos global_macros y te_macros para obtener más ejemplos de macros útiles. Se deben utilizar macros siempre que sea posible para ayudar a reducir la probabilidad de errores debidos a denegaciones de permisos relacionados.

Una vez definido un tipo, es necesario asociarlo con el archivo o proceso que representa. Consulte Implementación de SELinux para obtener más detalles sobre cómo se realiza esta asociación. Para obtener más información sobre las reglas, consulte SELinux Notebook .

Contexto y categorías de seguridad

Al depurar políticas de SELinux o etiquetar archivos (a través de file_contexts o al ingresar ls -Z ), es posible que se encuentre con un contexto de seguridad (también conocido como etiqueta ). Por ejemplo: u:r:untrusted_app:s0:c15,c256,c513,c768 . Un contexto de seguridad tiene el formato: user:role:type:sensitivity[:categories] . Por lo general, puede ignorar los campos user , role y sensitivity de un contexto (consulte Especificidad ). El campo type se explica en la sección anterior. categories son parte del soporte de seguridad multinivel (MLS) en SELinux. Desde Android S, las categorías se utilizan para:

  • Aislar los datos de la aplicación del acceso de otra aplicación,
  • Aísle los datos de la aplicación de un usuario físico a otro.

Especificidad

Android no utiliza todas las funciones proporcionadas por SELinux. Al leer documentación externa, tenga en cuenta estos puntos:

  • La mayoría de las políticas en AOSP se definen utilizando el lenguaje de políticas del kernel. Existen algunas excepciones para el uso del lenguaje intermedio común (CIL).
  • No se utilizan usuarios de SELinux. El único usuario definido es u . Cuando es necesario, los usuarios físicos se representan mediante el campo de categorías de un contexto de seguridad.
  • No se utilizan roles de SELinux ni control de acceso basado en roles (RBAC). Se definen y utilizan dos roles predeterminados: r para sujetos y object_r para objetos.
  • No se utilizan sensibilidades de SELinux. La sensibilidad s0 predeterminada siempre está configurada.
  • Los booleanos de SELinux no se utilizan. Una vez que se crea la política para un dispositivo, no depende del estado del dispositivo. Esto simplifica la auditoría y depuración de políticas.