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 <[email protected]> --- 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; }
