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 <pengpeng@iscas.ac.cn>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Pengpeng Hou 2026-08-13 23:23:57 +08:00 committed by Mika Westerberg
parent ae35035da9
commit b946f490be

View File

@ -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;
}