From 970616464f43b33e309996dc58bbf49a8a29f5e4 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 30 Jun 2017 10:58:28 +0100 Subject: irqchip/gic-v3: Fix out-of-bound access in gic_set_affinity commit 866d7c1b0a3c70387646c4e455e727a58c5d465a upstream. The GICv3 driver doesn't check if the target CPU for gic_set_affinity is valid before going ahead and making the changes. This triggers the following splat with KASAN: [ 141.189434] BUG: KASAN: global-out-of-bounds in gic_set_affinity+0x8c/0x140 [ 141.189704] Read of size 8 at addr ffff200009741d20 by task swapper/1/0 [ 141.189958] [ 141.190158] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.12.0-rc7 [ 141.190458] Hardware name: Foundation-v8A (DT) [ 141.190658] Call trace: [ 141.190908] [] dump_backtrace+0x0/0x328 [ 141.191224] [] show_stack+0x14/0x20 [ 141.191507] [] dump_stack+0xa4/0xc8 [ 141.191858] [] print_address_description+0x13c/0x250 [ 141.192219] [] kasan_report+0x210/0x300 [ 141.192547] [] __asan_load8+0x84/0x98 [ 141.192874] [] gic_set_affinity+0x8c/0x140 [ 141.193158] [] irq_do_set_affinity+0x54/0xb8 [ 141.193473] [] irq_set_affinity_locked+0x64/0xf0 [ 141.193828] [] __irq_set_affinity+0x48/0x78 [ 141.194158] [] arm_perf_starting_cpu+0x104/0x150 [ 141.194513] [] cpuhp_invoke_callback+0x17c/0x1f8 [ 141.194783] [] notify_cpu_starting+0x8c/0xb8 [ 141.195130] [] secondary_start_kernel+0x15c/0x200 [ 141.195390] [<0000000080db81b4>] 0x80db81b4 [ 141.195603] [ 141.195685] The buggy address belongs to the variable: [ 141.196012] __cpu_logical_map+0x200/0x220 [ 141.196176] [ 141.196315] Memory state around the buggy address: [ 141.196586] ffff200009741c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 141.196913] ffff200009741c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 141.197158] >ffff200009741d00: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00 [ 141.197487] ^ [ 141.197758] ffff200009741d80: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00 [ 141.198060] ffff200009741e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 141.198358] ================================================================== [ 141.198609] Disabling lock debugging due to kernel taint [ 141.198961] CPU1: Booted secondary processor [410fd051] This patch adds the check to make sure the cpu is valid. Fixes: commit 021f653791ad17e03f98 ("irqchip: gic-v3: Initial support for GICv3") Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e33c729b9f48..5a1490b046ac 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -632,6 +632,9 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, int enabled; u64 val; + if (cpu >= nr_cpu_ids) + return -EINVAL; + if (gic_irq_in_rdist(d)) return -EINVAL; -- cgit v1.2.3 From fc6c41f0b921a7c6a8b4a14f63b0e22df9bc06de Mon Sep 17 00:00:00 2001 From: "Strashko, Grygorii" Date: Thu, 8 Dec 2016 17:33:10 -0600 Subject: irqchip/keystone: Fix "scheduling while atomic" on rt [ Upstream commit 2f884e6e688a0deb69e6c9552e51aef8b7e3f5f1 ] The below call chain generates "scheduling while atomic" backtrace and causes system crash when Keystone 2 IRQ chip driver is used with RT-kernel: gic_handle_irq() |-__handle_domain_irq() |-generic_handle_irq() |-keystone_irq_handler() |-regmap_read() |-regmap_lock_spinlock() |-rt_spin_lock() The reason is that Keystone driver dispatches IRQ using chained IRQ handler and accesses I/O memory through syscon->regmap(mmio) which is implemented as fast_io regmap and uses regular spinlocks for synchronization, but spinlocks transformed to rt_mutexes on RT. Hence, convert Keystone 2 IRQ driver to use generic irq handler instead of chained IRQ handler. This way it will be compatible with RT kernel where it will be forced thread IRQ handler while in non-RT kernel it still will be executed in HW IRQ context. Cc: Suman Anna Signed-off-by: Grygorii Strashko Tested-by: Suman Anna Link: https://lkml.kernel.org/r/20161208233310.10329-1-grygorii.strashko@ti.com Signed-off-by: Jason Cooper Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-keystone.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index deb89d63a728..e684be1bb7c0 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -19,9 +19,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -39,6 +39,7 @@ struct keystone_irq_device { struct irq_domain *irqd; struct regmap *devctrl_regs; u32 devctrl_offset; + raw_spinlock_t wa_lock; }; static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq) @@ -83,17 +84,15 @@ static void keystone_irq_ack(struct irq_data *d) /* nothing to do here */ } -static void keystone_irq_handler(struct irq_desc *desc) +static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq) { - unsigned int irq = irq_desc_get_irq(desc); - struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); + struct keystone_irq_device *kirq = keystone_irq; + unsigned long wa_lock_flags; unsigned long pending; int src, virq; dev_dbg(kirq->dev, "start irq %d\n", irq); - chained_irq_enter(irq_desc_get_chip(desc), desc); - pending = keystone_irq_readl(kirq); keystone_irq_writel(kirq, pending); @@ -111,13 +110,15 @@ static void keystone_irq_handler(struct irq_desc *desc) if (!virq) dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n", src, virq); + raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags); generic_handle_irq(virq); + raw_spin_unlock_irqrestore(&kirq->wa_lock, + wa_lock_flags); } } - chained_irq_exit(irq_desc_get_chip(desc), desc); - dev_dbg(kirq->dev, "end irq %d\n", irq); + return IRQ_HANDLED; } static int keystone_irq_map(struct irq_domain *h, unsigned int virq, @@ -182,9 +183,16 @@ static int keystone_irq_probe(struct platform_device *pdev) return -ENODEV; } + raw_spin_lock_init(&kirq->wa_lock); + platform_set_drvdata(pdev, kirq); - irq_set_chained_handler_and_data(kirq->irq, keystone_irq_handler, kirq); + ret = request_irq(kirq->irq, keystone_irq_handler, + 0, dev_name(dev), kirq); + if (ret) { + irq_domain_remove(kirq->irqd); + return ret; + } /* clear all source bits */ keystone_irq_writel(kirq, ~0x0); @@ -199,6 +207,8 @@ static int keystone_irq_remove(struct platform_device *pdev) struct keystone_irq_device *kirq = platform_get_drvdata(pdev); int hwirq; + free_irq(kirq->irq, kirq); + for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++) irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq)); -- cgit v1.2.3 From 4c1ea6a51acdd9090effa9086df1b86354298cef Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 27 Dec 2016 18:29:57 +0000 Subject: irqchip/mxs: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND [ Upstream commit 88e20c74ee020f9e0c99dfce0dd9aa61c3f0cca0 ] The ICOLL controller doesn't provide any facility to configure the wakeup sources. That's the reason why this implementation lacks the irq_set_wake implementation. But this prevent us from properly entering power management states like "suspend to idle". So enable the flags IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND to let the irqchip core allows and handles the power management. Signed-off-by: Stefan Wahren Reviewed-by: Fabio Estevam Link: https://lkml.kernel.org/r/1482863397-11400-1-git-send-email-stefan.wahren@i2se.com Signed-off-by: Jason Cooper Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-mxs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 17304705f2cf..05fa9f7af53c 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -131,12 +131,16 @@ static struct irq_chip mxs_icoll_chip = { .irq_ack = icoll_ack_irq, .irq_mask = icoll_mask_irq, .irq_unmask = icoll_unmask_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, }; static struct irq_chip asm9260_icoll_chip = { .irq_ack = icoll_ack_irq, .irq_mask = asm9260_mask_irq, .irq_unmask = asm9260_unmask_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, }; asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) -- cgit v1.2.3