History

Input: rmi4 - tolerate short register descriptor structure

Some touchpads (e.g. ThinkPad T14 Gen 1) have buggy firmware that reports a register descriptor structure size that is too small for the number of registers it claims to have in the presence map. The remaining bytes in the structure are 0, which with the new strict bounds checking causes the parser to fail with -EIO, aborting the device probe. Tolerate such short reads by dropping the remaining (unparseable or 0-size) registers from the list instead of failing the probe, preventing the driver from trying to use them.

Dmitry Torokhov committed 4 months ago

Commit 2d6d33e1 parent d8558981 file · +25 −12Browse files

Unified · Split

drivers/input/rmi4/rmi_driver.c+25−12
@@ -616,8 +616,8 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, · 615 unmodified lines
616616 unsigned int presence_offset;
617617 unsigned int map_offset;
618618 unsigned int offset;
619+ unsigned int num_registers;
619620 unsigned int reg;
620− int i;
621621 int b;
622622 int ret;
623623
@@ -657,7 +657,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, · 33 unmodified lines
657657
658658 memset(presence_map, 0, sizeof(presence_map));
659659 map_offset = 0;
660− for (i = presence_offset; i < size_presence_reg; i++) {
660+ for (int i = presence_offset; i < size_presence_reg; i++) {
661661 for (b = 0; b < 8; b++) {
662662 if (buf[i] & BIT(b)) {
663663 if (map_offset >= RMI_REG_DESC_PRESENCE_BITS)
@@ -697,28 +697,41 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, · 33 unmodified lines
697697 if (ret)
698698 return ret;
699699
700− reg = find_first_bit(presence_map, RMI_REG_DESC_PRESENCE_BITS);
701700 offset = 0;
702− for (i = 0; i < rdesc->num_registers; i++) {
703− struct rmi_register_desc_item *item = &rdesc->registers[i];
701+ num_registers = 0;
702+ for_each_set_bit(reg, presence_map, RMI_REG_DESC_PRESENCE_BITS) {
703+ struct rmi_register_desc_item *item = &rdesc->registers[num_registers];
704704 int item_size;
705705
706+ if (offset >= rdesc->struct_size)
707+ break;
708+
706709 item_size = rmi_parse_register_desc_item(item,
707710 &struct_buf[offset],
708711 rdesc->struct_size - offset);
709− if (item_size < 0)
710− return item_size;
712+ if (item_size < 0) {
713+ dev_warn(&d->dev,
714+ "%s: Failed to parse register %d descriptor, ignoring it\n",
715+ __func__, reg);
716+ break;
717+ }
711718
712719 item->reg = reg;
713720 offset += item_size;
714721
715− rmi_dbg(RMI_DEBUG_CORE, &d->dev,
716− "%s: reg: %d reg size: %u subpackets: %d\n", __func__,
717− item->reg, item->reg_size, item->num_subpackets);
722+ if (item->reg_size == 0) {
723+ dev_warn(&d->dev,
724+ "%s: Register %d has 0 size, ignoring it\n",
725+ __func__, item->reg);
726+ } else {
727+ rmi_dbg(RMI_DEBUG_CORE, &d->dev,
728+ "%s: reg: %d reg size: %u subpackets: %d\n", __func__,
729+ item->reg, item->reg_size, item->num_subpackets);
718730
719− reg = find_next_bit(presence_map,
720− RMI_REG_DESC_PRESENCE_BITS, reg + 1);
731+ num_registers++;
732+ }
721733 }
734+ rdesc->num_registers = num_registers;
722735
723736 return 0;
724737 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t