From b946f490be576691c4c47998cf1d4e41d637fbfb Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Thu, 13 Aug 2026 23:23:57 +0800 Subject: [PATCH] thunderbolt: Require complete DROM entry headers tb_drom_parse_entries() checks for one byte remaining before reading a DROM entry header, but the header occupies two bytes. It also accepts a declared length of one byte. A one-byte tail consequently makes the parser read entry->len outside the DROM. A one-byte generic string entry reaches the subtype parser and underflows its payload-length calculation. Require a complete entry header before reading it and require the declared entry length to cover that header. Use subtraction-based bounds checks so the firmware-provided length cannot overflow the DROM extent calculation. While at it, use the actual const type instead of void * to make it clear we only read these. Assisted-by: Codex:gpt-5 Signed-off-by: Pengpeng Hou Signed-off-by: Mika Westerberg --- drivers/thunderbolt/eeprom.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 2a13fa6888ba..2acfe83928b6 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -324,7 +324,7 @@ int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid) } static int tb_drom_parse_entry_generic(struct tb_switch *sw, - struct tb_drom_entry_header *header) + const struct tb_drom_entry_header *header) { const struct tb_drom_entry_generic *entry = (const struct tb_drom_entry_generic *)header; @@ -360,7 +360,7 @@ static int tb_drom_parse_entry_generic(struct tb_switch *sw, } static int tb_drom_parse_entry_port(struct tb_switch *sw, - struct tb_drom_entry_header *header) + const struct tb_drom_entry_header *header) { struct tb_port *port; int res; @@ -386,11 +386,13 @@ static int tb_drom_parse_entry_port(struct tb_switch *sw, type &= 0xffffff; if (type == TB_TYPE_PORT) { - struct tb_drom_entry_port *entry = (void *) header; + const struct tb_drom_entry_port *entry = + (const struct tb_drom_entry_port *)header; + if (header->len != sizeof(*entry)) { tb_sw_warn(sw, "port entry has size %#x (expected %#zx)\n", - header->len, sizeof(struct tb_drom_entry_port)); + header->len, sizeof(*entry)); return -EIO; } port->link_nr = entry->link_nr; @@ -421,9 +423,16 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size) int res; while (pos < drom_size) { - struct tb_drom_entry_header *entry = (void *) (sw->drom + pos); - if (pos + 1 == drom_size || pos + entry->len > drom_size - || !entry->len) { + const struct tb_drom_entry_header *entry; + + if (drom_size - pos < sizeof(*entry)) { + tb_sw_warn(sw, "DROM buffer overrun\n"); + return -EIO; + } + + entry = (const struct tb_drom_entry_header *)(sw->drom + pos); + if (entry->len < sizeof(*entry) || + entry->len > drom_size - pos) { tb_sw_warn(sw, "DROM buffer overrun\n"); return -EIO; }