* [PATCH] Input: apple_z2 - bound the device-reported packet length
@ 2026-06-13 21:42 Bryam Vargas via B4 Relay
2026-06-13 21:53 ` sashiko-bot
2026-06-13 21:57 ` Sasha Finkelstein
0 siblings, 2 replies; 3+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-06-13 21:42 UTC (permalink / raw)
To: Dmitry Torokhov, Sasha Finkelstein
Cc: linux-arm-kernel, Neal Gompa, linux-input, asahi, linux-kernel,
Sven Peter, Janne Grunau
From: Bryam Vargas <hexlabsecurity@proton.me>
apple_z2_read_packet() takes a 16-bit length from the touch controller's
interrupt-data reply (rx_buf[1..2]) and, only rounded down to a multiple of
four, uses it as the size of the second SPI transfer into the fixed-size
rx_buf:
pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
rx_buf is a fixed 4000-byte buffer, but pkt_len is fully controlled by the
device and is never checked against it, so a malicious, malfunctioning or
counterfeit controller (or an interposer on the SPI bus) that reports a
large length makes spi_read() write up to 65540 device-supplied bytes into
the 4000-byte buffer -- a controller-driven heap out-of-bounds write of up
to about 61 KiB. The recently added reply-type check only validates
rx_buf[0], not the length.
Reject any packet whose length exceeds the receive buffer.
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
Reachable on every touch interrupt once the controller is booted
(apple_z2_irq -> apple_z2_read_packet).
Verified with a faithful in-kernel KASAN litmus (the verbatim 4000-byte
allocation, the exact pkt_len computation, and the spi_read transfer modelled
as a memset of pkt_len controller bytes), CONFIG_KASAN_INLINE=y:
Arm A, reported length 0x1000 -> pkt_len 4104:
BUG: KASAN: slab-out-of-bounds in apple_z2_read_packet
Write of size 4104 ... located 0 bytes inside of allocated 4000-byte region
... which belongs to the cache kmalloc-4k of size 4096
Arm B, with this patch (length rejected): clean
Arm C, benign length: clean
AddressSanitizer (x86_64 and i386), reported length 0xffff -> pkt_len 65540:
heap-buffer-overflow WRITE of size 65540, both ABIs.
Reproducer and full logs available on request.
---
drivers/input/touchscreen/apple_z2.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index 271ababf0ad5..ff9ff97be185 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -22,6 +22,7 @@
#define APPLE_Z2_TOUCH_MOVED 4
#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
#define APPLE_Z2_REPLY_INTERRUPT_DATA 0xE1
+#define APPLE_Z2_MAX_PACKET 4000
#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
#define APPLE_Z2_FW_MAGIC 0x5746325A
#define LOAD_COMMAND_INIT_PAYLOAD 0
@@ -147,6 +148,8 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
return 0;
pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
+ if (pkt_len > APPLE_Z2_MAX_PACKET)
+ return -EMSGSIZE;
error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
if (error)
@@ -363,7 +366,7 @@ static int apple_z2_probe(struct spi_device *spi)
if (!z2->tx_buf)
return -ENOMEM;
/* 4096 will end up being rounded up to 8192 due to devres header */
- z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
+ z2->rx_buf = devm_kzalloc(dev, APPLE_Z2_MAX_PACKET, GFP_KERNEL);
if (!z2->rx_buf)
return -ENOMEM;
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260613-b4-disp-b1926f1a-caad8f942af9
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] Input: apple_z2 - bound the device-reported packet length
2026-06-13 21:42 [PATCH] Input: apple_z2 - bound the device-reported packet length Bryam Vargas via B4 Relay
@ 2026-06-13 21:53 ` sashiko-bot
2026-06-13 21:57 ` Sasha Finkelstein
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-06-13 21:53 UTC (permalink / raw)
To: Bryam Vargas via B4 Relay; +Cc: linux-input, dmitry.torokhov
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing bounds check on the number of fingers (`nfingers`) reported by the device in `apple_z2_parse_touches` leads to a kernel heap out-of-bounds read and potential information leak.
- [High] Concurrent execution of `apple_z2_read_packet()` from the probe/resume thread and the IRQ handler causes a data race and shared SPI buffer corruption.
- [Medium] If `apple_z2_boot()` times out waiting for the boot IRQ, it returns directly without disabling the IRQ or reverting the hardware reset state, leading to state inconsistencies.
- [Low] The input device is registered and exposed to userspace before the hardware is initialized and firmware is uploaded, violating input subsystem readiness rules.
--
commit 0ef574cc6b6df1efb30f7e523d3cf505e551ae3c
Author: Bryam Vargas <hexlabsecurity@proton.me>
Input: apple_z2 - bound the device-reported packet length
apple_z2_read_packet() takes a 16-bit length from the touch controller's
interrupt-data reply and uses it as the size of the second SPI transfer into
the fixed-size rx_buf. This bounds the device-reported packet length to reject
any packet whose length exceeds the receive buffer.
> diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
> index 271ababf0ad55..ff9ff97be185a 100644
> --- a/drivers/input/touchscreen/apple_z2.c
> +++ b/drivers/input/touchscreen/apple_z2.c
[ ... ]
> @@ -147,6 +148,8 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
> return 0;
>
> pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
> + if (pkt_len > APPLE_Z2_MAX_PACKET)
> + return -EMSGSIZE;
>
> error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
> if (error)
[Severity: High]
This isn't a bug introduced by this patch, but does apple_z2_parse_touches()
lack a bounds check on the number of fingers?
It appears that apple_z2_parse_touches() reads the unvalidated nfingers count
from msg[APPLE_Z2_NUM_FINGERS_OFFSET] and blindly iterates over it:
drivers/input/touchscreen/apple_z2.c:apple_z2_parse_touches() {
...
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
for (i = 0; i < nfingers; i++) {
...
}
Could a spoofed device set nfingers to 255, causing the loop to read
out-of-bounds past the rx_buf allocation, and potentially leading to an
information leak when those bytes are parsed as touch coordinates?
[Severity: High]
This is a pre-existing issue, but is there a data race when
apple_z2_read_packet() is executed concurrently?
In apple_z2_boot(), the device interrupt is unmasked via enable_irq() before
firmware is uploaded. Then in apple_z2_upload_firmware(), the driver sets
z2->booted = true and manually calls apple_z2_read_packet().
If the device asserts the interrupt concurrently, the threaded IRQ handler
apple_z2_irq() will wake up, observe z2->booted == true, and also invoke
apple_z2_read_packet().
Since there is no lock protecting apple_z2_read_packet(), could this
concurrently overwrite z2->tx_buf, mutate z2->index_parity, and corrupt the
shared SPI buffers?
[ ... ]
> @@ -363,7 +366,7 @@ static int apple_z2_probe(struct spi_device *spi)
> if (!z2->tx_buf)
> return -ENOMEM;
> /* 4096 will end up being rounded up to 8192 due to devres header */
> - z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
> + z2->rx_buf = devm_kzalloc(dev, APPLE_Z2_MAX_PACKET, GFP_KERNEL);
> if (!z2->rx_buf)
> return -ENOMEM;
[Severity: Medium]
This is a pre-existing issue, but does apple_z2_boot() miss cleanup when
wait_for_completion_timeout() fails?
In apple_z2_boot(), the IRQ enable depth is incremented and the device is
taken out of reset. If it times out waiting for the boot_irq completion, it
directly returns -ETIMEDOUT:
drivers/input/touchscreen/apple_z2.c:apple_z2_boot() {
...
if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)))
return -ETIMEDOUT;
...
}
If this happens during apple_z2_resume(), devm teardown does not occur. Does
this leave the IRQ permanently enabled and the reset GPIO active, leading to
state inconsistency?
[Severity: Low]
This is a pre-existing issue, but is the input device registered before the
hardware is fully initialized?
In apple_z2_probe(), input_register_device() is called before apple_z2_boot()
has completed:
drivers/input/touchscreen/apple_z2.c:apple_z2_probe() {
...
error = input_register_device(z2->input_dev);
if (error)
return dev_err_probe(dev, error, "unable to register input device\n");
/* Wait for device reset to finish */
usleep_range(5000, 10000);
error = apple_z2_boot(z2);
...
}
If apple_z2_boot() fails, the momentarily registered device is removed. Does
this expose an uninitialized device to userspace prematurely?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260613-b4-disp-b1926f1a-v1-1-3a277b7c0cfa@proton.me?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Input: apple_z2 - bound the device-reported packet length
2026-06-13 21:42 [PATCH] Input: apple_z2 - bound the device-reported packet length Bryam Vargas via B4 Relay
2026-06-13 21:53 ` sashiko-bot
@ 2026-06-13 21:57 ` Sasha Finkelstein
1 sibling, 0 replies; 3+ messages in thread
From: Sasha Finkelstein @ 2026-06-13 21:57 UTC (permalink / raw)
To: hexlabsecurity
Cc: Dmitry Torokhov, linux-arm-kernel, Neal Gompa, linux-input, asahi,
linux-kernel, Sven Peter, Janne Grunau
> On Jun 13, 2026, at 23:42, Bryam Vargas via B4 Relay <devnull+hexlabsecurity.proton.me@kernel.org> wrote:
>
> From: Bryam Vargas <hexlabsecurity@proton.me>
>
> [...]
> Reject any packet whose length exceeds the receive buffer.
>
Reviewed-by: Sasha Finkelstein <k@chaosmail.tech>
Although, if you reject the packet, the datastream will be desynced and
the device should be reset before it can operate again.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-13 21:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-13 21:42 [PATCH] Input: apple_z2 - bound the device-reported packet length Bryam Vargas via B4 Relay
2026-06-13 21:53 ` sashiko-bot
2026-06-13 21:57 ` Sasha Finkelstein
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox