From d34ac2129c5da5cf322f392c370506b9040696df Mon Sep 17 00:00:00 2001 From: Mark Tomlinson Date: Thu, 9 Jul 2026 16:51:16 +1200 Subject: [PATCH] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock ANBZ: #44446 commit 9dc325327babe7f159e84cbe9380a45342da0585 upstream. Locking is disabled in the regmap config as this driver uses its own lock. This means that all calls to regmap functions (read or write) must hold the i2c_lock. The function pca953x_irq_bus_sync_unlock() did not do this, and it was therefore possible that multiple threads could cause an incorrect register to be read/written. A previous patch partly fixed this, but only protected the write to the interrupt mask register, and not the read from the direction register. [backport-note] PatchPilot-Conflict-Type: context_drift, divergent_fix PatchPilot-Conflict-Files: drivers/gpio/gpio-pca953x.c PatchPilot-Resolution: drivers/gpio/gpio-pca953x.c: Remove duplicate lock in _unlocked helper and irq_bus_sync_unlock; use unlocked... Fixes: bfc6444b57dc ("gpio: pca953x: fix pca953x_irq_bus_sync_unlock race") Cc: stable@vger.kernel.org Signed-off-by: Mark Tomlinson Link: https://patch.msgid.link/20260709045116.2304246-1-mark.tomlinson@alliedtelesis.co.nz Signed-off-by: Bartosz Golaszewski Fixes: CVE-2026-74733 Assisted-by: PatchPilot Signed-off-by: Xunlei Pang --- drivers/gpio/gpio-pca953x.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index bf701766f4d0..52f81dbf39c3 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -517,15 +517,23 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long * return 0; } -static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) +static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc, + unsigned int off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); u8 bit = BIT(off % BANK_SZ); + return regmap_write_bits(chip->regmap, dirreg, bit, bit); +} + +static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + guard(mutex)(&chip->i2c_lock); - return regmap_write_bits(chip->regmap, dirreg, bit, bit); + return pca953x_gpio_direction_input_unlocked(gc, off); } static int pca953x_gpio_direction_output(struct gpio_chip *gc, @@ -753,9 +761,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(reg_direction, MAX_LINE); int level; - if (chip->driver_data & PCA_PCAL) { - guard(mutex)(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); + if (chip->driver_data & PCA_PCAL) { /* Enable latch on interrupt-enabled inputs */ pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); @@ -775,8 +783,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio); /* Look for any newly setup interrupt */ - for_each_set_bit(level, irq_mask, gc->ngpio) - pca953x_gpio_direction_input(&chip->gpio_chip, level); + for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio) + pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); mutex_unlock(&chip->irq_lock); } -- Gitee