CVE-2026-74568 in Linux
Riassunto
di VulDB • 15/08/2026
Nel kernel Linux è stata risolta la seguente vulnerabilità:
KVM: arm64: vgic: Correzione di una race condition tra il rilascio e la re-registrazione degli LPI
Risolve una potenziale race condition tra la decrementazione del conteggio dei riferimenti (reference count) di un LPI ed l'evizione della relativa struttura dall'xarray degli LPI.
Le strutture LPI sono mantenute nell'xarray VGIC LPI (dist->lpi_xa). Quando il conteggio dei riferimenti di una struttura LPI scende a zero, vgic_release_lpi_locked() rimuove la struttura dall'xarray e la libera sotto il lock dell'xarray.
Tuttavia, il rilascio di un LPI può andare in conflitto (race) con una contemporanea re-registrazione dello stesso LPI con lo stesso INTID tramite vgic_add_lpi() su un altro CPU, poiché la diminuzione del conteggio dei riferimenti e l'evizione dall'xarray non vengono eseguite come un'unica operazione atomica. Ciò può accadere ad esempio se il guest emette una DISCARD mentre l'LPI è ancora referenziato nella lista active-pending (ap_list) di un vCPU, e lo stesso INTID viene rimappato tramite MAPTI.
In particolare, vgic_release_lpi_locked() viene chiamata da due percorsi distinti: rilascio diretto tramite vgic_put_irq(), e rilascio differito tramite vgic_release_deleted_lpis(). Durante il rilascio diretto, il problema può comportare la cancellazione di un LPI appena registrato dall'xarray:
CPU0 (Rilascio LPI) CPU1 (Aggiunta nuovo LPI) ==================== ===================== vgic_put_irq() __vgic_put_irq() refcount_dec_and_test() vgic_add_lpi() xa_lock_irqsave() old_irq = xa_load(.., intid) vgic_try_get_irq_ref(old_irq) == false nuovo IRQ inserito --> __xa_store(.., intid, ..) xa_unlock_irqrestore() xa_lock_irqsave(); vgic_release_lpi_locked() __xa_erase(.., irq->intid) <-- BUG: il nuovo IRQ viene cancellato kfree_rcu(old_irq)
Durante il percorso di rilascio differito, l'IRQ vecchio può andare in leak (memory leak):
CPU0 (Rilascio LPI) CPU1 (Aggiunta nuovo LPI) ==================== ===================== vgic_put_irq_norelease() __vgic_put_irq() refcount_dec_and_test() irq->pending_release = true vgic_add_lpi() xa_lock_irqsave() old_irq = xa_load(.., intid) vgic_try_get_irq_ref(oldirq) == false BUG: vecchio IRQ sovrascritto --> __xa_store(.., intid, ..) xa_unlock_irqrestore()
vgic_release_deleted_lpis() xa_lock_irqsave() xa_for_each() { .. } <-- il vecchio IRQ con pending_release = true
è scomparso, quindi non può essere rilasciato
Per correggere il percorso di rilascio diretto, spostare la diminuzione del conteggio dei riferimenti all'interno del lock dell'xarray, assicurandosi che vgic_add_lpi() non incontri mai l'LPI in fase di rilascio.
Nel percorso di rilascio differito, la diminuzione del refcount deve avvenire sotto un raw spinlock, quindi il lock dell'xarray non può essere acquisito e la stessa soluzione non funziona. Invece, aggiornare vgic_add_lpi() in modo che, se evitasse un LPI dall'xarray, si assuma la responsabilità di liberarlo. Di conseguenza, un LPI ora potrebbe essere liberato contemporaneamente dopo che il rilascio differito ha abbassato il refcount; l'accesso al campo pending_release non è più sicuro da use-after-free. Eliminare tutti gli utilizzi del flag e aggiornare vgic_release_deleted_lpis() per identificare i LPI orfani esclusivamente in base al loro conteggio dei riferimenti
If you want to get best quality of vulnerability data, you may have to visit VulDB.