[PATCH] drm/i915/bios: validate VBT vswing/preemphasis override table

From: Noah Weinberger

Date: Sun Nov 08 2026 - 17:36:09 EST


Hello,

Proposed-fix limitation: the patch below does not validate the full
VBT table extent against the section size. The malformed/short-table
out-of-bounds case described below remains unresolved by these
existence and minimum-count checks. This is an incomplete proposal for
maintainer review; a complete fix still needs section-extent bounds
validation.

parse_vswing_preemph_override() stores the raw pointer and count fields
from VBT block 57 without validating that the block actually contains
the announced table, and allocate_vswing_preemph_override() allocates
the consumer structures whenever a child device sets use_vbt_vswing -
even when the block is absent entirely. validate_vspeo() only checks
that devdata->vspeo is non-NULL and that the port has DP.

Two failure modes follow at DDI buffer-translation time:
- block absent: tables == NULL, num_columns == 0, so the consumer
dereferences tables[0] (NULL).
- block short or malformed: the table walk reads up to
(5+1)*num_rows*num_columns u32s from a block whose enforced minimum
size is 2 bytes - with num_columns = 255 that is ~98 KB past a small
heap allocation, and the values are programmed into PHY registers.

The patch gates the consumer on the table existing with sane counts.
A complete fix should also validate the table extent against the
section size, which is not currently plumbed through; happy to rework
if there is a preferred way to carry the section size.

Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), drivers/gpu/drm/i915/display/intel_bios.c:2216-2234 (parse), 2654-2676 (allocate), 3874-3923 (validate/consume).
Introduced in the v7.4 merge window.

This was found during an assisted (AI-supported) static source review of
mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
reporter against that tree. The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.

Reported-by: Noah Weinberger <noahweinberger2003@xxxxxxxxx>
---
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 7b6a6f8..d99a675 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2657,7 +2657,8 @@ static void allocate_vswing_preemph_override(struct intel_bios_encoder_data *dev
union intel_ddi_buf_trans_entry *entries;
struct intel_ddi_buf_trans *vspeo;

- if (!intel_bios_encoder_requests_vspeo(devdata))
+ if (!intel_bios_encoder_requests_vspeo(devdata) ||
+ !devdata->display->vbt.vspeo.tables)
return;

vspeo = kzalloc_obj(*vspeo);
@@ -3876,6 +3877,8 @@ validate_vspeo(const struct intel_bios_encoder_data *devdata, bool has_dp)
{
struct intel_ddi_buf_trans *vspeo;

+ struct intel_display *display = devdata->display;
+
vspeo = devdata->vspeo;
if (!vspeo)
return false;
@@ -3883,5 +3886,10 @@ validate_vspeo(const struct intel_bios_encoder_data *devdata, bool has_dp)
if (!has_dp)
return false;

+ if (!display->vbt.vspeo.tables ||
+ display->vbt.vspeo.num_columns < 3 ||
+ display->vbt.vspeo.num_tables < 6)
+ return false;
+
return true;
}