Linux Input/HID development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Bishwa Bhusan Saha" <contact@bishwasaha.com>
Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH 4/5] HID: UNCTRL: keep a single battery when a mouse has multiple connections
Date: Mon, 12 Oct 2026 20:29:02 +0000	[thread overview]
Message-ID: <sashiko-outbox-168594@kernel.org> (raw)
In-Reply-To: <20261013-b4-unctrl-m1-battery-v1-4-4a50203b7177@bishwasaha.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] hid: uaf in unctrl_remove() due to early work cancellation and list exposure
- [High] hid: uaf of power_supply in unctrl_raw_event() racing with cross-device probe
- [High] hid: uaf of dev in unctrl_probe() error path due to concurrent battery transfer
- [Medium] hid: permanent battery loss due to missing rollback in unctrl_battery_register()
--

commit 01440f9100f714c61f17b835003fbfa0e20c249f
Author: Bishwa Bhusan Saha <contact@bishwasaha.com>

    HID: UNCTRL: keep a single battery when a mouse has multiple connections

    This patch modifies the unctrl_m1 driver to register a single power
    supply across multiple connections (e.g., wired and dongle) of the same
    mouse. It transfers the power supply ownership when a more capable
    connection appears or disappears.

> diff --git a/drivers/hid/hid-unctrl-m1.c b/drivers/hid/hid-unctrl-m1.c
> --- a/drivers/hid/hid-unctrl-m1.c
> +++ b/drivers/hid/hid-unctrl-m1.c
[ ... ]
> @@ -181,32 +181,32 @@ static int unctrl_battery_register(struct unctrl_dev *dev)
>  	if (owner) {
>  		struct power_supply *owner_battery;
>  
>  		cancel_delayed_work_sync(&owner->battery_work);
>  		/* so a raw_event cannot touch the supply being unregistered */
>  		scoped_guard(spinlock_irqsave, &owner->lock) {
>  			owner_battery = owner->battery;
>  			owner->battery = NULL;
>  		}
>  		power_supply_unregister(owner_battery);
>  	}
>  
>  	battery = power_supply_register(&dev->hdev->dev, &dev->battery_desc,
>  					&config);
>  	if (IS_ERR(battery)) {
>  		ret = PTR_ERR(battery);
>  		hid_err(dev->hdev,
>  			"%s:power_supply_register failed with error %d\n",
>  			__func__, ret);
>  		return ret;

[Severity: Medium]
If power_supply_register() fails here, does the original owner's battery 
remain unregistered forever?

We just cancelled the owner's work and unregistered its battery above, but 
the error path doesn't restore it. Could this leave the active device 
permanently without battery reporting?

>  	}
>  
>  	power_supply_powers(battery, &dev->hdev->dev);
[ ... ]
> @@ -312,11 +312,11 @@ static int unctrl_probe(struct hid_device *hdev, const struct hid_device_id *id)
>  	if (ret)
>  		goto err_del;
>  
>  	return 0;
>  
>  err_del:
>  	mutex_lock(&unctrl_lock);
>  	list_del(&dev->list);
>  	mutex_unlock(&unctrl_lock);

[Severity: High]
Is there a use-after-free risk in this error path due to a concurrent 
battery transfer?

During the time between the failing unctrl_battery_register() returning and 
re-acquiring the lock here at err_del, could a concurrent unctrl_remove() 
on another connection find this dev in unctrl_connections?

If that happens, the other thread would transfer its battery to this failing
dev and schedule dev->battery_work. This work would remain active after 
kfree(dev) is called at the end of this function.

>  	hid_hw_close(hdev);
>  	hid_hw_stop(hdev);
>  	hid_set_drvdata(hdev, NULL);
>  	kfree(dev);
>  	return ret;
>  }
[ ... ]
> @@ -336,15 +336,15 @@ static int unctrl_raw_event(struct hid_device *hdev, struct hid_report *report,
[ ... ]
>  	scoped_guard(spinlock_irqsave, &dev->lock) {
>  		/* the receiver reports 0% while the mouse is switched off */
>  		dev->battery_capacity = min_t(u8, data[4], 100);
>  		dev->mode = data[5];
>  		dev->online = dev->battery_capacity != 0;
>  		battery = dev->battery;
>  	}
>  
>  	/* only schedules a work, so this is safe from the completion path */
>  	if (battery)
>  		power_supply_changed(battery);

[Severity: High]
Can power_supply_changed() dereference a freed pointer here?

If a new connection probes concurrently, it can call unctrl_battery_register(), 
which acquires this dev->lock, sets dev->battery = NULL, and immediately 
calls power_supply_unregister(). 

Since power_supply_unregister() synchronously frees the battery, and this 
code drops dev->lock before using the cached battery pointer, could this 
lead to a use-after-free?

>  	return 0;
>  }
>  
>  static void unctrl_remove(struct hid_device *hdev)
>  {
>  	struct unctrl_dev *dev = hid_get_drvdata(hdev);
>  	struct unctrl_dev *other;
>  
>  	/* Stop polling before the transport goes down. */
>  	if (dev) {
>  		cancel_delayed_work_sync(&dev->battery_work);

[Severity: High]
Could dev->battery_work be rescheduled after this cancellation, leading to
a use-after-free?

Since dev is still in the global unctrl_connections list here (it isn't 
removed until the mutex_lock(&unctrl_lock) later in the function), could a 
concurrent unctrl_probe() or unctrl_remove() from another device find it, 
transfer a battery to it, and call schedule_delayed_work()?

If so, the rescheduled work might execute after kfree(dev) is called.

>  		hid_hw_close(hdev);
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261013-b4-unctrl-m1-battery-v1-0-4a50203b7177@bishwasaha.com?part=4

  reply	other threads:[~2026-10-12 20:29 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-12 20:15 [PATCH 0/5] HID: add battery driver for the UNCTRL RAGE Wireless Mouse Bishwa Bhusan Saha via B4 Relay
2026-10-12 20:15 ` [PATCH 1/5] HID: add IDs for UNCTRL RAGE Mouse Bishwa Bhusan Saha via B4 Relay
2026-10-12 20:15 ` [PATCH 2/5] HID: UNCTRL: add basic battery reporting " Bishwa Bhusan Saha via B4 Relay
2026-10-12 20:23   ` sashiko-bot
2026-10-12 20:15 ` [PATCH 3/5] HID: UNCTRL: add periodic battery reporting using a workqueue Bishwa Bhusan Saha via B4 Relay
2026-10-12 20:26   ` sashiko-bot
2026-10-12 20:15 ` [PATCH 4/5] HID: UNCTRL: keep a single battery when a mouse has multiple connections Bishwa Bhusan Saha via B4 Relay
2026-10-12 20:29   ` sashiko-bot [this message]
2026-10-12 20:15 ` [PATCH 5/5] HID: UNCTRL: only report to userspace on battery changes Bishwa Bhusan Saha via B4 Relay

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=sashiko-outbox-168594@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=contact@bishwasaha.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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