From nobody Fri Oct 2 12:22:33 2026 Received: from zg8tmtyylji0my4xnjeumjiw.icoremail.net (zg8tmtyylji0my4xnjeumjiw.icoremail.net [162.243.161.220]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9A6DD2D063E; Sun, 2 Aug 2026 02:04:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.243.161.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785636262; cv=none; b=WZr2lA6kAjcx8m02IoKwr8I9qJcngCXQ/PC3dHBZxsnkav95aVh4uHcJBj3XCRPubY4mO3/IJROIFlHSu9TY/6ypA2e89TxsMIFKG1Z7SSJF317fIYpo1I3m7dJg6RD0AY0MkNgd1K2OW0QgFrBecBykw/BgGPUOjjPMRvqZeRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785636262; c=relaxed/simple; bh=xKbEZNSJ0MfUPk/Ogo4MrO+ZKJhEBz4eja60qCvYOlQ=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=VYZeoD4f5Q4rhlZz0yFVlSOBUWkn7QSOW3T/gaS2s9Hl2OYHSegkA/gIoB0wMuN8tIQFJhYIve2tAdnSbcbUpuZRuBJFVGs+DYYugnFa+3QvtUcsRRkArzlAYSQ/mV9e9wCHoyuRh9XwlL+MhLtXIXdZ5MaE8AHtQ7L6057V7kQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zju.edu.cn; spf=pass smtp.mailfrom=zju.edu.cn; arc=none smtp.client-ip=162.243.161.220 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zju.edu.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zju.edu.cn Received: from zju.edu.cn (unknown [10.98.66.117]) by mtasvr (Coremail) with SMTP id _____wAn8n2bpW5q+QxZAA--.8833S3; Sun, 02 Aug 2026 10:04:12 +0800 (CST) Received: from localhost.localdomain (unknown [10.98.66.117]) by mail-app2 (Coremail) with SMTP id zC_KCgCH9cqbpW5qgk5zAw--.23194S2; Sun, 02 Aug 2026 10:04:11 +0800 (CST) From: Fan Wu To: linux-pm@vger.kernel.org Cc: sre@kernel.org, linusw@kernel.org, arun.murthy@stericsson.com, anton.vorontsov@linaro.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Fan Wu Subject: [PATCH] power: supply: ab8500_fg: fix use-after-free on remove Date: Sun, 2 Aug 2026 02:03:16 +0000 Message-Id: <20260802020316.417757-1-fanwu01@zju.edu.cn> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: zC_KCgCH9cqbpW5qgk5zAw--.23194S2 X-CM-SenderInfo: qrstjiaswqq6lmxovvfxof0/ X-CM-DELIVERINFO: =?B?WLVragXKKxbFmtjJiESix3B1w3vZ3A9ovKVTomAyoQazvoRs/NHSP8GI2EvgeEEW7R sfncGSG+szpQCInt5Y8rbJUI0TwYvJJsLt58VnWhmFj6/wTGpwf9BHTNqP+i4dXGDUEahK PROcqqbFF12lOVoJfpep9E6mavGmQbzmcFsnzP86 X-Coremail-Antispam: 1Uk129KBj93XoWxAFyfArWkJFWkGr43WF1fKrX_yoW5uF1xpF Z3WFyYk3y8XF4jvFZxJr17CF13Ca1xAr17Cw4fGa1Syw15X3yqyw1rKFy0gF95WFyrJ39r Aa95J393ur1F9agCm3ZEXasCq-sJn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUU9Cb4IE77IF4wAFF20E14v26r4j6ryUM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_tr0E3s1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26F4UJVW0owA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2vYz4IE04k24VAvwVAKI4IrM2AIxVAIcxkEcVAq07x20xvEncxIr21l57 IF6xkI12xvs2x26I8E6xACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE 14v26r1Y6r17McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2 IYc2Ij64vIr41lF7xvr2IYc2Ij64vIr40E4x8a64kEw24l42xK82IYc2Ij64vIr41l4I8I 3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxV WUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAF wI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r1j6r4UMIIF0xvE42xK8VAvwI8IcI k0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r1j 6r4UYxBIdaVFxhVjvjDU0xZFpf9x07jUGYJUUUUU= Content-Type: text/plain; charset="utf-8" ab8500_fg_remove() destroys the driver workqueue while the threaded interrupt handlers are still armed; they are devm-managed and freed only after ->remove() returns, so a handler that fires in that window queues work on the freed workqueue. Tear the workqueue down through devm instead, registering its cleanup after the power supply and before the interrupt requests. devm then frees the interrupts first, so the handlers can no longer queue work, before disabling the delayed and plain work items and destroying the workqueue. Disabling the items, rather than cancelling them, keeps them disabled so no producer (including the power-supply external_power_changed callback) can requeue them. Found by an in-house static analysis tool. Fixes: 13151631b5bd ("ab8500-fg: A8500 fuel gauge driver") Cc: stable@vger.kernel.org # v6.10+ Assisted-by: Codex:gpt-5.6 Signed-off-by: Fan Wu Reviewed-by: Linus Walleij --- drivers/power/supply/ab8500_fg.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500= _fg.c index 0000000..1111111 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3054,6 +3054,20 @@ flush_workqueue(di->fg_wq); } =20 +/* Disable, not cancel: works stay disabled so nothing can re-arm them. */ +static void ab8500_fg_destroy_workqueue(void *data) +{ + struct ab8500_fg *di =3D data; + + disable_work_sync(&di->fg_acc_cur_work); + disable_work_sync(&di->fg_work); + disable_delayed_work_sync(&di->fg_reinit_work); + disable_delayed_work_sync(&di->fg_low_bat_work); + disable_delayed_work_sync(&di->fg_check_hw_failure_work); + disable_delayed_work_sync(&di->fg_periodic_work); + destroy_workqueue(di->fg_wq); +} + static const struct component_ops ab8500_fg_component_ops =3D { .bind =3D ab8500_fg_bind, .unbind =3D ab8500_fg_unbind, @@ -3155,6 +3169,11 @@ return PTR_ERR(di->fg_psy); } =20 + /* Registered after fg_psy, before the IRQs: devm frees IRQ -> workqueue = -> fg_psy. */ + ret =3D devm_add_action_or_reset(dev, ab8500_fg_destroy_workqueue, di); + if (ret) + return ret; + di->fg_samples =3D SEC_TO_SAMPLE(di->bm->fg_params->init_timer); =20 /* @@ -3168,7 +3187,6 @@ for (i =3D 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) { irq =3D platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); if (irq < 0) { - destroy_workqueue(di->fg_wq); return irq; } =20 @@ -3180,7 +3198,6 @@ if (ret !=3D 0) { dev_err(dev, "failed to request %s IRQ %d: %d\n", ab8500_fg_irq[i].name, irq, ret); - destroy_workqueue(di->fg_wq); return ret; } dev_dbg(dev, "Requested %s IRQ %d: %d\n", @@ -3196,7 +3213,6 @@ ret =3D ab8500_fg_sysfs_init(di); if (ret) { dev_err(dev, "failed to create sysfs entry\n"); - destroy_workqueue(di->fg_wq); return ret; } =20 @@ -3204,7 +3220,6 @@ if (ret) { dev_err(dev, "failed to create FG psy\n"); ab8500_fg_sysfs_exit(di); - destroy_workqueue(di->fg_wq); return ret; } =20 @@ -3224,7 +3239,6 @@ { struct ab8500_fg *di =3D platform_get_drvdata(pdev); =20 - destroy_workqueue(di->fg_wq); component_del(&pdev->dev, &ab8500_fg_component_ops); list_del(&di->node); ab8500_fg_sysfs_exit(di); --=20 2.34.1