Skip to content

Commit 92ea772

Browse files
author
Linus Torvalds
committed
Fix crash with irqpoll due to the IRQF_IRQPOLL flag testing
With irqpoll enabled, trying to test the IRQF_IRQPOLL flag in the actions would cause a NULL pointer dereference if no action was installed (for example, the driver might have been unloaded with interrupts still pending). So be a bit more careful about testing the flag by making sure to test for that case. (The actual _change_ is trivial, the patch is more than a one-liner because I rewrote the testing to also be much more readable. Original (discarded) bugfix by Bernhard Walle. Cc: Bernhard Walle <[email protected]> Tested-by: Vivek Goyal <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent db2668f commit 92ea772

File tree

1 file changed

+37
-9
lines changed

1 file changed

+37
-9
lines changed

kernel/irq/spurious.c

+37-9
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,39 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
135135
}
136136
}
137137

138+
static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
139+
{
140+
struct irqaction *action;
141+
142+
if (!irqfixup)
143+
return 0;
144+
145+
/* We didn't actually handle the IRQ - see if it was misrouted? */
146+
if (action_ret == IRQ_NONE)
147+
return 1;
148+
149+
/*
150+
* But for 'irqfixup == 2' we also do it for handled interrupts if
151+
* they are marked as IRQF_IRQPOLL (or for irq zero, which is the
152+
* traditional PC timer interrupt.. Legacy)
153+
*/
154+
if (irqfixup < 2)
155+
return 0;
156+
157+
if (!irq)
158+
return 1;
159+
160+
/*
161+
* Since we don't get the descriptor lock, "action" can
162+
* change under us. We don't really care, but we don't
163+
* want to follow a NULL pointer. So tell the compiler to
164+
* just load it once by using a barrier.
165+
*/
166+
action = desc->action;
167+
barrier();
168+
return action && (action->flags & IRQF_IRQPOLL);
169+
}
170+
138171
void note_interrupt(unsigned int irq, struct irq_desc *desc,
139172
irqreturn_t action_ret)
140173
{
@@ -144,15 +177,10 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
144177
report_bad_irq(irq, desc, action_ret);
145178
}
146179

147-
if (unlikely(irqfixup)) {
148-
/* Don't punish working computers */
149-
if ((irqfixup == 2 && ((irq == 0) ||
150-
(desc->action->flags & IRQF_IRQPOLL))) ||
151-
action_ret == IRQ_NONE) {
152-
int ok = misrouted_irq(irq);
153-
if (action_ret == IRQ_NONE)
154-
desc->irqs_unhandled -= ok;
155-
}
180+
if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
181+
int ok = misrouted_irq(irq);
182+
if (action_ret == IRQ_NONE)
183+
desc->irqs_unhandled -= ok;
156184
}
157185

158186
desc->irq_count++;

0 commit comments

Comments
 (0)