diff options
| author | Jiang Liu <jiang.liu@linux.intel.com> | 2015-06-01 04:05:11 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2015-06-16 04:10:20 -0400 |
| commit | f6b1464f647424bbeb609ec832428e4079940701 (patch) | |
| tree | 6d98ea920419b704a73e452d77b17b2e81611b91 | |
| parent | c7cfc94096db28d3072b402c224eb50349926e24 (diff) | |
genirq: Prevent crash in irq_move_irq()
The functions irq_move_irq() and irq_move_masked_irq() expect that the
caller passes the top-level irq_data to them when hierarchical
irqdomains are enabled. But that's not true when called from
apic_ack_edge(), which results in a null pointer dereference by
idata->chip->irq_mask(idata).
Instead of fixing callers to passing top-level irq_data, we rather
change irq_move_irq()/irq_move_masked_irq() to accept any irq_data.
Fixes: 52f518a3a7c 'x86/MSI: Use hierarchical irqdomains to manage MSI interrupts'
Reported-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Link: http://lkml.kernel.org/r/1433145945-789-3-git-send-email-jiang.liu@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | kernel/irq/migration.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index ca3f4aaff707..dd203e276b07 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | void irq_move_masked_irq(struct irq_data *idata) | 7 | void irq_move_masked_irq(struct irq_data *idata) |
| 8 | { | 8 | { |
| 9 | struct irq_desc *desc = irq_data_to_desc(idata); | 9 | struct irq_desc *desc = irq_data_to_desc(idata); |
| 10 | struct irq_chip *chip = idata->chip; | 10 | struct irq_chip *chip = desc->irq_data.chip; |
| 11 | 11 | ||
| 12 | if (likely(!irqd_is_setaffinity_pending(&desc->irq_data))) | 12 | if (likely(!irqd_is_setaffinity_pending(&desc->irq_data))) |
| 13 | return; | 13 | return; |
| @@ -52,6 +52,13 @@ void irq_move_irq(struct irq_data *idata) | |||
| 52 | { | 52 | { |
| 53 | bool masked; | 53 | bool masked; |
| 54 | 54 | ||
| 55 | /* | ||
| 56 | * Get top level irq_data when CONFIG_IRQ_DOMAIN_HIERARCHY is enabled, | ||
| 57 | * and it should be optimized away when CONFIG_IRQ_DOMAIN_HIERARCHY is | ||
| 58 | * disabled. So we avoid an "#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY" here. | ||
| 59 | */ | ||
| 60 | idata = irq_desc_get_irq_data(irq_data_to_desc(idata)); | ||
| 61 | |||
| 55 | if (likely(!irqd_is_setaffinity_pending(idata))) | 62 | if (likely(!irqd_is_setaffinity_pending(idata))) |
| 56 | return; | 63 | return; |
| 57 | 64 | ||
