From: Rene Rebe Subject: [PATCH] drm/nouveau/bios: fix shadowing on boards with a distant or absent PCIR The BIOS shadowing code prefetches only the first 0x1000 bytes of a candidate ROM image before parsing its header. Header parsing follows the PCI data structure pointer stored at offset 0x18 of the image, so any image whose PCIR lives beyond the first 4KiB is dereferenced past the end of the fetched data: nouveau 0000:00:08.0: bios: OOB 4 00003b31 00003b31 nouveau 0000:00:08.0: bios: OOB 4 00003b31 00003b31 nouveau 0000:00:08.0: bios: OOB 4 00003b31 00003b31 nouveau 0000:00:08.0: bios: unable to locate usable image nouveau 0000:00:08.0: bios ctor failed: -22 nouveau 0000:00:08.0: probe with driver nouveau failed with error -22 The out-of-bounds read returns 0, the PCIR signature check fails, and the image is rejected - for every source that is tried (PRAMIN, PROM, PCIROM), leaving no usable image at all. Seen on a RIVA TNT (NV04). Fetch up to the PCI data structure (and the NPDE which may follow it) before the header is parsed. A failure to do so is not fatal: the regular header parsing still gets to reject the image, just without the alarming OOB error. Additionally, fall back to the image size from the legacy ROM header for the first image of a pre-nv50 board when no usable PCI data structure is present at all. The checksum test in shadow_image() still decides whether such an image is accepted. --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c | 17 +++++++++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -60,13 +60,27 @@ image.type = 0; image.size = mthd->func->size(mthd->data); image.last = 1; } else { + u32 pcir; + if (!shadow_fetch(bios, mthd, offset + 0x1000)) { nvkm_debug(subdev, "%08x: header fetch failed\n", offset); return 0; } + /* The PCI data structure is not required to live within the + * first 4KiB of the image, so fetch up to it (and the NPDE + * that may follow it) before the header is parsed. Failure + * is not fatal here, the header parsing below will reject + * the image if the pointer turns out to be bogus. + */ + pcir = nvbios_rd16(bios, offset + 0x18); + if (pcir && offset + pcir + 0x40 > bios->size) { + if (!shadow_fetch(bios, mthd, offset + pcir + 0x40)) + shadow_fetch(bios, mthd, offset + pcir + 0x16); + } + if (!nvbios_image(bios, idx, &image)) { nvkm_debug(subdev, "image %d invalid\n", idx); return 0; --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -47,8 +47,21 @@ return false; } - if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir))) - return false; + if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir))) { + /* Some pre-nv50 boards have a missing or corrupt PCI data + * structure. Fall back to the image size from the legacy + * ROM header, there'll be no further images to find. + */ + if (image->base || subdev->device->card_type >= NV_50) + return false; + + image->size = nvbios_rd08(bios, image->base + 0x02) * 512; + image->type = 0; + image->last = true; + nvkm_debug(subdev, "%08x: no PCIR, assuming %d byte image\n", + image->base, image->size); + return image->size != 0; + } image->size = pcir.image_size; image->type = pcir.image_type; image->last = pcir.last;