CVE-2026-31431 (Copy Fail): come Appbox l'ha mitigata
Una grave falla del kernel Linux, CVE-2026-31431, è stata divulgata la scorsa settimana. Ecco come Appbox l'ha mitigata e ha distribuito la correzione del kernel Debian.
CVE-2026-31431 (Copy Fail) - come l'abbiamo mitigata
La scorsa settimana è stata divulgata una grave escalation di privilegi locale nel kernel Linux: CVE-2026-31431, soprannominata "Copy Fail". Colpisce un'ampia gamma di versioni del kernel nelle distribuzioni Linux moderne e un exploit pubblico è comparso rapidamente dopo la divulgazione.
Voglio essere trasparente su cosa è successo, cosa significa per Appbox e cosa abbiamo fatto al riguardo. Versione breve: grazie al modo in cui sono costruiti i nostri container, le app eseguite con il remapping degli user namespace erano già protette dal trasformare questo problema in root sull'host anche prima della distribuzione dei kernel corretti. Ieri (4 maggio 2026) abbiamo inoltre eseguito una manutenzione di emergenza per aggiornare ogni server a un kernel corretto, quindi il bug è ora completamente rimosso dalla nostra flotta.
Che cos'è "Copy Fail"?
CVE-2026-31431 è una falla nell'API crittografica AF_ALG del kernel. Effettuando il binding a uno specifico cifrario (authencesn(hmac(sha256),cbc(aes))) e abusando del modo in cui il kernel inserisce pagine in uno scratch buffer, un utente locale non privilegiato può scrivere blocchi arbitrari di 4 byte direttamente nella page cache di file che non dovrebbe avere il permesso di modificare, inclusi binari SUID come /usr/bin/su.
Una volta che la copia di su nella page cache viene sovrascritta con un piccolo ELF malevolo, l'invocazione successiva esegue il codice dell'attaccante come UID 0. Partita chiusa per l'host.
Per i dettagli tecnici più approfonditi (disassemblaggio dello shellcode, trace delle syscall, tutto il resto), il writeup di Andrea Veri è eccellente: CVE-2026-31431: Copy Fail vs. rootless containers. Ha anche dimostrato, con eBPF e prove di uid_map, esattamente ciò di cui parleremo ora: gli user namespace neutralizzano questo exploit.
Perché le app Appbox erano già mitigate
L'exploit si basa sul fatto che setuid(0) conceda davvero root sull'host. In un container eseguito con user namespace abilitati, non è questo che accade.
Gli user namespace mappano lo spazio UID del container su un diverso intervallo UID (non privilegiato) sull'host. Quindi, quando l'exploit ha successo dentro il container e setuid(0) restituisce esito positivo, la shell "root" risultante viene mappata a un normale utente host non privilegiato, non a root reale. Lo shellcode viene eseguito, il prompt cambia in #, ma sull'host:
podman 27943 0.0 0.0 2984 2028 pts/1 S+ 22:15 0:00 sleep 100
Tutto qui. Nessun accesso ai file dell'host, nessun /etc/shadow, nessun root sull'host. Il confine del namespace del container impedisce che questo diventi una fuga verso root sull'host.
A livello di piattaforma, ogni Appbox ottiene il proprio daemon Docker avviato con il remapping degli user namespace abilitato. In pseudocodice, assomiglia più o meno a questo:
start_docker_daemon(
userns_remap = appbox_id,
container_namespace = appbox_id
)Questa mappatura è supportata da un intervallo UID/GID subordinato dedicato sull'host:
write "/etc/subuid" -> "<appbox-id>:<host-subuid-start>:65536"
write "/etc/subgid" -> "<appbox-id>:<host-subgid-start>:65536"In più, le definizioni delle app possono ancora sovrascrivere esplicitamente UsernsMode quando un'app richiede una gestione speciale:
container_config = {
userns_mode: app.userns_mode,
network_mode: app.network_mode,
...
}Quindi il modo corretto di descriverlo è: il remapping degli user namespace fa parte dell'impostazione predefinita della piattaforma e le eccezioni per singola app sono esplicite. Esiste un numero ridotto di app che richiede impostazioni diverse perché espone funzionalità che necessitano di capability aggiuntive, e quei casi vengono gestiti separatamente.
In altre parole: per le app eseguite con la normale configurazione rimappata, Copy Fail non poteva trasformare una compromissione del container in root sull'host.
Cosa volevamo comunque correggere
Gli user namespace fermano la fuga dall'host, ma non fanno sparire il bug dentro il container. Un attaccante poteva comunque escalare a "root del container" all'interno del perimetro dell'app, il che, pur rimanendo contenuto, è comunque una cattiva situazione operativa. Il kernel stesso era vulnerabile e volevamo eliminare quel problema.
Appena abbiamo saputo del bug, abbiamo iniziato immediatamente a valutare la nostra esposizione. Anche se il remapping degli user namespace bloccava già il lato "host escape" del problema per la nostra normale configurazione delle app, volevamo comunque rimuovere il bug sottostante del kernel il più rapidamente possibile.
Cosa abbiamo fatto ieri
Domenica sera abbiamo pianificato una manutenzione di emergenza per lunedì 4 maggio 2026, la prima finestra utile in cui potevamo distribuire un aggiornamento del kernel su tutta la flotta.
Durante la finestra:
- Ogni host è stato aggiornato usando i pacchetti ufficiali del kernel Debian contenenti la correzione per "Copy Fail".
- L'obiettivo era semplice: rimuovere completamente il percorso vulnerabile del kernel, non limitarci a fare affidamento sull'isolamento dei namespace già esistente.
La manutenzione è completata. Ogni host Appbox ora esegue un kernel corretto.
Cosa significa per te
- Non hai dovuto fare nulla. Le tue app hanno continuato a funzionare e gli eventuali brevi disservizi durante la finestra di manutenzione sono stati l'unico effetto visibile ai clienti.
- Anche prima della patch di ieri, il remapping degli user namespace significava che questo bug non poteva trasformare una normale compromissione di un'app in root sull'host. È esattamente il tipo di scenario per cui esiste questo modello di isolamento.
- Da qui in avanti, la nostra politica non cambia: gli user namespace restano attivi di default e le pochissime eccezioni passano attraverso una revisione di sicurezza aggiuntiva.
Il quadro generale
Questa è una di quelle CVE in cui il titolo ("escalation di privilegi locale, exploit pubblico, ogni kernel moderno colpito") suona catastrofico, e per molti ambienti multi-tenant condivisi lo è stato davvero. Il motivo per cui non è stato catastrofico per noi è lo stesso per cui anni fa abbiamo preso decisioni architetturali che a volte ci costano un po' di compatibilità: eseguiamo le app con il principio del privilegio minimo integrato nel livello container, non aggiunto dopo.
La difesa in profondità funziona davvero. Bug al livello kernel? Il livello namespace lo ha intercettato. Bug al livello namespace? La rimozione delle capability e seccomp ne intercettano la maggior parte. Non fingiamo che un singolo livello sia perfetto; ci assicuriamo solo che ce ne sia sempre un altro.
Se hai domande su questo o su come sono configurate le tue app specifiche, contattaci.
Hai domande? Contattaci a support@appbox.co o apri un ticket su billing.appbox.co.
