The legacy BIT parser finds the BIT signature and then reads the entry size, entry count and entry array directly from the VBIOS image. The signature only proves that the magic bytes are present. It does not prove that the fixed BIT header, every directory entry, or the referenced table range fits inside the VBIOS image.
Validate the BIT header, entry array and referenced table ranges before returning a legacy BIT entry to the individual table parsers. Signed-off-by: Pengpeng Hou <[email protected]> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 38032bb95826..93b035905ca2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -972,24 +972,39 @@ bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvbios *bios = &drm->vbios; - u8 entries, *entry; + u32 entry_size, entries, offset; + u8 *entry; if (bios->type != NVBIOS_BIT) return -ENODEV; + if (bios->offset > bios->length || bios->length - bios->offset < 12) + return -EINVAL; + + entry_size = bios->data[bios->offset + 9]; entries = bios->data[bios->offset + 10]; - entry = &bios->data[bios->offset + 12]; + if (entry_size < 6 || + entries > (bios->length - bios->offset - 12) / entry_size) + return -EINVAL; + + entry = &bios->data[bios->offset + 12]; while (entries--) { if (entry[0] == id) { bit->id = entry[0]; bit->version = entry[1]; bit->length = ROM16(entry[2]); bit->offset = ROM16(entry[4]); + + offset = bit->offset; + if (offset > bios->length || + bit->length > bios->length - offset) + return -EINVAL; + bit->data = ROMPTR(dev, entry[4]); return 0; } - entry += bios->data[bios->offset + 9]; + entry += entry_size; } return -ENOENT; -- 2.43.0
