mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: 徐晗翔 <xuhx@hust.edu.cn>
To: sre@kernel.org
Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: power: supply: bq25890: pump-express work can call power_supply_changed after the psy is unregistered
Date: Tue, 10 Nov 2026 21:14:45 +0800 (GMT+08:00)	[thread overview]
Message-ID: <4ff0e52f.22b04.1a1c598c347.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>

The bq25890 probe registers the power_supply with devm and registers
bq25890_non_devm_cleanup() as an earlier devm action.  Devres is LIFO,
so on unbind the psy is unregistered first and the pump-express work is
canceled only afterwards.  bq25890_remove() does not cancel the work.
The pump work can therefore run after power_supply_unregister() and call
power_supply_changed(bq->charger) (and set_property on the secondary
charger), dereferencing a psy that the core may already have freed.
This is a driver remove-order bug, not the core wrapper bug.

The detailed description:

* Test environment / affected version

  Linux 7.3.0 source tree (unmodified kernel.org 7.3), x86_64.  This is
  a source-level report.  I did not run it on bq25890 hardware: the
  KASAN build used for my core tests does not enable
  CONFIG_CHARGER_BQ25890 and has no I2C bq25890 device.  No reproducer
  is attached.  Line numbers are from 7.3.

* Mechanism

  Probe order:

      :1409  bq->secondary_chrg = power_supply_get_by_name(...)
      :1413  devm_add_action_or_reset(..., bq25890_release_secondary_chrg)
      :1477  INIT_DELAYED_WORK(&bq->pump_express_work, ...)
      :1522  devm_add_action_or_reset(..., bq25890_non_devm_cleanup)
      :1530  bq25890_power_supply_init()
        :1040  devm_power_supply_register(...)
      :1534  devm_request_threaded_irq(...)

  The comment at :1518-1520 says the cleanup action must be registered
  before bq25890_power_supply_init() so that it runs after devm
  unregisters the power_supply.  That is exactly the wrong order for a
  work that calls into the psy: the psy is gone before the work is
  canceled.

  bq25890_remove() (:1550-1563) only cancels the usb_phy work and resets
  the chip; it does not cancel pump_express_work.
  bq25890_non_devm_cleanup() (:1449-1460) calls
  cancel_delayed_work_sync(&bq->pump_express_work), but only after the
  psy unregister.

  bq25890_charger_external_power_changed() (:744-779) queues the work at
  :763-765.  The work (:1056-1116) sleeps/polls for up to several
  seconds (3 s poll + 1 s sleep per iteration), calls
  power_supply_set_property(secondary, ONLINE) at :1068/:1104, and
  power_supply_changed(bq->charger) at :1110.

  Once power_supply_unregister() has run and the last reference is gone,
  bq->charger is a dangling pointer; power_supply_changed() dereferences
  psy->changed_lock at its first line.  If a consumer still holds a
  reference, the psy survives but is already removed; the changed work
  then hits the core 5B problem.

* Concrete corruption / impact

  power_supply_changed() on the freed psy is a slab-use-after-free
  (spin_lock on the freed changed_lock, then schedule_work on the freed
  work item).  It can corrupt the workqueue or crash the kernel; if a
  consumer keeps the psy alive, the same call reaches the freed LED
  triggers described in the core 5B report on a 7.3 kernel without the
  9f7f7a859451 get/set guard.  I have not demonstrated
  privilege escalation, and I have not run this on hardware.

* Trigger model

  bq25890 with pump-express enabled and a DCP charger; unbind/remove
  while the pump work is queued or running.  The work deliberately
  sleeps, so the window is seconds, not a single instruction.  Removing
  the device or unbinding the driver requires root; a charger
  unplug/replug can also start the work.  No generic unprivileged
  userspace interface.

* Reproducer / results

  No reproducer attached.  This is a source-level report; I can test a
  proposed fix if bq25890 hardware is available.  The relevant call
  chain is fully visible in 7.3 at the line numbers above.



* Suggested direction

  Quiesce the work before unregistering the psy.  In bq25890_remove(),
  set a stop flag checked by bq25890_charger_external_power_changed(),
  cancel_delayed_work_sync(&bq->pump_express_work), then ensure the
  power_supply is unregistered after that (explicit unregister or a
  devres order that puts cleanup before unregister).  Reordering the
  cleanup action alone is not enough because external_power_changed()
  can requeue the work after the cancel.  Also clear or check
  bq->charger before use.  Report-first, no patch attached; happy to
  test a proposal.

  
Please keep me in Cc; I am not subscribed to the lists.


Regards,
Hanxiang Xu
xuhx@hust.edu.cn

  parent reply	other threads:[~2026-11-10 13:14 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-27 12:35 usb: devio: usbdev_release() has no barrier against an in-flight async_completed() callback (use-after-free window on struct usb_dev_state)gregkh@linuxfoundation.org 徐晗翔
2026-10-27 14:12 ` Greg KH
2026-11-03 11:21   ` mm/slub: has_pcs_used() reads remote per-CPU sheaf state from flush_all_cpus_locked() without synchronization (data race; KCSAN blind spot: slub.o is uninstrumented) 徐晗翔
2026-11-04  9:41     ` Qing Wang
2026-11-04 10:07       ` Qing Wang
2026-11-03 11:30   ` futex/hrtimer: hrtimer_sleeper::task is read unsynchronized in 16 places on v7.3 -- the accessor series that fixes this is not in 7.3; please make sure it reaches the affected trees (backport nudge + stock-kernel KCSAN evidence) 徐晗翔
2026-11-03 11:48   ` cgroup: fork vs cgroup.procs write race in favordynmods mode -- v7.3 is affected; please make sure bf6fbf46b5ff reaches the stable trees (repro incl. uninstrumented natural hit) 徐晗翔
2026-11-03 14:51     ` Sasha Levin
2026-11-03 11:57   ` net: rtnetlink: rtnl_link_unregister() vs in-flight RTM_GETLINK dump readers -- v7.3 lacks the synchronize_rcu() fix (Fixes: 6b57ff21a310 family); A/B reproduction on stock 7.3 徐晗翔
2026-11-03 15:49     ` Eric Dumazet
2026-11-04 15:03     ` Sasha Levin
2026-11-03 12:07   ` wifi: wilc1000: SDIO/SPI remove destroys the srcu_struct before wiphy_unregister() -- late cfg80211 callbacks write through dangling srcu state (unfixed upstream; controlled + natural Oops) 徐晗翔
2026-11-03 12:10   ` gpio: gpiolib: final put of the gpio_device happens inside the SRCU read critical section on the setup-failure path -- deterministic use-after-free read at guard release (unfixed upstream) 徐晗翔
2026-11-05  8:52     ` Linus Walleij
2026-11-04 12:54   ` soc: qcom: pmic_glink_altmode: fix use-after-free on unbind (no cancel_work_sync for port work and enable_work) 徐晗翔
2026-11-04 13:04     ` Greg KH
2026-11-04 12:57   ` usb: typec: anx7411: unregister partner/altmodes before stopping the IRQ work -- use-after-free, double unregister, orphan partner on remove 徐晗翔
2026-11-04 13:28     ` Greg KH
2026-11-04 12:58   ` usb: typec: ucsi: deadlock on cros_ec unbind -- connector lock held across cancel_delayed_work_sync vs the mode-selection work's unbounded trylock polling 徐晗翔
2026-11-04 13:00   ` usb: typec: stusb160x/rt1719/hd3ss3220: IRQ thread vs remove -- double unregister / use-after-free on the partner and port 徐晗翔
2026-11-04 13:01   ` usb: typec: ucsi: displayport: data race on dp->header/ vdo_data/vdo_size -- work reads them unlocked while writers hold con->lock (VDM mismatch) 徐晗翔
2026-11-04 13:02   ` usb: typec: class: three lifetime/locking gaps around the mux/switch handles and mode_selection (drvdata UAF after provider unbind; no concurrent protocol for set/put; unlocked state_update vs delete) 徐晗翔
2026-11-10 12:56   ` driver core: uevent: netns teardown frees uevent_sock while a tagged uevent is still being broadcast (UAF) 徐晗翔
2026-11-10 13:00   ` 徐晗翔
2026-11-10 13:05   ` ACPI: CPPC: per-CPU cpc_desc is freed on processor unbind without clearing the published pointer, causing UAF in cpufreq accessors 徐晗翔
2026-11-10 13:07   ` ACPI: CPPC: shared PCC subspace data can be freed while another CPU probes, reads, or tears it down 徐晗翔
2026-11-10 13:11   ` ACPI: ACPICA: Reset can delete an event semaphore while another thread is blocked in Wait 徐晗翔
2026-11-10 13:14   ` 徐晗翔 [this message]
2026-11-10 13:17   ` power: supply: core: get/set property callbacks can run after unregister and read freed driver data 徐晗翔
2026-11-10 13:18   ` power: supply: core: system-battery enumeration can return an unregistered battery 徐晗翔
2026-11-10 13:21   ` power: supply: core: changed work can run after unregister and use freed LED triggers 徐晗翔
2026-11-10 13:23   ` power: supply: bq24190: IRQ handler can call power_supply_changed after the psy is unregistered 徐晗翔

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4ff0e52f.22b04.1a1c598c347.Coremail.xuhx@hust.edu.cn \
    --to=xuhx@hust.edu.cn \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=sre@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®