VYPR
Unrated severityNVD Advisory· Published Jun 9, 2026

CVE-2026-46316

CVE-2026-46316

Description

Linux kernel KVM: arm64 vgic-its vulnerability allows double-free due to incorrect cache reference handling.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Linux kernel KVM: arm64 vgic-its vulnerability allows double-free due to incorrect cache reference handling.

Vulnerability

The Linux kernel's KVM (Kernel-based Virtual Machine) component for arm64, specifically the vgic-its module, contains a vulnerability where the translation cache reference is dropped more than once for erased entries. This occurs in vgic_its_invalidate_cache() when multiple contexts concurrently invalidate the same cache entries. The affected versions are not explicitly stated, but the fix is present in the kernel version associated with reference [1].

Exploitation

An attacker can exploit this vulnerability by triggering concurrent invalidation of the same translation cache entries from different contexts. These contexts include ITS command handlers holding its_lock, the GITS_CTLR write path holding cmd_lock, and a path clearing EnableLPIs in a redistributor's GICR_CTLR which holds neither lock. If these concurrent operations observe and erase the same entry, the cache's reference to that entry is dropped multiple times.

Impact

Successful exploitation can lead to a use-after-free condition. The translation cache entry can be freed while an ITE (Interrupt Translation Entry) still maps it. This could potentially lead to system instability or allow an attacker to gain unauthorized access or control, depending on how the freed memory is subsequently used.

Mitigation

The vulnerability has been resolved in the Linux kernel version associated with reference [1]. The fix involves ensuring that vgic_put_irq() is called only on the entry that was actually removed by xa_erase(), thus dropping the cache reference exactly once per entry. No specific fixed version number or release date is provided in the available references, nor are any workarounds mentioned. The vulnerability is not listed on the KEV catalog at this time.

AI Insight generated on Jun 9, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

8
13031fb6b835

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 1d7e5d560af4c..1e3706ac3b8e9 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
b7b72e880463

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 5f6583b9abe37..dcd6b23ad2e1e 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -590,8 +590,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
2bbc395e81bd

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index a4c0fb7f02ea8..fa58668bcf1b7 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
9121f4605ab9

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 1d7e5d560af4c..1e3706ac3b8e9 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
13031fb6b835

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 1d7e5d560af4c..1e3706ac3b8e9 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
2bbc395e81bd

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index a4c0fb7f02ea8..fa58668bcf1b7 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
9121f4605ab9

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 1d7e5d560af4c..1e3706ac3b8e9 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    
b7b72e880463

KVM: arm64: vgic-its: Drop the translation cache reference only for the erased entry

1 file changed · +4 3
  • arch/arm64/kvm/vgic/vgic-its.c+4 3 modified
    diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
    index 5f6583b9abe37..dcd6b23ad2e1e 100644
    --- a/arch/arm64/kvm/vgic/vgic-its.c
    +++ b/arch/arm64/kvm/vgic/vgic-its.c
    @@ -590,8 +590,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
     	unsigned long idx;
     
     	xa_for_each(&its->translation_cache, idx, irq) {
    -		xa_erase(&its->translation_cache, idx);
    -		vgic_put_irq(kvm, irq);
    +		/* Only the context that erases the entry drops its cache ref. */
    +		irq = xa_erase(&its->translation_cache, idx);
    +		if (irq)
    +			vgic_put_irq(kvm, irq);
     	}
     }
     
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"The vgic_its_invalidate_cache function incorrectly drops translation cache references multiple times when multiple contexts concurrently erase the same entry."

Attack vector

The vulnerability occurs when multiple contexts concurrently call `vgic_its_invalidate_cache()`. These contexts include ITS command handlers, the GITS_CTLR write path, and the path clearing EnableLPIs in a redistributor's GICR_CTLR. If these contexts observe and erase the same cache entry, the reference count for that entry is decremented more than once. This can lead to the entry being freed while still in use, potentially causing a use-after-free condition.

Affected code

The vulnerability resides in the `vgic_its_invalidate_cache` function within `arch/arm64/kvm/vgic/vgic-its.c`. The issue stems from how the function iterates through the translation cache using `xa_for_each()` and calls `vgic_put_irq()` on the iterated pointer rather than the value returned by `xa_erase()`.

What the fix does

The patch modifies the `vgic_its_invalidate_cache` function to ensure that `vgic_put_irq()` is called only for the entry that was actually erased by `xa_erase()`. By assigning the result of `xa_erase()` to `irq` and then conditionally calling `vgic_put_irq(kvm, irq)` if `irq` is not null, the reference count is now decremented exactly once per erased entry. This prevents the double-free issue even when invalidations occur concurrently [patch_id=5354439].

Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

1