From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: linux-input@vger.kernel.org
Cc: Marge Yang <Marge.Yang@tw.synaptics.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH 1/2] Input: rmi4 - refactor register descriptor parsing
Date: Mon, 27 Apr 2026 18:09:15 -0700 [thread overview]
Message-ID: <20260428010917.1320927-1-dmitry.torokhov@gmail.com> (raw)
Factor out parsing a register descriptor item from
rmi_read_register_desc() and ensure there are no out-of-bounds accesses.
Use get_unaligned_le16() and get_unaligned_le32() for reading multi-byte
values.
Reported-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Fixes: 2b6a321da9a2 ("Input: synaptics-rmi4 - add support for Synaptics RMI4 devices")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/rmi4/rmi_driver.c | 119 ++++++++++++++++++++------------
1 file changed, 73 insertions(+), 46 deletions(-)
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index ccd9338a44db..9871e9b816dc 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -22,6 +22,7 @@
#include <uapi/linux/input.h>
#include <linux/rmi.h>
#include <linux/export.h>
+#include <linux/unaligned.h>
#include "rmi_bus.h"
#include "rmi_driver.h"
@@ -558,30 +559,74 @@ int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
return retval < 0 ? retval : 0;
}
+static int rmi_parse_register_desc_item(struct rmi_register_desc_item *item,
+ const u8 *buf, size_t size)
+{
+ int offset = 0;
+ int map_offset = 0;
+ int b;
+
+ if (offset >= size)
+ return -EIO;
+
+ item->reg_size = buf[offset++];
+ if (item->reg_size == 0) {
+ if (size - offset < 2)
+ return -EIO;
+ item->reg_size = get_unaligned_le16(&buf[offset]);
+ offset += 2;
+ }
+
+ if (item->reg_size == 0) {
+ if (size - offset < 4)
+ return -EIO;
+ item->reg_size = get_unaligned_le32(&buf[offset]);
+ offset += 4;
+ }
+
+ do {
+ if (offset >= size)
+ return -EIO;
+
+ for (b = 0; b < 7; b++) {
+ if (buf[offset] & BIT(b)) {
+ if (map_offset >= RMI_REG_DESC_SUBPACKET_BITS)
+ return -EIO;
+ bitmap_set(item->subpacket_map, map_offset, 1);
+ }
+ ++map_offset;
+ }
+ } while (buf[offset++] & 0x80);
+
+ item->num_subpackets = bitmap_weight(item->subpacket_map,
+ RMI_REG_DESC_SUBPACKET_BITS);
+
+ return offset;
+}
+
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
- struct rmi_register_descriptor *rdesc)
+ struct rmi_register_descriptor *rdesc)
{
int ret;
u8 size_presence_reg;
u8 buf[35];
- int presense_offset = 1;
- u8 *struct_buf;
+ int presence_offset;
int reg;
int offset = 0;
- int map_offset = 0;
+ int map_offset;
int i;
int b;
/*
* The first register of the register descriptor is the size of
- * the register descriptor's presense register.
+ * the register descriptor's presence register.
*/
ret = rmi_read(d, addr, &size_presence_reg);
if (ret)
return ret;
++addr;
- if (size_presence_reg < 0 || size_presence_reg > 35)
+ if (size_presence_reg < 1 || size_presence_reg > 35)
return -EIO;
memset(buf, 0, sizeof(buf));
@@ -597,16 +642,23 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
++addr;
if (buf[0] == 0) {
- presense_offset = 3;
- rdesc->struct_size = buf[1] | (buf[2] << 8);
+ if (size_presence_reg < 3)
+ return -EIO;
+ presence_offset = 3;
+ rdesc->struct_size = get_unaligned_le16(&buf[1]);
} else {
+ presence_offset = 1;
rdesc->struct_size = buf[0];
}
- for (i = presense_offset; i < size_presence_reg; i++) {
+ map_offset = 0;
+ for (i = presence_offset; i < size_presence_reg; i++) {
for (b = 0; b < 8; b++) {
- if (buf[i] & (0x1 << b))
+ if (buf[i] & BIT(b)) {
+ if (map_offset >= RMI_REG_DESC_PRESENSE_BITS)
+ return -EIO;
bitmap_set(rdesc->presense_map, map_offset, 1);
+ }
++map_offset;
}
}
@@ -626,7 +678,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
* I'm not using devm_kzalloc here since it will not be retained
* after exiting this function
*/
- struct_buf = kzalloc(rdesc->struct_size, GFP_KERNEL);
+ u8 *struct_buf __free(kfree) = kzalloc(rdesc->struct_size, GFP_KERNEL);
if (!struct_buf)
return -ENOMEM;
@@ -638,56 +690,31 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
*/
ret = rmi_read_block(d, addr, struct_buf, rdesc->struct_size);
if (ret)
- goto free_struct_buff;
+ return ret;
reg = find_first_bit(rdesc->presense_map, RMI_REG_DESC_PRESENSE_BITS);
for (i = 0; i < rdesc->num_registers; i++) {
struct rmi_register_desc_item *item = &rdesc->registers[i];
- int reg_size = struct_buf[offset];
+ int item_size;
- ++offset;
- if (reg_size == 0) {
- reg_size = struct_buf[offset] |
- (struct_buf[offset + 1] << 8);
- offset += 2;
- }
-
- if (reg_size == 0) {
- reg_size = struct_buf[offset] |
- (struct_buf[offset + 1] << 8) |
- (struct_buf[offset + 2] << 16) |
- (struct_buf[offset + 3] << 24);
- offset += 4;
- }
+ item_size = rmi_parse_register_desc_item(item,
+ &struct_buf[offset],
+ rdesc->struct_size - offset);
+ if (item_size < 0)
+ return item_size;
item->reg = reg;
- item->reg_size = reg_size;
-
- map_offset = 0;
-
- do {
- for (b = 0; b < 7; b++) {
- if (struct_buf[offset] & (0x1 << b))
- bitmap_set(item->subpacket_map,
- map_offset, 1);
- ++map_offset;
- }
- } while (struct_buf[offset++] & 0x80);
-
- item->num_subpackets = bitmap_weight(item->subpacket_map,
- RMI_REG_DESC_SUBPACKET_BITS);
+ offset += item_size;
rmi_dbg(RMI_DEBUG_CORE, &d->dev,
"%s: reg: %d reg size: %ld subpackets: %d\n", __func__,
item->reg, item->reg_size, item->num_subpackets);
reg = find_next_bit(rdesc->presense_map,
- RMI_REG_DESC_PRESENSE_BITS, reg + 1);
+ RMI_REG_DESC_PRESENSE_BITS, reg + 1);
}
-free_struct_buff:
- kfree(struct_buf);
- return ret;
+ return 0;
}
const struct rmi_register_desc_item *rmi_get_register_desc_item(
--
2.54.0.545.g6539524ca2-goog
next reply other threads:[~2026-04-28 1:09 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 1:09 Dmitry Torokhov [this message]
2026-04-28 1:09 ` [PATCH 2/2] Input: rmi4 - fix num_subpackets overflow in register descriptor Dmitry Torokhov
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=20260428010917.1320927-1-dmitry.torokhov@gmail.com \
--to=dmitry.torokhov@gmail.com \
--cc=Marge.Yang@tw.synaptics.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@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