All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Michael Reeves via B4 Relay"
	<devnull+michael.reeves077.gmail.com@kernel.org>
Cc: dmitry.torokhov@gmail.com, devicetree@vger.kernel.org,
	robh@kernel.org, conor+dt@kernel.org,
	linux-input@vger.kernel.org
Subject: Re: [PATCH 08/10] HID: apple: Add DockChannel HID transport driver
Date: Tue, 30 Jun 2026 13:58:03 +0000	[thread overview]
Message-ID: <20260630135803.F39741F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-8-506d936a1707@gmail.com>

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Flawed teardown ordering in dchid_remove leads to Use-After-Free of HID devices and transport channel.
- [High] dchid_raw_request returns an unvalidated length from the device, leading to a heap out-of-bounds read in hidraw.
- [High] Missing null-termination enforcement on hardware-provided interface name leads to an out-of-bounds read.
- [High] Concurrency flaws in dchid_cmd lead to kernel log spam and state corruption.
- [High] Unbounded devres memory allocation in dchid_handle_descriptor allows device to exhaust kernel memory.
- [High] Missing memory barriers when publishing and reading dchid->ifaces array causes a potential crash on weakly ordered architectures.
- [Medium] dchid_raw_request returns incorrect length for HID_REQ_SET_REPORT, causing false short write errors.
- [Medium] Missing cleanup for the ASC coprocessor and RTKit on probe error paths.
- [Low] Native pointer assignment writes the checksum in host byte order, causing failures on Big-Endian systems.
--

commit 73972b8194e713fd30c0d82321eb7f0553221fd5
Author: Michael Reeves <michael.reeves077@gmail.com>

HID: apple: Add DockChannel HID transport driver

This commit adds a transport driver that boots the MTP RTKit coprocessor,
exchanges HID packets through the DockChannel mailbox, and registers child
HID interfaces from devicetree.

> diff --git a/drivers/hid/dockchannel/apple-hid.c b/drivers/hid/dockchannel/apple-hid.c
> index 0000000000000..162fcfb5ab1ce
> --- /dev/null
> +++ b/drivers/hid/dockchannel/apple-hid.c

[ ... ]

> +static struct dchid_iface *
> +dchid_get_interface(struct dchid_dev *dchid, int index, const char *name)
> +{

[ ... ]

> +	iface->index = index;
> +	iface->name = devm_kstrdup(dchid->dev, name, GFP_KERNEL);

[Severity: High]
Can this cause an out-of-bounds read if the hardware sends a name that is
exactly 16 characters and not null-terminated? In dchid_handle_init(), the
device provides a fixed 16-byte character array for hdr->name. If it lacks a
null terminator, devm_kstrdup() will read past the end of the array into
adjacent fields. Should this use devm_kstrndup(..., 16, ...) instead?

[ ... ]

> +	dchid->ifaces[index] = iface;
> +	mutex_unlock(&dchid->ifaces_lock);
> +	return iface;
> +}

[Severity: High]
Does the absence of a memory barrier here allow the reader to observe an
uninitialized interface? The interface is published to the array here and
the mutex is unlocked, but dchid_process_packet() reads this array locklessly.
The mutex_unlock() does not prevent the compiler or CPU from reordering the
initialization of the structure (like iface->wq) to after the pointer becomes
visible. Should smp_store_release() be used when publishing to the array?

[ ... ]

> +static int dchid_send(struct dchid_iface *iface, u32 flags, const void *msg,
> +		      size_t size)
> +{

[ ... ]

> +	*checksum_ptr = 0xffffffff - dchid_checksum(buf, total_len - DCHID_CHECKSUM_LEN);

[Severity: Low]
Does this write the checksum in the CPU's native byte order rather than
the expected little-endian format? Since other fields like hdr->length use
__le16, it appears the hardware expects little-endian, which could cause
packets to be dropped on big-endian architectures. Should this use
put_unaligned_le32() instead?

[ ... ]

> +static int dchid_cmd(struct dchid_iface *iface, u32 type, u32 req,
> +		     void *data, size_t size, void *resp_buf, size_t resp_size)
> +{

[ ... ]

> +	/* Only one command can be in flight per interface */
> +	if (WARN_ON(iface->out_report != -1)) {
> +		spin_unlock_irqrestore(&iface->out_lock, flags);
> +		return -EBUSY;
> +	}

[Severity: High]
Can userspace easily trigger this WARN_ON and spam the kernel log by issuing
concurrent hidraw ioctls? Furthermore, is there a race window here? In
dchid_handle_ack(), iface->out_report is cleared before the waiting thread
completes its cleanup. This could allow a second concurrent thread to bypass
this check and set up its own command, only to have its state clobbered when
the first thread finally wakes up.

[ ... ]

> +static int dchid_set_report(struct dchid_iface *iface, void *buf, size_t len)
> +{
> +	return dchid_cmd(iface, HID_OUTPUT_REPORT, REQ_SET_REPORT, buf, len,
> +			 NULL, 0);
> +}

[Severity: Medium]
Does returning the result of dchid_cmd() here cause false short-write errors
for userspace? The HID core expects the raw_request function for a SET_REPORT
call to return the number of bytes written (the requested length). However,
dchid_cmd() returns the length of the device's ACK payload, which is typically
just 1 byte.

[ ... ]

> +static int dchid_raw_request(struct hid_device *hdev, unsigned char reportnum,
> +			     __u8 *buf, size_t len, unsigned char rtype,
> +			     int reqtype)
> +{
> +	struct dchid_iface *iface = hdev->driver_data;
> +
> +	switch (reqtype) {
> +	case HID_REQ_GET_REPORT:
> +		if (len < 1)
> +			return -EINVAL;
> +
> +		buf[0] = reportnum;
> +		return dchid_cmd(iface, rtype, REQ_GET_REPORT, &reportnum, 1,
> +				 buf + 1, len - 1);

[Severity: High]
Could this return an unvalidated length from the device and lead to an
out-of-bounds heap read? In dchid_handle_ack(), iface->resp_size is
overwritten with the hardware-supplied sub_len. If the device sends a
response larger than the requested length, dchid_cmd() returns that larger
value, and hidraw_ioctl() will use it as the count for copy_to_user(),
reading past the end of the allocated buffer.

[ ... ]

> +static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc,
> +				    size_t desc_len)
> +{
> +	u8 *rdesc;
> +	int i;
> +
> +	if (iface->hid)
> +		return;
> +
> +	rdesc = devm_kmemdup(iface->dchid->dev, hid_desc, desc_len,
> +			     GFP_KERNEL);
> +	if (!rdesc)
> +		return;

[Severity: High]
Can a misbehaving device exhaust kernel memory by flooding the host with
descriptor packets? The devm_kmemdup() allocation is performed without checking
if iface->hid_desc is already allocated or freeing the previous pointer. Since
the check for iface->hid only bypasses this once asynchronous registration
completes, a rapid stream of packets before that point could leak memory.

[ ... ]

> +static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr,
> +			     void *data)
> +{

[ ... ]

> +	if (shdr->flags == iface->out_flags && iface->tx_seq == hdr->seq &&
> +	    iface->out_report == payload[0]) {
> +		if (iface->resp_buf && iface->resp_size)
> +			memcpy(iface->resp_buf, payload + 1,
> +			       min_t(size_t, sub_len - 1, iface->resp_size));
> +
> +		iface->resp_size = sub_len;

[Severity: High]
Is it safe to unconditionally overwrite iface->resp_size with the unvalidated
sub_len from the device here? This causes the calling function to believe more
bytes were read than actually requested, setting up the info leak mentioned
earlier in dchid_raw_request().

[ ... ]

> +static void dchid_process_packet(struct dchid_dev *dchid, struct dchid_hdr *hdr,
> +				 u8 *payload, size_t payload_len, u8 *packet,
> +				 size_t packet_len)
> +{
> +	struct dchid_work *work;
> +
> +	if (dchid_checksum(packet, packet_len) != DCHID_CHECKSUM_SEED) {
> +		dev_err_ratelimited(dchid->dev, "checksum error\n");
> +		return;
> +	}
> +
> +	if (payload_len < sizeof(struct dchid_subhdr))
> +		return;
> +
> +	if (hdr->iface >= MAX_INTERFACES || !dchid->ifaces[hdr->iface])
> +		return;

[Severity: High]
Does reading the dchid->ifaces array locklessly in the RX interrupt context
require an acquire barrier? Without READ_ONCE() and corresponding release
semantics on the writer side, a weakly ordered architecture could see a
non-NULL pointer but read uninitialized memory for fields like the workqueue,
leading to a crash.

[ ... ]

> +static int dchid_probe(struct platform_device *pdev)
> +{

[ ... ]

> +	dchid->new_iface_wq = alloc_ordered_workqueue("dchid-new", 0);
> +	if (!dchid->new_iface_wq)
> +		return dev_err_probe(dev, -ENOMEM, "failed to allocate workqueue\n");

[Severity: Medium]
Will this error path leave the ASC coprocessor running and RTKit awake? If
probe fails here after the hardware is started, it returns without calling
apple_rtkit_quiesce() or writing 0 to the control register, which could leak
resources or drain power.

[ ... ]

> +static void dchid_remove(struct platform_device *pdev)
> +{
> +	struct dchid_dev *dchid = platform_get_drvdata(pdev);
> +	int i;
> +
> +	if (dchid->dc_mbox) {
> +		devm_release_action(&pdev->dev, dchid_free_mbox, dchid->dc_mbox);
> +		dchid->dc_mbox = NULL;
> +	}

[Severity: High]
Does freeing the mailbox channel early here introduce a use-after-free risk?
The HID devices and workqueues are still active at this point. If a userspace
process continues to access the HID device concurrently, or if a pending work
item executes and calls dchid_send(), they will attempt to dereference the
freed mailbox channel. Should the teardown order be reversed to destroy
consumers first?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260630-apple-mtp-keyboard-final-v1-0-506d936a1707@gmail.com?part=8

  parent reply	other threads:[~2026-06-30 13:58 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-30 12:54 [PATCH 00/10] Add support for Apple Silicon DockChannel internal keyboards Michael Reeves via B4 Relay
2026-06-30 12:54 ` Michael Reeves
2026-06-30 12:54 ` [PATCH 01/10] dt-bindings: mailbox: Add Apple t8122 ASC mailbox Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 17:05   ` Conor Dooley
2026-06-30 12:54 ` [PATCH 02/10] dt-bindings: mailbox: apple: Add DockChannel mailbox Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 17:07   ` Conor Dooley
2026-07-01 14:35     ` Michael Reeves
2026-06-30 12:54 ` [PATCH 03/10] dt-bindings: iommu: apple,dart: Add t8122 compatible Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 17:07   ` Conor Dooley
2026-06-30 12:54 ` [PATCH 04/10] dt-bindings: input: apple: Add DockChannel HID transport Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 13:10   ` sashiko-bot
2026-06-30 17:08   ` Conor Dooley
2026-07-01 14:36     ` Michael Reeves
2026-06-30 12:54 ` [PATCH 05/10] mailbox: apple: Add DockChannel FIFO controller Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-07-04 20:14   ` Yureka Lilian
2026-07-07 13:42     ` Michael Reeves
2026-06-30 12:54 ` [PATCH 06/10] soc: apple: rtkit: Add tracekit endpoint Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 12:54 ` [PATCH 07/10] HID: apple: Add support for DockChannel HID keyboards Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 13:41   ` Sasha Finkelstein
2026-07-01 14:01     ` Michael Reeves
2026-06-30 13:43   ` sashiko-bot
2026-06-30 12:54 ` [PATCH 08/10] HID: apple: Add DockChannel HID transport driver Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 13:21   ` Yureka Lilian
2026-07-01 14:32     ` Michael Reeves
2026-06-30 13:58   ` sashiko-bot [this message]
2026-07-02 19:32   ` Julian Braha
2026-07-07 13:37     ` Michael Reeves
2026-06-30 12:54 ` [PATCH 09/10] arm64: dts: apple: Add MTP DockChannel HID nodes Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves
2026-06-30 12:54 ` [PATCH 10/10] arm64: dts: apple: Enable DockChannel HID on M2 and M3 laptops Michael Reeves via B4 Relay
2026-06-30 12:54   ` Michael Reeves

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=20260630135803.F39741F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=devnull+michael.reeves077.gmail.com@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=robh@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.