All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Aaron Erhardt" <aer@tuxedocomputers.com>
Cc: linux-input@vger.kernel.org, linux-leds@vger.kernel.org,
	dmitry.torokhov@gmail.com, lee@kernel.org
Subject: Re: [PATCH v7 2/3] HID: generic: add LampArray support via hid-lamparray helper
Date: Tue, 20 Oct 2026 10:06:41 +0000	[thread overview]
Message-ID: <sashiko-outbox-178793@kernel.org> (raw)
In-Reply-To: <20261020-hid-lamparray-v7-2-47418b667b47@tuxedocomputers.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] HID: generic: drvdata clobber and uninitialized read in hid_generic_remove()
- [High] HID: generic: double hid_hw_start() in hid_generic_probe() corrupts reports
--

commit 977659b4786943b7473279419965b0035b45922c
Author: Aaron Erhardt <aer@tuxedocomputers.com>

HID: generic: add LampArray support via hid-lamparray helper

This commit checks for LampArray support in hid_generic_probe() after
hid_parse() and registers a lamparray instance when present. On failure, it
stops the hardware and falls back to starting the device without LampArray,
and unregisters the lamparray instance in hid_generic_remove().

Link: https://lore.kernel.org/all/20260728115918.125349-2-aer@tuxedocomputers.com

[ ... ]

> diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
> index c2de916747dec..fde772c5014bb 100644
> --- a/drivers/hid/hid-generic.c
> +++ b/drivers/hid/hid-generic.c

[ ... ]

> @@ -67,6 +69,34 @@ static int hid_generic_probe(struct hid_device *hdev,
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * Optional: attach LampArray support if present.
> +	 * Never fail probe on LampArray errors; keep device functional.
> +	 */
> +	if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && lamparray_is_supported_device(hdev)) {
> +		/*
> +		 * Use HID_CONNECT_DRIVER to make sure requests are
> +		 * processed in hid_report_raw_event. Without this,
> +		 * hid-core will skip parsing for devices that are only
> +		 * claimed by hidraw, thus making it impossible to query
> +		 * the required information.
> +		 * See 7704ac937345 for more information about this flag
> +		 * and why it is necessary.
> +		 */
> +		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_DRIVER);
> +		if (ret)
> +			return ret;
> +
> +		la = lamparray_register(hdev, NULL);
> +		if (IS_ERR(la)) {
> +			hid_hw_stop(hdev);
> +			hid_warn(hdev, "LampArray init failed: %ld\n", PTR_ERR(la));
> +		} else {
> +			hid_set_drvdata(hdev, la);
> +			return 0;
> +		}
> +	}
> +
>  	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
>  }

[Severity: High]
Does calling hid_hw_start() a second time on the fallback path when
lamparray_register() fails leak report->field_entries and duplicate entries
in report->field_entry_list?

The first hid_hw_start() calls hid_connect() -> hid_process_ordering() ->
hid_report_process_ordering() for every HID_INPUT_REPORT:

drivers/hid/hid-core.c:hid_report_process_ordering() {
	...
	/* allocate the memory to process the fields */
	entries = kzalloc_objs(*entries, count);
	if (!entries)
		return;

	report->field_entries = entries;
	...
}

And appends each entry to report->field_entry_list (which was initialized
once during hid_parse() -> hid_register_report()).

When lamparray_register() fails, hid_generic_probe() calls hid_hw_stop() ->
hid_disconnect(), which does not free report->field_entries or reinitialize
report->field_entry_list because those are only cleaned up in
hid_close_report() -> hid_free_report():

drivers/hid/hid-core.c:hid_free_report() {
	unsigned n;

	kfree(report->field_entries);

	for (n = 0; n < report->maxfield; n++)
		kvfree(report->field[n]);
	kfree(report);
}

When hid_generic_probe() falls through to the second hid_hw_start() on the
same parsed reports, hid_report_process_ordering() allocates a new entries
array, overwrites report->field_entries without freeing the previous array,
and links a second set of entries into report->field_entry_list alongside
the still-linked entries from the first leaked array.

Wouldn't this permanently leak the first report->field_entries allocation and
cause hid_process_report() to process every input field twice per report?

> @@ -78,6 +108,16 @@ static int hid_generic_reset_resume(struct hid_device *hdev)
>  	return 0;
>  }
>  
> +static void hid_generic_remove(struct hid_device *hdev)
> +{
> +	struct lamparray *la = hid_get_drvdata(hdev);
> +
> +	if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && la)
> +		lamparray_unregister(la);
> +
> +	hid_hw_stop(hdev);
> +}

[Severity: Critical]
Can using hid_set_drvdata() and hid_get_drvdata() here collide with low-level
HID transport drivers that store their own private data in
hdev->dev.driver_data?

For example, drivers/hid/hid-hyperv.c sets drvdata before registering the HID
device:

drivers/hid/hid-hyperv.c:mousevsc_probe() {
	...
	hid_set_drvdata(hid_dev, device);

	ret = hid_add_device(hid_dev);
	...
}

And drivers/platform/x86/tuxedo/nb04/wmi_ab.c sets drvdata inside its start
callback during hid_hw_start():

drivers/platform/x86/tuxedo/nb04/wmi_ab.c:tux_ll_start() {
	...
	dev_set_drvdata(&hdev->dev, driver_data);

	return ret;
}

Because hid_generic_probe() only calls hid_set_drvdata(hdev, la) when
lamparray_register() succeeds and leaves hdev->dev.driver_data untouched on
all other paths, if a device on such a transport does not support LampArray
or fails lamparray_register(), won't hid_generic_remove() retrieve the
transport driver's pointer via hid_get_drvdata(hdev) and pass it to
lamparray_unregister(la), corrupting memory and calling kfree() on the
transport driver's structure?

Conversely, if lamparray_register() succeeds on tuxedo_nb04_wmi, won't
hid_set_drvdata(hdev, la) overwrite the struct tux_hdev_driver_data_t pointer
stored by tux_ll_start(), causing subsequent tux_ll_raw_request() calls to
dereference struct lamparray as struct tux_hdev_driver_data_t?

[ ... ]

>
>
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-hid-lamparray-v7-0-47418b667b47@tuxedocomputers.com?part=2

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

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20  9:51 [PATCH v7 0/3] HID: generic: add LampArray support via hid-lamparray helper Aaron Erhardt
2026-10-20  9:51 ` [PATCH v7 1/3] HID: lamparray: add new LampArray helper module Aaron Erhardt
2026-10-20 10:21   ` sashiko-bot
2026-10-20  9:51 ` [PATCH v7 2/3] HID: generic: add LampArray support via hid-lamparray helper Aaron Erhardt
2026-10-20 10:06   ` sashiko-bot [this message]
2026-10-20  9:51 ` [PATCH v7 3/3] HID: lamparray: blank lamps across suspend and restore on resume Aaron Erhardt
2026-10-20 10:11   ` sashiko-bot

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-178793@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=aer@tuxedocomputers.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=lee@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-leds@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.