Commit c2b56b62 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Greg Kroah-Hartman

x86/irq: Clear move_in_progress before sending cleanup IPI

commit c1684f50 upstream.

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: default avatarJoe Lawrence <joe.lawrence@stratus.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarBorislav 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>
Link: http://lkml.kernel.org/r/20151231160106.892412198@linutronix.deSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 550ac3f7
...@@ -530,6 +530,8 @@ static void __send_cleanup_vector(struct apic_chip_data *data) ...@@ -530,6 +530,8 @@ static void __send_cleanup_vector(struct apic_chip_data *data)
{ {
cpumask_var_t cleanup_mask; cpumask_var_t cleanup_mask;
raw_spin_lock(&vector_lock);
data->move_in_progress = 0;
if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
unsigned int i; unsigned int i;
...@@ -541,7 +543,7 @@ static void __send_cleanup_vector(struct apic_chip_data *data) ...@@ -541,7 +543,7 @@ static void __send_cleanup_vector(struct apic_chip_data *data)
apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
free_cpumask_var(cleanup_mask); free_cpumask_var(cleanup_mask);
} }
data->move_in_progress = 0; raw_spin_unlock(&vector_lock);
} }
void send_cleanup_vector(struct irq_cfg *cfg) void send_cleanup_vector(struct irq_cfg *cfg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment