Linux Input/HID development
 help / color / mirror / Atom feed
From: Maoyi Xie <maoyixie.tju@gmail.com>
To: Hans de Goede <hansg@kernel.org>, Jiri Kosina <jikos@kernel.org>,
	Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: hid-lg-g15: possible use-after-free of devm data via work scheduled from a report
Date: Wed, 17 Jun 2026 20:10:05 +0800	[thread overview]
Message-ID: <178169820506.2930960.12219303668828186338@maoyixie.com> (raw)

Hi all,

I think the lg-g15 driver can read freed memory on disconnect. I would
appreciate it if you could check my reading before I send a patch.

The per device state is allocated with devm in lg_g15_probe().

	g15 = devm_kzalloc(&hdev->dev, sizeof(*g15), GFP_KERNEL);

That struct contains a work item, and the report handlers schedule it
straight from device input. For example in lg_g15_event().

	/* Backlight cycle button pressed? */
	if (data[1] & 0x80)
		schedule_work(&g15->work);

The same schedule_work(&g15->work) call also runs in lg_g15_v2_event() and
lg_g510_leds_event(). The worker lg_g15_leds_changed_work() does a
container_of() back to g15 and dereferences g15->mutex and g15->leds.

The driver has a probe but no remove callback, and there is no
cancel_work_sync() anywhere in the file. So if a report schedules the work
and the keyboard is then removed, devm frees g15 while the work is still
pending or running, and the worker touches the freed object.

The attacker model is a Logitech G15 class keyboard that sends one report
with the backlight cycle bit set and then disconnects. That can be a
malicious device or an unlucky unplug.

I reproduced the freed while pending pattern under KASAN on 7.1-rc7. The
workqueue picked up the orphaned work after the object was freed, and KASAN
reported a slab-use-after-free read.

The fix I tried is a small remove callback that cancels the work before the
devm teardown frees g15.

	static void lg_g15_remove(struct hid_device *hdev)
	{
		struct lg_g15_data *g15 = hid_get_drvdata(hdev);

		if (g15)
			cancel_work_sync(&g15->work);

		hid_hw_stop(hdev);
	}

and wiring it up with .remove = lg_g15_remove. The g15 NULL guard mirrors the
existing check in lg_g15_raw_event().

Does this look like a real issue to you, and is the remove plus
cancel_work_sync the approach you would want? If so I am happy to send a
proper patch with a Fixes tag against 97b741aba918.

Thanks,
Maoyi
https://maoyixie.com/

                 reply	other threads:[~2026-06-17 12:10 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=178169820506.2930960.12219303668828186338@maoyixie.com \
    --to=maoyixie.tju@gmail.com \
    --cc=bentiss@kernel.org \
    --cc=hansg@kernel.org \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.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