mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86/irq: fix infinite loop in irq_move_cleanup_interrupt
If Xen enters irq_move_cleanup_interrupt with a dynamic vector below
IRQ_MOVE_CLEANUP_VECTOR pending in IRR (0x20 or 0x21) that's also
designated for a cleanup it will enter a loop where
irq_move_cleanup_interrupt continuously sends a cleanup IPI (vector
0x22) to itself while waiting for the vector with lower priority to be
injected - which will never happen because IRQ_MOVE_CLEANUP_VECTOR
takes precedence and it's always injected first.
Fix this by making sure vectors below IRQ_MOVE_CLEANUP_VECTOR are
marked as used and thus not available for APs. Also add some logic to
assert and prevent irq_move_cleanup_interrupt from entering such an
infinite loop, albeit that should never happen given the current code.
This is XSA-356 / CVE-2020-29567.
Fixes: 3fba06ba9f ('x86/IRQ: re-use legacy vector ranges on APs')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
e6ebd39438
commit
ca85682e8c
1 file changed
+14
-6
+14
-6
@@ -448,8 +448,15 @@ int __init init_irq_data(void)
|
||||
set_bit(HYPERCALL_VECTOR, used_vectors);
|
||||
#endif
|
||||
|
||||
/* IRQ_MOVE_CLEANUP_VECTOR used for clean up vectors */
|
||||
set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
|
||||
/*
|
||||
* Mark vectors up to the cleanup one as used, to prevent an infinite loop
|
||||
* invoking irq_move_cleanup_interrupt.
|
||||
*/
|
||||
BUILD_BUG_ON(IRQ_MOVE_CLEANUP_VECTOR < FIRST_DYNAMIC_VECTOR);
|
||||
for ( vector = FIRST_DYNAMIC_VECTOR;
|
||||
vector <= IRQ_MOVE_CLEANUP_VECTOR;
|
||||
vector++ )
|
||||
__set_bit(vector, used_vectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -734,10 +741,6 @@ void irq_move_cleanup_interrupt(struct cpu_user_regs *regs)
|
||||
{
|
||||
unsigned vector, me;
|
||||
|
||||
/* This interrupt should not nest inside others. */
|
||||
BUILD_BUG_ON(APIC_PRIO_CLASS(IRQ_MOVE_CLEANUP_VECTOR) !=
|
||||
APIC_PRIO_CLASS(FIRST_DYNAMIC_VECTOR));
|
||||
|
||||
ack_APIC_irq();
|
||||
|
||||
me = smp_processor_id();
|
||||
@@ -781,6 +784,11 @@ void irq_move_cleanup_interrupt(struct cpu_user_regs *regs)
|
||||
*/
|
||||
if ( irr & (1u << (vector % 32)) )
|
||||
{
|
||||
if ( vector < IRQ_MOVE_CLEANUP_VECTOR )
|
||||
{
|
||||
ASSERT_UNREACHABLE();
|
||||
goto unlock;
|
||||
}
|
||||
send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
|
||||
TRACE_3D(TRC_HW_IRQ_MOVE_CLEANUP_DELAY,
|
||||
irq, vector, smp_processor_id());
|
||||
|
||||