[PATCH] drm/i915/gvt: validate LRCA-derived guest context range
From: Nikita Zhandarovich
Date: Fri May 29 2026 - 09:26:50 EST
The GVT execlist context handling code derives GGTT page addresses from
desc->lrca in several places:
- intel_vgpu_create_workload()
- populate_shadow_context()
- update_guest_context()
These paths translate addresses based on desc->lrca + page_index, but do
not first verify that the referenced guest context range fits in 32-bit
GMA space.
If desc->lrca is close enough (0xFFFFE, for instance) to the top
encodable page value, the page addition can exceed the representable
32-bit GMA range before the value is shifted and truncated for address
translation.
Fix this by validating the full LRCA-derived context range once during
workload creation, based on the engine context size, and reject invalid
descriptors before any GPA translation is attempted.
Found by Linux Verification Center (linuxtesting.org) with static
analysis tool SVACE.
Fixes: 28c4c6ca7f79 ("drm/i915/gvt: vGPU workload submission")
Signed-off-by: Nikita Zhandarovich <n.zhandarovich@xxxxxxxxxx>
---
drivers/gpu/drm/i915/gvt/scheduler.c | 37 ++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index 15fdd514ca83..b2c028396093 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -68,6 +68,37 @@ static void set_context_pdp_root_pointer(
ring_context->pdps[i].val = pdp[7 - i];
}
+static unsigned long
+intel_vgpu_context_page_num(struct intel_vgpu *vgpu,
+ const struct intel_engine_cs *engine)
+{
+ unsigned long context_page_num;
+
+ context_page_num = engine->context_size >> PAGE_SHIFT;
+
+ if (IS_BROADWELL(vgpu->gvt->gt->i915) && engine->id == RCS0)
+ context_page_num = 19;
+
+ return context_page_num;
+}
+
+static bool
+intel_vgpu_lrca_range_valid(struct intel_vgpu *vgpu,
+ const struct intel_engine_cs *engine,
+ u32 lrca)
+{
+ unsigned long context_page_num;
+ u32 max_lrca;
+
+ context_page_num = intel_vgpu_context_page_num(vgpu, engine);
+ if (!context_page_num)
+ return false;
+
+ max_lrca = (U32_MAX >> I915_GTT_PAGE_SHIFT) - (context_page_num - 1);
+
+ return lrca <= max_lrca;
+}
+
static void update_shadow_pdps(struct intel_vgpu_workload *workload)
{
struct execlist_ring_context *shadow_ring_context;
@@ -1646,6 +1677,12 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu,
u32 guest_head;
int ret;
+ if (!intel_vgpu_lrca_range_valid(vgpu, engine, desc->lrca)) {
+ gvt_vgpu_err("invalid guest context LRCA: 0x%x\n",
+ desc->lrca);
+ return ERR_PTR(-EINVAL);
+ }
+
ring_context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
(u32)((desc->lrca + 1) << I915_GTT_PAGE_SHIFT));
if (ring_context_gpa == INTEL_GVT_INVALID_ADDR) {