[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.14] x86/irq: fix infinite loop in irq_move_cleanup_interrupt



commit d785e076b36111899ef9ee2340f2da9375afc9f5
Author:     Roger Pau Monné <roger.pau@xxxxxxxxxx>
AuthorDate: Tue Dec 15 14:14:34 2020 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Dec 15 14:14:34 2020 +0100

    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: 3fba06ba9f8 ('x86/IRQ: re-use legacy vector ranges on APs')
    Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: ca85682e8c16361fdf3814c9b25a2ec3ff4f8bed
    master date: 2020-12-15 13:42:16 +0100
---
 xen/arch/x86/irq.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 8d1f9a9fc6..37c86283cc 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -441,8 +441,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;
 }
@@ -727,10 +734,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();
@@ -774,6 +777,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());
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.14



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.