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
616 unsigned int presence_offset;616 unsigned int presence_offset;
617 unsigned int map_offset;617 unsigned int map_offset;
618 unsigned int offset;618 unsigned int offset;
619 unsigned int num_registers;
619 unsigned int reg;620 unsigned int reg;
620 int i;
621 int b;621 int b;
622 int ret;622 int ret;
623 623
@@ -657,7 +657,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, · 33 unmodified lines
657 657
658 memset(presence_map, 0, sizeof(presence_map));658 memset(presence_map, 0, sizeof(presence_map));
659 map_offset = 0;659 map_offset = 0;
660 for (i = presence_offset; i < size_presence_reg; i++) {660 for (int i = presence_offset; i < size_presence_reg; i++) {
661 for (b = 0; b < 8; b++) {661 for (b = 0; b < 8; b++) {
662 if (buf[i] & BIT(b)) {662 if (buf[i] & BIT(b)) {
663 if (map_offset >= RMI_REG_DESC_PRESENCE_BITS)663 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
697 if (ret)697 if (ret)
698 return ret;698 return ret;
699 699
700 reg = find_first_bit(presence_map, RMI_REG_DESC_PRESENCE_BITS);
701 offset = 0;700 offset = 0;
702 for (i = 0; i < rdesc->num_registers; i++) {701 num_registers = 0;
703 struct rmi_register_desc_item *item = &rdesc->registers[i];702 for_each_set_bit(reg, presence_map, RMI_REG_DESC_PRESENCE_BITS) {
703 struct rmi_register_desc_item *item = &rdesc->registers[num_registers];
704 int item_size;704 int item_size;
705 705
706 if (offset >= rdesc->struct_size)
707 break;
708
706 item_size = rmi_parse_register_desc_item(item,709 item_size = rmi_parse_register_desc_item(item,
707 &struct_buf[offset],710 &struct_buf[offset],
708 rdesc->struct_size - offset);711 rdesc->struct_size - offset);
709 if (item_size < 0)712 if (item_size < 0) {
710 return item_size;713 dev_warn(&d->dev,
714 "%s: Failed to parse register %d descriptor, ignoring it\n",
715 __func__, reg);
716 break;
717 }
711 718
712 item->reg = reg;719 item->reg = reg;
713 offset += item_size;720 offset += item_size;
714 721
715 rmi_dbg(RMI_DEBUG_CORE, &d->dev,722 if (item->reg_size == 0) {
716 "%s: reg: %d reg size: %u subpackets: %d\n", __func__,723 dev_warn(&d->dev,
717 item->reg, item->reg_size, item->num_subpackets);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);
718 730
719 reg = find_next_bit(presence_map,731 num_registers++;
720 RMI_REG_DESC_PRESENCE_BITS, reg + 1);732 }
721 }733 }
734 rdesc->num_registers = num_registers;
722 735
723 return 0;736 return 0;
724}737}

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