
# Blocker BPF LSM per CVE-2026-31431 (Copy Fail) - remediation a zero-reboot per OpenShift 4
CVE-2026-31431 ("Copy Fail") è una vulnerabilità di escalation dei privilegi nel kernel Linux
nell'interfaccia crittografica algif_aead. Un attaccante utilizza socket AF_ALG con
l'algoritmo authencesn e splice() per corrompere file arbitrari nella cache delle pagine
del kernel — inclusi binari setuid come /usr/bin/su.
Questo documento fornisce una mitigazione senza riavvio utilizzando un DaemonSet BPF LSM
che blocca tutti i bind AEAD AF_ALG — il sottosistema sfruttato da Copy Fail. Questo
previene bypass tramite annidamento di template crittografici (es. pcrypt(authencesn(...))).
Altri utilizzi di AF_ALG (hash, skcipher) non sono influenzati. Testato end-to-end su tre
cluster OCP 4.22 separati.
# 1. Verificare che BPF LSM sia abilitato (RHEL CoreOS 9.8 lo ha per impostazione predefinita)
oc debug node/<qualsiasi-nodo> -- chroot /host cat /sys/kernel/security/lsm
# Deve contenere "bpf"
# 2. Distribuire il namespace e concedere la SCC privilegiata
oc apply -f daemonset.yaml
# 3. I pod del DaemonSet si avvieranno automaticamente su tutti i nodi
# 4. Verifica
oc get pods -n block-copyfail # Tutti i nodi dovrebbero mostrare Running
oc logs -n block-copyfail -l app=block-copyfail
# Previsto: "block-copyfail: blocker active — all AF_ALG AEAD binds blocked"
Nessun riavvio. Nessun drain dei nodi. Nessun riavvio dei pod. La protezione è immediata e copre tutti i processi su tutti i nodi (copertura al 100%).
L'exploit combina tre funzionalità del kernel:
socket(AF_ALG, SOCK_SEQPACKET, 0)authencesn(hmac(sha256),cbc(aes)), uno specifico
algoritmo di crittografia autenticataL'attaccante corrompe /usr/bin/su nella cache delle pagine (senza accesso in scrittura al
file), quindi lo esegue per ottenere root.
Crea un nuovo namespace cve-2026-31431-test sul tuo cluster ed esegui lo script di test applicando i manifest nella directory test:
oc apply -f test
Controlla i risultati:
oc wait pod/cve-test -n cve-2026-31431-test \
--for=jsonpath='{.status.phase}'=Succeeded --timeout=120s
oc -n cve-2026-31431-test logs -l app=cve-2026-31431-test
Su un cluster vulnerabile vedrai:
=== CVE-2026-31431 Vulnerability Test ===
Target: /usr/bin/su
Original SHA256: 8969560ae8e6e21c6184c1451f59418822ee69dd5d946d71987b55236bbc0feb
Attempting splice + AF_ALG page-cache corruption (160 bytes in 40 chunks)...
After SHA256: 30b0f5b5a054c4df65b48ca792863bf7054b4d793f15f57163792ba6c2b151ae
PAGE CACHE CORRUPTION: YES - /usr/bin/su was modified in the page cache
Attempting to execute corrupted /usr/bin/su ...
exit code: 0
RESULT: PARTIALLY MITIGATED
Page-cache corruption succeeded (kernel is vulnerable)
Privilege escalation blocked (allowPrivilegeEscalation=false)
oc delete namespace cve-2026-31431-test
L'approccio BPF LSM aggancia socket_bind a livello di kernel e blocca tutti
i bind AEAD AF_ALG indipendentemente dall'annidamento dei template. Si basa su
block-copyfail, riscritto in C
con libbpf per la distribuzione su OCP.
BPF LSM deve essere abilitato. RHEL CoreOS 9.8 (OCP 4.22) lo ha abilitato per impostazione predefinita. Verifica con:
oc debug node/<qualsiasi-nodo> -- chroot /host cat /sys/kernel/security/lsm
L'output previsto include bpf:
lockdown,capability,landlock,yama,selinux,bpf
Se bpf non è presente, è necessario un MachineConfig una tantum (questo è
l'unico scenario che richiede un riavvio):
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
labels:
machineconfiguration.openshift.io/role: worker
name: 99-enable-bpf-lsm
spec:
kernelArguments:
- lsm=lockdown,capability,selinux,bpf
Crea un nuovo namespace block-copyfail, concedi la SCC e distribuisci il DaemonSet applicando il manifest daemonset.yaml.
La SCC privilegiata deve essere concessa prima della creazione dei pod del DaemonSet,
altrimenti la creazione dei pod fallirà con errori di validazione SCC.
oc apply -f daemonset.yaml
oc get pods -n block-copyfail -o wide
Previsto: un pod per nodo, tutti Running:
NAME READY STATUS AGE NODE
block-copyfail-2jhzf 1/1 Running 34s ci-...-master-2
block-copyfail-4dfq7 1/1 Running 34s ci-...-master-1
block-copyfail-c2ts8 1/1 Running 34s ci-...-worker-c
block-copyfail-ctblk 1/1 Running 34s ci-...-worker-a
block-copyfail-m26sx 1/1 Running 34s ci-...-worker-b
block-copyfail-xsh6d 1/1 Running 34s ci-...-master-0
oc logs -n block-copyfail -l app=block-copyfail
Previsto:
block-copyfail: blocker active — all AF_ALG AEAD binds blocked
Esegui nuovamente lo stesso test dell'exploit dalla sezione Confermare la Vulnerabilità.
Dopo la distribuzione del DaemonSet BPF LSM, l'output sarà:
=== CVE-2026-31431 Vulnerability Test ===
Target: /usr/bin/su
Original SHA256: 30b0f5b5a054c4df65b48ca792863bf7054b4d793f15f57163792ba6c2b151ae
Attempting splice + AF_ALG page-cache corruption (160 bytes in 40 chunks)...
AF_ALG bind failed: [Errno 1] Operation not permitted
RESULT: CANNOT TEST - AF_ALG or splice not available/permitted
I log del DaemonSet mostreranno il tentativo bloccato:
oc logs -n block-copyfail -l app=block-copyfail
block-copyfail: blocker active — all AF_ALG AEAD binds blocked
block-copyfail: BLOCKED pid=16777 comm=python3 time=2026-05-01 16:37:23
Esegui verify-algos.py su un nodo per confermare che tutti gli algoritmi AEAD siano bloccati
mentre gli altri tipi AF_ALG (hash, skcipher) continuano a funzionare:
oc debug node/<qualsiasi-nodo> -- chroot /host python3 -c "
import socket
tests = [
('aead', 'gcm(aes)'),
('aead', 'ccm(aes)'),
('aead', 'rfc4106(gcm(aes))'),
('hash', 'sha256'),
('skcipher', 'cbc(aes)'),
('aead', 'authencesn(hmac(sha256),cbc(aes))'),
]
for t, n in tests:
s = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
try:
s.bind((t, n))
print(f' ALLOWED {t}/{n}')
except OSError as e:
print(f' BLOCKED {t}/{n} -- {e}')
finally:
s.close()
"
Output previsto: