From: Cyrill Gorcunov Subject: x86: io-apic - interrupt remapping fix References: fate #303948 and fate #303984 Patch-Mainline: queued for .28 Commit-ID: 77322deb4bc676a5ee645444e7ed1a89f854473d Signed-off-by: Thomas Renninger Interrupt remapping could lead to NULL dereference in case of kzalloc failed and memory leak in other way. So fix the both cases. Signed-off-by: Cyrill Gorcunov Cc: "Maciej W. Rozycki" Cc: Suresh Siddha Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic_64.c | 13 ++++++++++--- arch/x86/kernel/io_apic_64.c | 19 +++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) Index: linux-2.6.26/arch/x86/kernel/apic_64.c =================================================================== --- linux-2.6.26.orig/arch/x86/kernel/apic_64.c +++ linux-2.6.26/arch/x86/kernel/apic_64.c @@ -969,7 +969,12 @@ void enable_IR_x2apic(void) local_irq_save(flags); mask_8259A(); - save_mask_IO_APIC_setup(); + + ret = save_mask_IO_APIC_setup(); + if (ret) { + printk(KERN_INFO "Saving IO-APIC state failed: %d\n", ret); + goto end; + } ret = enable_intr_remapping(1); @@ -979,14 +984,15 @@ void enable_IR_x2apic(void) } if (ret) - goto end; + goto end_restore; if (!x2apic) { x2apic = 1; apic_ops = &x2apic_ops; enable_x2apic(); } -end: + + end_restore: if (ret) /* * IR enabling failed @@ -995,6 +1001,7 @@ end: else reinit_intr_remapped_IO_APIC(x2apic_preenabled); + end: unmask_8259A(); local_irq_restore(flags); Index: linux-2.6.26/arch/x86/kernel/io_apic_64.c =================================================================== --- linux-2.6.26.orig/arch/x86/kernel/io_apic_64.c +++ linux-2.6.26/arch/x86/kernel/io_apic_64.c @@ -474,7 +474,7 @@ int save_mask_IO_APIC_setup(void) kzalloc(sizeof(struct IO_APIC_route_entry) * nr_ioapic_registers[apic], GFP_KERNEL); if (!early_ioapic_entries[apic]) - return -ENOMEM; + goto nomem; } for (apic = 0; apic < nr_ioapics; apic++) @@ -489,16 +489,31 @@ int save_mask_IO_APIC_setup(void) } } return 0; + + nomem: + for (; apic > 0; apic--) + kfree(early_ioapic_entries[apic]); + kfree(early_ioapic_entries[apic]); + memset(early_ioapic_entries, 0, + ARRAY_SIZE(early_ioapic_entries)); + + return -ENOMEM; + } void restore_IO_APIC_setup(void) { int apic, pin; - for (apic = 0; apic < nr_ioapics; apic++) + for (apic = 0; apic < nr_ioapics; apic++) { + if (!early_ioapic_entries[apic]) + break; for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) ioapic_write_entry(apic, pin, early_ioapic_entries[apic][pin]); + kfree(early_ioapic_entries[apic]); + early_ioapic_entries[apic] = NULL; + } } void reinit_intr_remapped_IO_APIC(int intr_remapping)