
LID — Linux Integrity Drift: bypass di AppArmor tramite riscrittura dei pathname via eBPF. Manipolazione degli argomenti delle syscall pre-LSM con impronta di audit pari a zero. "Linux sta morendo"
```
██╗ ██╗██████╗
██║ ██║██╔══██╗
██║ ██║██║ ██║
██║ ██║██║ ██║
███████╗██║██████╔╝
╚══════╝╚═╝╚═════╝
```
— "Linux is Dying" —
Scoperta sistematica dei percorsi del kernel che aggirano le garanzie di sicurezza LSM
Il cancello non è mai stato forzato. È stato semplicemente aggirato.
Il framework Linux Security Module ha una garanzia fondamentale che regge da 20+ anni:
I moduli di sicurezza possono solo aggiungere restrizioni. Non possono mai rimuoverle.
Questa garanzia è corretta. LID non la infrange.
LID trova percorsi del kernel che bypassano completamente gli hook LSM — sottosistemi che eseguono operazioni sensibili per la sicurezza senza consultare il framework LSM. Il controllo di sicurezza è corretto. Il problema è che il kernel non chiede mai.
Ogni scoperta ha due dimensioni distinte che non vanno confuse:
Il punto cieco architetturale. La domanda non è "un attaccante può sfruttare questo?", ma:
Se un'operazione sensibile per la sicurezza avviene e il livello di enforcement non la valuta nemmeno, hai un divario di visibilità — indipendentemente dal fatto che un attaccante possa abusarne praticamente oggi. Questo conta per conformità, forensics e assunzioni di difesa in profondità.
La domanda sulla sfruttabilità nel mondo reale:
Queste due cose sono diverse. Una scoperta può essere un divario di visibilità critico (il tuo monitoring è cieco) senza essere un'escalation di privilegi pratica (l'attaccante ha già root). Al contrario, una scoperta può essere un percorso di escalation diretto con prerequisiti minimi.
| Finding | Divario di visibilità | Escalation pratica |
|---|---|---|
| LID-001 | Critico — AppArmor non vede nulla, log di audit vuoto, zero traccia forense | Limitato — richiede root o CAP_BPF+CAP_PERFMON (già privilegiato). Non è un'escalation di privilegi. Impatto: evasione delle policy + cecità dell'audit. |
| LID-002 | Alto — security_file_receive() non scatta mai, il trasferimento di fd è invisibile a tutti gli LSM | Alto — funziona da userspace non privilegiato tramite io_uring. Attraversa il confine di enforcement LSM senza alcun privilegio. |
| LID-003 | Alto — security_sb_mount() bypassato, la policy di mount di AppArmor è codice morto | Medio — richiede accesso al mount namespace (CAP_SYS_ADMIN nella user ns). Disponibile in molte configurazioni container. |
| LID-004 | Critico — AppArmor non vede nulla, zero hook BPF (0/9), nessuna traccia di audit per qualsiasi operazione con BPF token | Medio — richiede delega bpffs da parte dell'host + CAP_BPF nella user namespace. Disponibile nei runtime container con delega BPF (LXD/Incus). |
| LID-005 | Medio — i classificatori tc egress sull'interfaccia container non valutano mai il traffico AF_XDP | Limitato — bypassa tc egress su eth0 del container (verificato). Cilium NON bypassato — applica il controllo sull'ingresso veth lato nodo + verifica IP sorgente (testato). Impatto limitato a setup Docker puri con filtro egress solo tc. |
Ogni scoperta ha requisiti specifici di kernel/config/privilegi. Se il tuo ambiente non corrisponde, la scoperta non si riprodurrà.
| Condizione | Richiesta | Note |
|---|---|---|
| Versione kernel | 5.x+ | Testato su 5.15, 6.1, 6.6, 6.8 |
CONFIG_BPF_SYSCALL | =y | Default su tutte le principali distro |
CONFIG_BPF_KPROBE_OVERRIDE | =y | Ubuntu/Debian lo abilitano, RHEL no |
CONFIG_SECURITY_APPARMOR | =y | LSM target deve essere AppArmor |
| Profilo AppArmor | Enforcing, regola di deny sul path target | Funziona con qualsiasi regola di deny basata su path |
| Privilegi | root o CAP_BPF + CAP_PERFMON | Non può essere eseguito senza privilegi |
kernel.lockdown | none o integrity | La modalità confidentiality blocca l'attach dei kprobe |
kernel.unprivileged_bpf_disabled | Irrilevante | Richiede comunque CAP_BPF |
fs.protected_hardlinks | 0 per link cross-user | 1 (default) consente comunque hard link stesso-utente |
| SELinux invece di AppArmor | Non funziona | SELinux è basato su inode, non su pathname |
| Condizione | Richiesta | Note |
|---|---|---|
| Versione kernel | 6.0+ | IORING_MSG_SEND_FD aggiunto in 6.0 |
CONFIG_IO_URING | =y | Default su tutte le principali distro |
| Privilegi | Nessuno | Funziona da userspace non privilegiato |
Sysctl io_uring_disabled | 0 (default) | 2 blocca i non privilegiati, 1 blocca tutti |
| LSM target | Qualsiasi (SELinux, AppArmor, Smack) | security_file_receive() è un hook LSM generico |
kernel.lockdown | Irrilevante | Nessun BPF coinvolto |
| Condizione | Richiesta | Note |
|---|---|---|
| Versione kernel | 6.9+ | BPF token introdotto in 6.9 |
CONFIG_BPF_SYSCALL | =y | Default su tutte le principali distro |
CONFIG_SECURITY_APPARMOR | =y | Default Ubuntu/Debian |
| bpffs con delega | Sì | L'host deve montare con opzioni delegate_* |
| Privilegi | CAP_BPF nella user namespace | Banalmente disponibile per root userns |
| SELinux invece di AppArmor | Non interessato | SELinux implementa tutti i 9 hook BPF |
| Condizione | Richiesta | Note |
|---|---|---|
| Versione kernel | 5.2+ | fsopen/fsmount introdotti in 5.2 |
CONFIG_SECURITY_APPARMOR | =y | Solo AppArmor è interessato |
| Privilegi | CAP_SYS_ADMIN nella user namespace | Disponibile con unshare -m |
| SELinux invece di AppArmor | Non funziona | SELinux implementa security_sb_kern_mount() |
| Runtime container | Dipende dal filtro seccomp | Il seccomp default di Docker blocca fsopen — Podman/LXC potrebbero non bloccarlo |
| Condizione | Richiesta | Note |
|---|---|---|
| Versione kernel | 4.18+ | AF_XDP introdotto in 4.18 |
CONFIG_XDP_SOCKETS | =y | Default su tutte le principali distro |
| Privilegi | Solo CAP_NET_RAW | Default in Docker, pod Kubernetes |
| Runtime container | Docker, K8s, LXC | Set di capability predefinito |
| Policy di rete basata su tc | Sì | Cilium eBPF, Calico, tc u32/flower |