Blame SOURCES/CVE-2022-0330.patch

c6ac4c
From c2dd834b3e366fff19a868fa446643f7f30201c7 Mon Sep 17 00:00:00 2001
c6ac4c
From: Yannick Cote <ycote@redhat.com>
c6ac4c
Date: Tue, 8 Feb 2022 17:10:45 -0500
c6ac4c
Subject: [KPATCH CVE-2022-0330] drm/i915: kpatch fixes for CVE-2022-0330
c6ac4c
c6ac4c
Kernels:
c6ac4c
3.10.0-1160.21.1.el7
c6ac4c
3.10.0-1160.24.1.el7
c6ac4c
3.10.0-1160.25.1.el7
c6ac4c
3.10.0-1160.31.1.el7
c6ac4c
3.10.0-1160.36.2.el7
c6ac4c
3.10.0-1160.41.1.el7
c6ac4c
3.10.0-1160.42.2.el7
c6ac4c
3.10.0-1160.45.1.el7
c6ac4c
3.10.0-1160.49.1.el7
c6ac4c
3.10.0-1160.53.1.el7
c6ac4c
c6ac4c
Changes since last build:
c6ac4c
arches: x86_64
c6ac4c
i915_drv.o: changed function: i915_driver_destroy
c6ac4c
i915_gem.o: changed function: __i915_gem_object_unset_pages
c6ac4c
i915_gem.o: changed function: i915_gem_fault
c6ac4c
i915_gem.o: new function: assert_rpm_wakelock_held.part.56
c6ac4c
i915_gem.o: new function: tlb_invalidate_lock_ctor
c6ac4c
i915_vma.o: changed function: i915_vma_bind
c6ac4c
---------------------------
c6ac4c
c6ac4c
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-7/-/merge_requests/24
c6ac4c
Kernels:
c6ac4c
3.10.0-1160.21.1.el7
c6ac4c
3.10.0-1160.24.1.el7
c6ac4c
3.10.0-1160.25.1.el7
c6ac4c
3.10.0-1160.31.1.el7
c6ac4c
3.10.0-1160.36.2.el7
c6ac4c
3.10.0-1160.41.1.el7
c6ac4c
3.10.0-1160.42.2.el7
c6ac4c
3.10.0-1160.45.1.el7
c6ac4c
3.10.0-1160.49.1.el7
c6ac4c
3.10.0-1160.53.1.el7
c6ac4c
c6ac4c
Modifications:
c6ac4c
- Move new bit definition to .c files avoiding changes to .h files.
c6ac4c
- Redefine tlb_invalidate_lock as a klp shadow variable and avoid
c6ac4c
changes to global structure definition (struct drm_i915_private).
c6ac4c
c6ac4c
commit c96aee1f92b3a81d8a36efd91cfc5ff33ca3ac80
c6ac4c
Author: Dave Airlie <airlied@redhat.com>
c6ac4c
Date:   Tue Jan 25 18:19:06 2022 -0500
c6ac4c
c6ac4c
    drm/i915: Flush TLBs before releasing backing store
c6ac4c
c6ac4c
    Bugzilla: http://bugzilla.redhat.com/2044319
c6ac4c
    CVE: CVE-2022-0330
c6ac4c
c6ac4c
    commit 7938d61591d33394a21bdd7797a245b65428f44c
c6ac4c
    Author: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
c6ac4c
    Date:   Tue Oct 19 13:27:10 2021 +0100
c6ac4c
c6ac4c
        drm/i915: Flush TLBs before releasing backing store
c6ac4c
c6ac4c
        We need to flush TLBs before releasing backing store otherwise userspace
c6ac4c
        is able to encounter stale entries if a) it is not declaring access to
c6ac4c
        certain buffers and b) it races with the backing store release from a
c6ac4c
        such undeclared execution already executing on the GPU in parallel.
c6ac4c
c6ac4c
        The approach taken is to mark any buffer objects which were ever bound
c6ac4c
        to the GPU and to trigger a serialized TLB flush when their backing
c6ac4c
        store is released.
c6ac4c
c6ac4c
        Alternatively the flushing could be done on VMA unbind, at which point
c6ac4c
        we would be able to ascertain whether there is potential a parallel GPU
c6ac4c
        execution (which could race), but essentially it boils down to paying
c6ac4c
        the cost of TLB flushes potentially needlessly at VMA unbind time (when
c6ac4c
        the backing store is not known to be going away so not needed for
c6ac4c
        safety), versus potentially needlessly at backing store relase time
c6ac4c
        (since we at that point cannot tell whether there is anything executing
c6ac4c
        on the GPU which uses that object).
c6ac4c
c6ac4c
        Thereforce simplicity of implementation has been chosen for now with
c6ac4c
        scope to benchmark and refine later as required.
c6ac4c
c6ac4c
        Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
c6ac4c
        Reported-by: Sushma Venkatesh Reddy <sushma.venkatesh.reddy@intel.com>
c6ac4c
        Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
c6ac4c
        Acked-by: Dave Airlie <airlied@redhat.com>
c6ac4c
        Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
c6ac4c
        Cc: Jon Bloomfield <jon.bloomfield@intel.com>
c6ac4c
        Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
c6ac4c
        Cc: Jani Nikula <jani.nikula@intel.com>
c6ac4c
        Cc: stable@vger.kernel.org
c6ac4c
        Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
c6ac4c
c6ac4c
    Signed-off-by: Dave Airlie <airlied@redhat.com>
c6ac4c
c6ac4c
Signed-off-by: Yannick Cote <ycote@redhat.com>
c6ac4c
---
c6ac4c
 drivers/gpu/drm/i915/i915_drv.c |   4 ++
c6ac4c
 drivers/gpu/drm/i915/i915_gem.c | 104 ++++++++++++++++++++++++++++++++
c6ac4c
 drivers/gpu/drm/i915/i915_vma.c |   6 ++
c6ac4c
 3 files changed, 114 insertions(+)
c6ac4c
c6ac4c
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
c6ac4c
index db8a0e6d2f2f..9c12def30f4b 100644
c6ac4c
--- a/drivers/gpu/drm/i915/i915_drv.c
c6ac4c
+++ b/drivers/gpu/drm/i915/i915_drv.c
c6ac4c
@@ -1683,11 +1683,15 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent)
c6ac4c
 	return i915;
c6ac4c
 }
c6ac4c
 
c6ac4c
+#include <linux/livepatch.h>
c6ac4c
+#define KLP_CVE_2022_0330_MUTEX 0x2022033000000001
c6ac4c
+
c6ac4c
 static void i915_driver_destroy(struct drm_i915_private *i915)
c6ac4c
 {
c6ac4c
 	struct pci_dev *pdev = i915->drm.pdev;
c6ac4c
 
c6ac4c
 	drm_dev_fini(&i915->drm);
c6ac4c
+	klp_shadow_free(i915, KLP_CVE_2022_0330_MUTEX, NULL);
c6ac4c
 	kfree(i915);
c6ac4c
 
c6ac4c
 	/* And make sure we never chase our dangling pointer from pci_dev */
c6ac4c
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
c6ac4c
index c96ccd9001bf..b882a08b32f9 100644
c6ac4c
--- a/drivers/gpu/drm/i915/i915_gem.c
c6ac4c
+++ b/drivers/gpu/drm/i915/i915_gem.c
c6ac4c
@@ -2464,6 +2464,101 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj)
c6ac4c
 	rcu_read_unlock();
c6ac4c
 }
c6ac4c
 
c6ac4c
+struct reg_and_bit {
c6ac4c
+	i915_reg_t reg;
c6ac4c
+	u32 bit;
c6ac4c
+};
c6ac4c
+
c6ac4c
+static struct reg_and_bit
c6ac4c
+get_reg_and_bit(const struct intel_engine_cs *engine,
c6ac4c
+		const i915_reg_t *regs, const unsigned int num)
c6ac4c
+{
c6ac4c
+	const unsigned int class = engine->class;
c6ac4c
+	struct reg_and_bit rb = { .bit = 1 };
c6ac4c
+
c6ac4c
+	if (WARN_ON_ONCE(class >= num || !regs[class].reg))
c6ac4c
+		return rb;
c6ac4c
+
c6ac4c
+	rb.reg = regs[class];
c6ac4c
+	if (class == VIDEO_DECODE_CLASS)
c6ac4c
+		rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
c6ac4c
+
c6ac4c
+	return rb;
c6ac4c
+}
c6ac4c
+
c6ac4c
+#include <linux/livepatch.h>
c6ac4c
+#define KLP_CVE_2022_0330_MUTEX 0x2022033000000001
c6ac4c
+#define I915_BO_WAS_BOUND_BIT   1
c6ac4c
+#define GEN8_RTCR               _MMIO(0x4260)
c6ac4c
+#define GEN8_M1TCR              _MMIO(0x4264)
c6ac4c
+#define GEN8_M2TCR              _MMIO(0x4268)
c6ac4c
+#define GEN8_BTCR               _MMIO(0x426c)
c6ac4c
+#define GEN8_VTCR               _MMIO(0x4270)
c6ac4c
+
c6ac4c
+static int tlb_invalidate_lock_ctor(void *obj, void *shadow_data, void *ctor_data)
c6ac4c
+{
c6ac4c
+	struct mutex *m = shadow_data;
c6ac4c
+	mutex_init(m);
c6ac4c
+
c6ac4c
+	return 0;
c6ac4c
+}
c6ac4c
+
c6ac4c
+static void invalidate_tlbs(struct drm_i915_private *dev_priv)
c6ac4c
+{
c6ac4c
+	static const i915_reg_t gen8_regs[] = {
c6ac4c
+		[RENDER_CLASS]                  = GEN8_RTCR,
c6ac4c
+		[VIDEO_DECODE_CLASS]            = GEN8_M1TCR, /* , GEN8_M2TCR */
c6ac4c
+		[VIDEO_ENHANCEMENT_CLASS]       = GEN8_VTCR,
c6ac4c
+		[COPY_ENGINE_CLASS]             = GEN8_BTCR,
c6ac4c
+	};
c6ac4c
+	const unsigned int num = ARRAY_SIZE(gen8_regs);
c6ac4c
+	const i915_reg_t *regs = gen8_regs;
c6ac4c
+	struct intel_engine_cs *engine;
c6ac4c
+	enum intel_engine_id id;
c6ac4c
+	struct mutex *tlb_invalidate_lock;
c6ac4c
+
c6ac4c
+	if (INTEL_GEN(dev_priv) < 8)
c6ac4c
+		return;
c6ac4c
+
c6ac4c
+	GEM_TRACE("\n");
c6ac4c
+
c6ac4c
+	assert_rpm_wakelock_held(dev_priv);
c6ac4c
+
c6ac4c
+	tlb_invalidate_lock = klp_shadow_get_or_alloc(dev_priv, KLP_CVE_2022_0330_MUTEX,
c6ac4c
+						      sizeof(*tlb_invalidate_lock), GFP_KERNEL,
c6ac4c
+						      tlb_invalidate_lock_ctor, NULL);
c6ac4c
+	if (tlb_invalidate_lock) {
c6ac4c
+		mutex_lock(tlb_invalidate_lock);
c6ac4c
+		intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
c6ac4c
+
c6ac4c
+		for_each_engine(engine, dev_priv, id) {
c6ac4c
+			/*
c6ac4c
+			 * HW architecture suggest typical invalidation time at 40us,
c6ac4c
+			 * with pessimistic cases up to 100us and a recommendation to
c6ac4c
+			 * cap at 1ms. We go a bit higher just in case.
c6ac4c
+			 */
c6ac4c
+			const unsigned int timeout_us = 100;
c6ac4c
+			const unsigned int timeout_ms = 4;
c6ac4c
+			struct reg_and_bit rb;
c6ac4c
+
c6ac4c
+			rb = get_reg_and_bit(engine, regs, num);
c6ac4c
+			if (!i915_mmio_reg_offset(rb.reg))
c6ac4c
+				continue;
c6ac4c
+
c6ac4c
+			I915_WRITE_FW(rb.reg, rb.bit);
c6ac4c
+			if (__intel_wait_for_register_fw(dev_priv,
c6ac4c
+							 rb.reg, rb.bit, 0,
c6ac4c
+							 timeout_us, timeout_ms,
c6ac4c
+							 NULL))
c6ac4c
+				DRM_ERROR_RATELIMITED("%s TLB invalidation did not complete in %ums!\n",
c6ac4c
+						      engine->name, timeout_ms);
c6ac4c
+		}
c6ac4c
+
c6ac4c
+		intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
c6ac4c
+		mutex_unlock(tlb_invalidate_lock);
c6ac4c
+	}
c6ac4c
+}
c6ac4c
+
c6ac4c
 static struct sg_table *
c6ac4c
 __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
c6ac4c
 {
c6ac4c
@@ -2493,6 +2588,15 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
c6ac4c
 	__i915_gem_object_reset_page_iter(obj);
c6ac4c
 	obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
c6ac4c
 
c6ac4c
+	if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
c6ac4c
+		struct drm_i915_private *i915 = to_i915(obj->base.dev);
c6ac4c
+
c6ac4c
+		if (intel_runtime_pm_get_if_in_use(i915)) {
c6ac4c
+			invalidate_tlbs(i915);
c6ac4c
+			intel_runtime_pm_put(i915);
c6ac4c
+		}
c6ac4c
+	}
c6ac4c
+
c6ac4c
 	return pages;
c6ac4c
 }
c6ac4c
 
c6ac4c
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
c6ac4c
index 5b4d78cdb4ca..906e6321ad77 100644
c6ac4c
--- a/drivers/gpu/drm/i915/i915_vma.c
c6ac4c
+++ b/drivers/gpu/drm/i915/i915_vma.c
c6ac4c
@@ -285,6 +285,8 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
c6ac4c
 	return vma;
c6ac4c
 }
c6ac4c
 
c6ac4c
+#define I915_BO_WAS_BOUND_BIT    1
c6ac4c
+
c6ac4c
 /**
c6ac4c
  * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
c6ac4c
  * @vma: VMA to map
c6ac4c
@@ -335,6 +337,10 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
c6ac4c
 		return ret;
c6ac4c
 
c6ac4c
 	vma->flags |= bind_flags;
c6ac4c
+
c6ac4c
+	if (vma->obj)
c6ac4c
+		set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
c6ac4c
+
c6ac4c
 	return 0;
c6ac4c
 }
c6ac4c
 
c6ac4c
-- 
c6ac4c
2.26.3
c6ac4c
c6ac4c