x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
PATCH 1/1 x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
Hi,
In current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the cpu that has the disabled irqs in vector_irq is hotplugged again, __setup_vector_irq() hits invalid irq vector and may crash.
Commit f6175f5bfb4c partially fixes this, but was not enough in environments with IOMMU IRQ remapper.
This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online # modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared # echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crash
This patch fixes this bug by clearing vector_irq in __fixup_irqs() when the cpu is offlined.
--- arch/x86/kernel/irq.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/kernel/irq.c +1 -0
@@ -328,6 +328,7 @@ void fixup_irqs(void) chip->irq_retrigger (data); raw_spin_unlock(&desc->lock); } +__this_cpu_write (vector_irq[vector],-1 ); } }#endif
Signature · 5 lines
1.7.7.6 -- Tomoki Sekiyama <[email protected]> Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory
Quoted 7 lines · Tomoki
In current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the cpu that has the disabled irqs in
vector_irqis hotplugged again,__setup_vector_irq()hits invalid irq vector and may crash.Commit
f6175f5bfb4cpartially fixes this, but was not enough in environments with IOMMU IRQ remapper.
So, this patch essentially makes the commit f6175f5bfb4c unnecessary, right?
Can you revert that too as part of this new proposed patch?
thanks,
suresh
Hi, thanks for your comment.
Quoted 9 lines · Suresh B
Quoted 7 lines · Tomoki
In current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the cpu that has the disabled irqs in
vector_irqis hotplugged again,__setup_vector_irq()hits invalid irq vector and may crash.Commit
f6175f5bfb4cpartially fixes this, but was not enough in environments with IOMMU IRQ remapper.
Quoted 6 lines
So, this patch essentially makes the commit
f6175f5bfb4cunnecessary, right?Can you revert that too as part of this new proposed patch?
thanks,
suresh
OK, I will include a reverse patch of f6175f5bfb4c and resend the patch.
Thanks,
Signature · 3 lines
Tomoki Sekiyama <[email protected]> Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory
PATCH 1/1 x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
In reply to Siddha, Suresh BIn current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the CPU that has the disabled irqs in vector_irq is hotplugged again, __setup_vector_irq() hits invalid irq vector and may crash.
This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online # modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared # echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crash
To fix this problem, this patch clears vector_irq in __fixup_irqs() when the CPU is offlined.
This also reverts commit f6175f5bfb4c, which partially fixes this bug by clearing vector in __clear_irq_vector(). But in environments with IOMMU IRQ remapper, it could fail because cfg->domain doesn't contain offlined CPUs. With this patch, the fix in __clear_irq_vector() can be reverted because every vector_irq is already cleared in __fixup_irqs() on offlined CPUs.
--- arch/x86/kernel/apic/io_apic.c | 4 ++-- arch/x86/kernel/irq.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +2 -2
@@ -1195,7 +1195,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)BUG_ON (!cfg->vector); vector = cfg->vector; -for_each_cpu (cpu, cfg->domain) +for_each_cpu_and (cpu, cfg->domain, cpu_online_mask)per_cpu (vector_irq, cpu)[vector] =-1 ; cfg->vector =0 ;
@@ -1203,7 +1203,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)if (likely (!cfg->move_in_progress))return ; -for_each_cpu (cpu, cfg->old_domain) { +for_each_cpu_and (cpu, cfg->old_domain, cpu_online_mask) {for (vector =FIRST_EXTERNAL_VECTOR ; vector <NR_VECTORS ; vector++) {if (per_cpu (vector_irq, cpu)[vector] != irq)
arch/x86/kernel/irq.c +1 -0
@@ -328,6 +328,7 @@ void fixup_irqs(void) chip->irq_retrigger (data); raw_spin_unlock(&desc->lock); } +__this_cpu_write (vector_irq[vector],-1 ); } }#endif
Signature · 1 line
1.7.7.6
Quoted 43 lines · Tomoki Sekiyama
In current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the CPU that has the disabled irqs in
vector_irqis hotplugged again,__setup_vector_irq()hits invalid irq vector and may crash.This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online # modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared # echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crashTo fix this problem, this patch clears
vector_irqin__fixup_irqs()when the CPU is offlined.This also reverts commit
f6175f5bfb4c, which partially fixes this bug by clearing vector in__clear_irq_vector(). But in environments with IOMMU IRQ remapper, it could fail becausecfg->domaindoesn't contain offlined CPUs. With this patch, the fix in__clear_irq_vector()can be reverted because everyvector_irqis already cleared in__fixup_irqs()on offlined CPUs.Signed-off-by Tomoki Sekiyama <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Ingo Molnar <[email protected]>Cc "H. Peter Anvin" <[email protected]>Cc Suresh Siddha <[email protected]>Cc Yinghai Lu <[email protected]>Cc Alexander Gordeev <[email protected]>--- arch/x86/kernel/apic/io_apic.c | 4 ++-- arch/x86/kernel/irq.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)arch/x86/kernel/apic/io_apic.c +1
-1@@ -1195,7 +1195,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)BUG_ON (!cfg->vector); vector = cfg->vector; -for_each_cpu (cpu, cfg->domain) +for_each_cpu_and (cpu, cfg->domain, cpu_online_mask)per_cpu (vector_irq, cpu)[vector] =-1 ; cfg->vector =0 ;
arch/x86/kernel/apic/io_apic.c static void __clear_irq_vector(int irq, struct irq_cfg *cfg) · line 1205
Quoted 3 lines
arch/x86/kernel/apic/io_apic.c +0
-1@@ -1203,7 +1203,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)if (likely (!cfg->move_in_progress))return ; -for_each_cpu (cpu, cfg->old_domain) {
that's not a valid diff - something in your mailer ate lines or such. See Documentation/email-clients.txt.
Thanks,
Ingo
PATCH RESEND 1/1 x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
(Previous patch was broken, sorry. Resending with another mailer.)
In current Linux, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the CPU that has the disabled irqs in vector_irq is hotplugged again, __setup_vector_irq() hits invalid irq vector and may crash.
This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online # modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared # echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crash
To fix this problem, this patch clears vector_irq in __fixup_irqs() when the CPU is offlined.
This also reverts commit f6175f5bfb4c, which partially fixes this bug by clearing vector in __clear_irq_vector(). But in environments with IOMMU IRQ remapper, it could fail because cfg->domain doesn't contain offlined CPUs. With this patch, the fix in __clear_irq_vector() can be reverted because every vector_irq is already cleared in __fixup_irqs() on offlined CPUs.
---
arch/x86/kernel/apic/io_apic.c | 4 ++-- arch/x86/kernel/irq.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +2 -2
@@ -1195,7 +1195,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)BUG_ON (!cfg->vector); vector = cfg->vector; -for_each_cpu (cpu, cfg->domain) +for_each_cpu_and (cpu, cfg->domain, cpu_online_mask)per_cpu (vector_irq, cpu)[vector] =-1 ; cfg->vector =0 ;
@@ -1203,7 +1203,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)if (likely (!cfg->move_in_progress))return ; -for_each_cpu (cpu, cfg->old_domain) { +for_each_cpu_and (cpu, cfg->old_domain, cpu_online_mask) {for (vector =FIRST_EXTERNAL_VECTOR ; vector <NR_VECTORS ; vector++) {if (per_cpu (vector_irq, cpu)[vector] != irq)
arch/x86/kernel/irq.c +1 -0
@@ -328,6 +328,7 @@ void fixup_irqs(void) chip->irq_retrigger (data); raw_spin_unlock(&desc->lock); } +__this_cpu_write (vector_irq[vector],-1 ); } }#endif
Commit-ID: 1d44b30f35a9873a65b320dd5300088fa995fd94 Gitweb: http://git.kernel.org/tip/1d44b30f35a9873a65b320dd5300088fa995fd94 Author: Tomoki Sekiyama <[email protected]> AuthorDate: Thu, 26 Jul 2012 19:47:32 +0900 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 26 Jul 2012 15:01:17 +0200
x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
In the current kernel, percpu variable `vector_irq' is not always cleared when a CPU is offlined. If the CPU that has the disabled irqs in vector_irq is hotplugged again, __setup_vector_irq() hits invalid irq vector and may crash.
This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online # modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared # echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crash
To fix this problem, this patch clears vector_irq in __fixup_irqs() when the CPU is offlined.
This also reverts commit f6175f5bfb4c, which partially fixes this bug by clearing vector in __clear_irq_vector(). But in environments with IOMMU IRQ remapper, it could fail because cfg->domain doesn't contain offlined CPUs. With this patch, the fix in __clear_irq_vector() can be reverted because every vector_irq is already cleared in __fixup_irqs() on offlined CPUs.
--- arch/x86/kernel/apic/io_apic.c | 4 ++-- arch/x86/kernel/irq.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +2 -2
@@ -1204,7 +1204,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)BUG_ON (!cfg->vector); vector = cfg->vector; -for_each_cpu (cpu, cfg->domain) +for_each_cpu_and (cpu, cfg->domain, cpu_online_mask)per_cpu (vector_irq, cpu)[vector] =-1 ; cfg->vector =0 ;
@@ -1212,7 +1212,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)if (likely (!cfg->move_in_progress))return ; -for_each_cpu (cpu, cfg->old_domain) { +for_each_cpu_and (cpu, cfg->old_domain, cpu_online_mask) {for (vector =FIRST_EXTERNAL_VECTOR ; vector <NR_VECTORS ; vector++) {if (per_cpu (vector_irq, cpu)[vector] != irq)
arch/x86/kernel/irq.c +1 -0
@@ -328,6 +328,7 @@ void fixup_irqs(void) chip->irq_retrigger (data); raw_spin_unlock(&desc->lock); } +__this_cpu_write (vector_irq[vector],-1 ); } }#endif