From: Marc Zyngier maz@kernel.org
commit 1b73e588f47397dee6e4bdfd953e0306c60b5fe5 upstream.
Casting a small array of u8 to an unsigned long is *never* OK:
- it does funny thing when the array size is less than that of a long, as it accesses random places in the stack - it makes everything even more fun with a BE kernel
Fix this by building the unsigned long used as a bitmap byte by byte, in a way that works across endianess and has no undefined behaviours.
An extra BUILD_BUG_ON() catches the unlikely case where the array would be larger than a single unsigned long.
Fixes: 1490d9f841b1 ("pinctrl: Add STMFX GPIO expander Pinctrl/GPIO driver") Signed-off-by: Marc Zyngier maz@kernel.org Cc: stable@vger.kernel.org Cc: Amelie Delaunay amelie.delaunay@foss.st.com Cc: Linus Walleij linus.walleij@linaro.org Cc: Maxime Coquelin mcoquelin.stm32@gmail.com Cc: Alexandre Torgue alexandre.torgue@foss.st.com Link: https://lore.kernel.org/r/20210725180830.250218-1-maz@kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/pinctrl/pinctrl-stmfx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -566,7 +566,7 @@ static irqreturn_t stmfx_pinctrl_irq_thr u8 pending[NR_GPIO_REGS]; u8 src[NR_GPIO_REGS] = {0, 0, 0}; unsigned long n, status; - int ret; + int i, ret;
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_IRQ_GPI_PENDING, &pending, NR_GPIO_REGS); @@ -576,7 +576,9 @@ static irqreturn_t stmfx_pinctrl_irq_thr regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, src, NR_GPIO_REGS);
- status = *(unsigned long *)pending; + BUILD_BUG_ON(NR_GPIO_REGS > sizeof(status)); + for (i = 0, status = 0; i < NR_GPIO_REGS; i++) + status |= (unsigned long)pending[i] << (i * 8); for_each_set_bit(n, &status, gc->ngpio) { handle_nested_irq(irq_find_mapping(gc->irq.domain, n)); stmfx_pinctrl_irq_toggle_trigger(pctl, n);