
LID — Linux Integrity Drift: Evadiendo AppArmor mediante la reescritura de rutas con eBPF. Manipulación de argumentos de syscalls previa a LSM con cero huella de auditoría. "Linux está muriendo"
```
██╗ ██╗██████╗
██║ ██║██╔══██╗
██║ ██║██║ ██║
██║ ██║██║ ██║
███████╗██║██████╔╝
╚══════╝╚═╝╚═════╝
```
— "Linux está muriendo" —
Descubrimiento sistemático de rutas de código del kernel que omiten las garantías de seguridad de LSM
La puerta nunca fue derribada. Simplemente la rodearon.
El framework de módulos de seguridad de Linux tiene una garantía central que se ha mantenido durante más de 20 años:
Los módulos de seguridad solo pueden añadir restricciones. Nunca pueden eliminarlas.
Esta garantía es correcta. LID no la rompe.
LID encuentra rutas de código del kernel que omiten por completo los hooks de LSM — subsistemas que realizan operaciones sensibles para la seguridad sin consultar el framework LSM. La comprobación de seguridad es correcta. El problema es que el kernel nunca pregunta.
Cada hallazgo tiene dos dimensiones distintas que no deben confundirse:
El punto ciego arquitectónico. La pregunta no es "¿puede un atacante explotar esto?", sino:
Si se produce una operación sensible para la seguridad y la capa de aplicación de políticas ni siquiera la evalúa, tienes una brecha de visibilidad — independientemente de si un atacante puede abusar de ella en la práctica hoy. Esto importa para cumplimiento, forense digital y supuestos de defensa en profundidad.
La pregunta de explotabilidad en el mundo real:
Estas dos cosas son diferentes. Un hallazgo puede ser una brecha de visibilidad crítica (tu monitoreo está ciego) sin ser una escalada de privilegios práctica (el atacante ya necesita root). A la inversa, un hallazgo puede ser una ruta de escalada directa con requisitos previos mínimos.
| Hallazgo | Brecha de visibilidad | Escalada práctica |
|---|---|---|
| LID-001 | Crítica — AppArmor no ve nada, log de auditoría vacío, cero rastro forense | Limitada — requiere root o CAP_BPF+CAP_PERFMON (ya privilegiado). No es una escalada de privilegios. Impacto: evasión de políticas + ceguera de auditoría. |
| LID-002 | Alta — security_file_receive() nunca se dispara, la transferencia de fd invisible para todos los LSM | Alta — funciona desde el espacio de usuario sin privilegios mediante io_uring. Cruza el límite de aplicación de LSM sin ningún privilegio. |
| LID-003 | Alta — security_sb_mount() evadido, la política de montaje de AppArmor es código muerto | Media — requiere acceso al espacio de nombres de montaje (CAP_SYS_ADMIN en user ns). Disponible en muchas configuraciones de contenedores. |
| LID-004 | Crítica — AppArmor no ve nada, cero hooks BPF (0/9), sin rastro de auditoría para ninguna operación de token BPF | Media — requiere delegación de bpffs por parte del host + CAP_BPF en el espacio de nombres de usuario. Disponible en runtimes de contenedores con delegación BPF (LXD/Incus). |
| LID-005 | Media — los clasificadores de egress tc en la interfaz del contenedor nunca evalúan el tráfico AF_XDP | Limitada — evita el egress tc en eth0 del contenedor (verificado). Cilium NO es evadido — aplica control en el ingress veth del lado del nodo + verificación de IP de origen (probado). Impacto limitado a configuraciones de Docker simple con filtrado de egress solo con tc. |
Cada hallazgo tiene requisitos específicos de kernel/config/privilegios. Si tu entorno no coincide, el hallazgo no se reproducirá.
| Condición | Requerido | Notas |
|---|---|---|
| Versión del kernel | 5.x+ | Probado en 5.15, 6.1, 6.6, 6.8 |
CONFIG_BPF_SYSCALL | =y | Predeterminado en todas las distros principales |
CONFIG_BPF_KPROBE_OVERRIDE | =y | Ubuntu/Debian lo habilitan, RHEL no |
CONFIG_SECURITY_APPARMOR | =y | El LSM objetivo debe ser AppArmor |
| Perfil de AppArmor | Enforcing, regla de denegación en la ruta objetivo | Funciona con cualquier regla de denegación basada en rutas |
| Privilegios | root o CAP_BPF + CAP_PERFMON | No puede ejecutarse sin privilegios |
kernel.lockdown | none o integrity | El modo confidentiality impide adjuntar kprobes |
kernel.unprivileged_bpf_disabled | Irrelevante | Requiere CAP_BPF de todos modos |
fs.protected_hardlinks | 0 para enlaces entre usuarios | 1 (predeterminado) todavía permite enlaces duros del mismo usuario |
| SELinux en lugar de AppArmor | No funciona | SELinux se basa en inodos, no en nombres de ruta |
| Condición | Requerido | Notas |
|---|---|---|
| Versión del kernel | 6.0+ | IORING_MSG_SEND_FD añadido en 6.0 |
CONFIG_IO_URING | =y | Predeterminado en todas las distros principales |
| Privilegios | Ninguno | Funciona desde el espacio de usuario sin privilegios |
sysctl io_uring_disabled | 0 (predeterminado) | 2 bloquea a los no privilegiados, 1 bloquea a todos |
| LSM objetivo | Cualquiera (SELinux, AppArmor, Smack) | security_file_receive() es un hook LSM genérico |
kernel.lockdown | Irrelevante | No involucra BPF |
| Condición | Requerido | Notas |
|---|---|---|
| Versión del kernel | 6.9+ | El token BPF se introdujo en 6.9 |
CONFIG_BPF_SYSCALL | =y | Predeterminado en todas las distros principales |
CONFIG_SECURITY_APPARMOR | =y | Predeterminado en Ubuntu/Debian |
| bpffs con delegación | Sí | El host debe montar con opciones delegate_* |
| Privilegios | CAP_BPF en el espacio de nombres de usuario | Disponible trivialmente para root de userns |
| SELinux en lugar de AppArmor | No afectado | SELinux implementa los 9 hooks BPF |
| Condición | Requerido | Notas |
|---|---|---|
| Versión del kernel | 5.2+ | fsopen/fsmount introducidos en 5.2 |
CONFIG_SECURITY_APPARMOR | =y | Solo AppArmor se ve afectado |
| Privilegios | CAP_SYS_ADMIN en el espacio de nombres de usuario | Disponible con unshare -m |
| SELinux en lugar de AppArmor | No funciona | SELinux implementa security_sb_kern_mount() |
| Runtime de contenedores | Depende del filtro seccomp | El seccomp predeterminado de Docker bloquea fsopen — Podman/LXC puede que no |