Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

genirq: prevent wakeup of freed irq thread

free_irq() can remove an irqaction while the corresponding interrupt
is in progress, but free_irq() sets action->thread to NULL
unconditionally, which might lead to a NULL pointer dereference in
handle_IRQ_event() when the hard interrupt context tries to wake up
the handler thread.

Prevent this by moving the thread stop after synchronize_irq(). No
need to set action->thread to NULL either as action is going to be
freed anyway.

This fixes a boot crash reported against preempt-rt which uses the
mainline irq threads code to implement full irq threading.

[ tglx: removed local irqthread variable ]

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

Linus Torvalds and committed by
Thomas Gleixner
2d860ad7 3493e84d

+7 -10
+7 -10
kernel/irq/manage.c
··· 761 761 { 762 762 struct irq_desc *desc = irq_to_desc(irq); 763 763 struct irqaction *action, **action_ptr; 764 - struct task_struct *irqthread; 765 764 unsigned long flags; 766 765 767 766 WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); ··· 808 809 desc->chip->disable(irq); 809 810 } 810 811 811 - irqthread = action->thread; 812 - action->thread = NULL; 813 - 814 812 spin_unlock_irqrestore(&desc->lock, flags); 815 813 816 814 unregister_handler_proc(irq, action); 817 815 818 816 /* Make sure it's not being used on another CPU: */ 819 817 synchronize_irq(irq); 820 - 821 - if (irqthread) { 822 - if (!test_bit(IRQTF_DIED, &action->thread_flags)) 823 - kthread_stop(irqthread); 824 - put_task_struct(irqthread); 825 - } 826 818 827 819 #ifdef CONFIG_DEBUG_SHIRQ 828 820 /* ··· 830 840 local_irq_restore(flags); 831 841 } 832 842 #endif 843 + 844 + if (action->thread) { 845 + if (!test_bit(IRQTF_DIED, &action->thread_flags)) 846 + kthread_stop(action->thread); 847 + put_task_struct(action->thread); 848 + } 849 + 833 850 return action; 834 851 } 835 852