aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-12-31 11:30:51 -0500
committerThomas Gleixner <tglx@linutronix.de>2016-01-15 07:44:01 -0500
commitc1684f5035b60e9f98566493e869496fb5de1d89 (patch)
treecf57565f3857050c8827837d6ab2c04683d417e2 /arch/x86
parent847667ef10356b824a11c853fc8a8b1b437b6a8d (diff)
x86/irq: Clear move_in_progress before sending cleanup IPI
send_cleanup_vector() fiddles with the old_domain mask unprotected because it relies on the protection by the move_in_progress flag. But this is fatal, as the flag is reset after the IPI has been sent. So a cpu which receives the IPI can still see the flag set and therefor ignores the cleanup request. If no other cleanup request happens then the vector stays stale on that cpu and in case of an irq removal the vector still persists. That can lead to use after free when the next cleanup IPI happens. Protect the code with vector_lock and clear move_in_progress before sending the IPI. This does not plug the race which Joe reported because: CPU0 CPU1 CPU2 lock_vector() data->move_in_progress=0 sendIPI() unlock_vector() set_affinity() assign_irq_vector() lock_vector() handle_IPI move_in_progress = 1 lock_vector() unlock_vector() move_in_progress == 1 The full fix comes with a later patch. Reported-and-tested-by: Joe Lawrence <joe.lawrence@stratus.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Borislav Petkov <bp@alien8.de> Cc: Jiang Liu <jiang.liu@linux.intel.com> Cc: Jeremiah Mahler <jmmahler@gmail.com> Cc: andy.shevchenko@gmail.com Cc: Guenter Roeck <linux@roeck-us.net> Cc: stable@vger.kernel.org #4.3+ Link: http://lkml.kernel.org/r/20151231160106.892412198@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/apic/vector.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 68d18b338e3a..ed62f9c3f785 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -532,6 +532,8 @@ static void __send_cleanup_vector(struct apic_chip_data *data)
532{ 532{
533 cpumask_var_t cleanup_mask; 533 cpumask_var_t cleanup_mask;
534 534
535 raw_spin_lock(&vector_lock);
536 data->move_in_progress = 0;
535 if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { 537 if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
536 unsigned int i; 538 unsigned int i;
537 539
@@ -543,7 +545,7 @@ static void __send_cleanup_vector(struct apic_chip_data *data)
543 apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); 545 apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
544 free_cpumask_var(cleanup_mask); 546 free_cpumask_var(cleanup_mask);
545 } 547 }
546 data->move_in_progress = 0; 548 raw_spin_unlock(&vector_lock);
547} 549}
548 550
549void send_cleanup_vector(struct irq_cfg *cfg) 551void send_cleanup_vector(struct irq_cfg *cfg)