[PATCH 2/2] Input: synaptics-rmi4 - reject a PDT that grows between scans

From: Wei Jie Law

Date: Mon Aug 24 2026 - 01:51:49 EST


rmi_driver_probe() walks the Page Description Table three times, and each
walk reads the table back from the device:

1. rmi_initial_reset - issue the reset command in the F01 entry
2. rmi_count_irqs - total the interrupt sources
3. rmi_create_function - create the functions and set their irq bits

Scan 2 fixes data->irq_count, data->num_of_irq_regs and the size of every
per-function irq_mask[]. Scan 3 then accumulates fn->irq_pos and does

for (i = 0; i < fn->num_of_irqs; i++)
set_bit(fn->irq_pos + i, fn->irq_mask);

without checking the result against the count that sized the bitmap.
Nothing makes the device answer the third scan the way it answered the
second, so a device that reports one function with one interrupt source
on scan 2 and a long list of functions on scan 3 walks set_bit() past the
end of the flexible array at the tail of every struct rmi_function:

BUG: KASAN: slab-out-of-bounds in rmi_create_function+0x560/0x930 [rmi_core]
Write of size 8 at addr ffff888110c92b58 by task kworker/1:2/129
Workqueue: events uhid_device_add_worker
kasan_report+0xc6/0x100
kasan_check_range+0x105/0x1b0
rmi_create_function+0x560/0x930 [rmi_core]
rmi_scan_pdt+0x190/0x3f0 [rmi_core]
rmi_init_functions+0xb8/0x320 [rmi_core]
rmi_driver_probe+0x31e/0xbf0 [rmi_core]

one report per corrupted function object. The same unvalidated
fn->irq_pos is used again by the set_bit() and irq_create_mapping() in
rmi_create_function_irq().

Validate the position before using it and fail the probe instead. The
check is exact, not conservative: when both scans see the same table,
fn->irq_pos + fn->num_of_irqs is the running total that produced
data->irq_count, so it never fires for a device that behaves.

Reproduced with an emulated RMI4 device driven over /dev/uhid, and again
over dummy_hcd plus raw-gadget, on v6.12.69 booted slub_debug=FZPU and on
v6.12.105 built with CONFIG_KASAN=y. After this change the same device
gets

rmi4_physical rmi4-03: F40: interrupt count changed between PDT
scans (pos 1 + 6 > 1)
rmi4_physical rmi4-03: Function creation failed with code -22.

and a device that answers both scans consistently still probes normally.

Fixes: 2b6a321da9a2 ("Input: synaptics-rmi4 - add support for Synaptics RMI4 devices")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wei Jie Law <98lawweijie@xxxxxxxxx>
---
drivers/input/rmi4/rmi_driver.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 5d49a9021c7d..c0e91a372eff 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -899,6 +899,24 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
fn->irq_pos = *current_irq_count;
*current_irq_count += fn->num_of_irqs;

+ /*
+ * irq_mask[] was sized from the interrupt count collected by the
+ * earlier rmi_count_irqs() scan of the PDT. Nothing guarantees that
+ * this scan sees the same table -- the PDT is read back from the
+ * device every time -- so a device that grows its interrupt counts
+ * between the two scans would push these set_bit() calls past the end
+ * of the flexible array. Refuse the function instead.
+ */
+ if (fn->num_of_irqs > RMI_FN_MAX_IRQS ||
+ fn->irq_pos + fn->num_of_irqs > data->irq_count) {
+ dev_err(dev,
+ "F%02X: interrupt count changed between PDT scans (pos %u + %u > %d)\n",
+ pdt->function_number, fn->irq_pos, fn->num_of_irqs,
+ data->irq_count);
+ put_device(&fn->dev);
+ return -EINVAL;
+ }
+
for (i = 0; i < fn->num_of_irqs; i++)
set_bit(fn->irq_pos + i, fn->irq_mask);

--
2.43.0