Blame SOURCES/CVE-2022-0330.patch

c38cbc
From e314ba42cb4dccd4d9edb2ffcb2295b4c4e2d00d Mon Sep 17 00:00:00 2001
c38cbc
From: Yannick Cote <ycote@redhat.com>
c38cbc
Date: Tue, 1 Mar 2022 19:54:52 -0500
c38cbc
Subject: [KPATCH CVE-2022-0330] drm/i915: kpatch fixes for CVE-2022-0330
c38cbc
c38cbc
Kernels:
c38cbc
4.18.0-348.el8
c38cbc
4.18.0-348.2.1.el8_5
c38cbc
4.18.0-348.7.1.el8_5
c38cbc
4.18.0-348.12.2.el8_5
c38cbc
c38cbc
Changes since last build:
c38cbc
arches: x86_64
c38cbc
i915_drv.o: changed function: i915_driver_release
c38cbc
i915_vma.o: changed function: i915_vma_bind
c38cbc
intel_gt.o: new function: intel_gt_invalidate_tlbs
c38cbc
intel_gt.o: new function: tlb_invalidate_lock_ctor
c38cbc
intel_uncore.o: changed function: __intel_uncore_forcewake_put
c38cbc
intel_uncore.o: changed function: __intel_wait_for_register
c38cbc
intel_uncore.o: changed function: i915_pmic_bus_access_notifier
c38cbc
intel_uncore.o: changed function: intel_uncore_forcewake_put
c38cbc
intel_uncore.o: changed function: intel_uncore_forcewake_put__locked
c38cbc
intel_uncore.o: changed function: intel_uncore_forcewake_user_put
c38cbc
intel_uncore.o: new function: intel_uncore_forcewake_put_delayed
c38cbc
---------------------------
c38cbc
c38cbc
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-8/-/merge_requests/33
c38cbc
Approved-by: Joe Lawrence (@joe.lawrence)
c38cbc
Kernels:
c38cbc
4.18.0-348.el8
c38cbc
4.18.0-348.2.1.el8_5
c38cbc
4.18.0-348.7.1.el8_5
c38cbc
4.18.0-348.12.2.el8_5
c38cbc
c38cbc
Modifications:
c38cbc
- Move new bit definition to .c files avoiding changes to .h files.
c38cbc
- Redefine tlb_invalidate_lock as a klp shadow variable and avoid
c38cbc
changes to global structure definition (struct intel_gt).
c38cbc
c38cbc
commit 01dfa79afb751b4fec242c7d05ee2e0f78fe9a78
c38cbc
Author: Patrick Talbert <ptalbert@redhat.com>
c38cbc
Date:   Mon Jan 31 10:33:24 2022 +0100
c38cbc
c38cbc
    drm/i915: Flush TLBs before releasing backing store
c38cbc
c38cbc
    Bugzilla: https://bugzilla.redhat.com/2044328
c38cbc
    CVE: CVE-2022-0330
c38cbc
    Y-Commit: 5dfb7de610e0b38a03d4d71bdc6cb23a8af0161d
c38cbc
c38cbc
    commit 7938d61591d33394a21bdd7797a245b65428f44c
c38cbc
    Author: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
c38cbc
    Date:   Tue Oct 19 13:27:10 2021 +0100
c38cbc
c38cbc
        drm/i915: Flush TLBs before releasing backing store
c38cbc
c38cbc
        We need to flush TLBs before releasing backing store otherwise userspace
c38cbc
        is able to encounter stale entries if a) it is not declaring GPU access to
c38cbc
        certain buffers and b) this GPU execution then races with the backing
c38cbc
        store release getting triggered asynchronously.
c38cbc
c38cbc
        Approach taken is to mark any buffer objects which were ever bound to the
c38cbc
        GPU and triggering a serialized TLB flush when their backing store is
c38cbc
        released.
c38cbc
c38cbc
        Alternatively the flushing could be done on VMA unbind, at which point we
c38cbc
        would be able to ascertain whether there is potential parallel GPU
c38cbc
        execution (which could race), but choice essentially boils down to paying
c38cbc
        the cost of TLB flushes maybe needlessly at VMA unbind time (when the
c38cbc
        backing store is not known to be definitely going away, so flushing not
c38cbc
        always required for safety), versus potentially needlessly at backing
c38cbc
        store relase time since at that point cannot tell whether there is a
c38cbc
        parallel GPU execution happening.
c38cbc
c38cbc
        Therefore simplicity of implementation has been chosen for now, with scope
c38cbc
        to benchmark and refine later as required.
c38cbc
c38cbc
        Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
c38cbc
        Reported-by: Sushma Venkatesh Reddy <sushma.venkatesh.reddy@intel.com>
c38cbc
        Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
c38cbc
        Cc: Jon Bloomfield <jon.bloomfield@intel.com>
c38cbc
        Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
c38cbc
        Cc: Jani Nikula <jani.nikula@intel.com>
c38cbc
        Cc: stable@vger.kernel.org
c38cbc
c38cbc
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
c38cbc
c38cbc
Signed-off-by: Yannick Cote <ycote@redhat.com>
c38cbc
---
c38cbc
 drivers/gpu/drm/i915/gem/i915_gem_pages.c |  13 +++
c38cbc
 drivers/gpu/drm/i915/gt/intel_gt.c        | 130 ++++++++++++++++++++++
c38cbc
 drivers/gpu/drm/i915/i915_drv.c           |   5 +
c38cbc
 drivers/gpu/drm/i915/i915_vma.c           |   6 +
c38cbc
 drivers/gpu/drm/i915/intel_uncore.c       |  26 ++++-
c38cbc
 5 files changed, 176 insertions(+), 4 deletions(-)
c38cbc
c38cbc
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
c38cbc
index 76574e245916..ba7fce675ee7 100644
c38cbc
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
c38cbc
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
c38cbc
@@ -173,6 +173,11 @@ static void unmap_object(struct drm_i915_gem_object *obj, void *ptr)
c38cbc
 		vunmap(ptr);
c38cbc
 }
c38cbc
 
c38cbc
+/* CVE-2022-0330 - kpatch gathered definitions */
c38cbc
+#define I915_BO_WAS_BOUND_BIT	4
c38cbc
+
c38cbc
+void intel_gt_invalidate_tlbs(struct intel_gt *gt);
c38cbc
+
c38cbc
 struct sg_table *
c38cbc
 __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
c38cbc
 {
c38cbc
@@ -195,6 +200,14 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
c38cbc
 	__i915_gem_object_reset_page_iter(obj);
c38cbc
 	obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
c38cbc
 
c38cbc
+	if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
c38cbc
+		struct drm_i915_private *i915 = to_i915(obj->base.dev);
c38cbc
+		intel_wakeref_t wakeref;
c38cbc
+
c38cbc
+		with_intel_runtime_pm_if_active(&i915->runtime_pm, wakeref)
c38cbc
+			intel_gt_invalidate_tlbs(&i915->gt);
c38cbc
+	}
c38cbc
+
c38cbc
 	return pages;
c38cbc
 }
c38cbc
 
c38cbc
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
c38cbc
index d8e1ab412634..da0b144ea418 100644
c38cbc
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
c38cbc
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
c38cbc
@@ -662,3 +662,133 @@ void intel_gt_info_print(const struct intel_gt_info *info,
c38cbc
 
c38cbc
 	intel_sseu_dump(&info->sseu, p);
c38cbc
 }
c38cbc
+
c38cbc
+struct reg_and_bit {
c38cbc
+	i915_reg_t reg;
c38cbc
+	u32 bit;
c38cbc
+};
c38cbc
+
c38cbc
+static struct reg_and_bit
c38cbc
+get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
c38cbc
+		const i915_reg_t *regs, const unsigned int num)
c38cbc
+{
c38cbc
+	const unsigned int class = engine->class;
c38cbc
+	struct reg_and_bit rb = { };
c38cbc
+
c38cbc
+	if (drm_WARN_ON_ONCE(&engine->i915->drm,
c38cbc
+			     class >= num || !regs[class].reg))
c38cbc
+		return rb;
c38cbc
+
c38cbc
+	rb.reg = regs[class];
c38cbc
+	if (gen8 && class == VIDEO_DECODE_CLASS)
c38cbc
+		rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
c38cbc
+	else
c38cbc
+		rb.bit = engine->instance;
c38cbc
+
c38cbc
+	rb.bit = BIT(rb.bit);
c38cbc
+
c38cbc
+	return rb;
c38cbc
+}
c38cbc
+
c38cbc
+/* CVE-2022-0330 - kpatch gathered definitions */
c38cbc
+#include <linux/livepatch.h>
c38cbc
+#define KLP_CVE_2022_0330_MUTEX	0x2022033000000001
c38cbc
+#define GEN8_RTCR		_MMIO(0x4260)
c38cbc
+#define GEN8_M1TCR		_MMIO(0x4264)
c38cbc
+#define GEN8_M2TCR		_MMIO(0x4268)
c38cbc
+#define GEN8_BTCR		_MMIO(0x426c)
c38cbc
+#define GEN8_VTCR		_MMIO(0x4270)
c38cbc
+#define GEN12_GFX_TLB_INV_CR	_MMIO(0xced8)
c38cbc
+#define GEN12_VD_TLB_INV_CR	_MMIO(0xcedc)
c38cbc
+#define GEN12_VE_TLB_INV_CR	_MMIO(0xcee0)
c38cbc
+#define GEN12_BLT_TLB_INV_CR	_MMIO(0xcee4)
c38cbc
+
c38cbc
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
c38cbc
+					enum forcewake_domains domains);
c38cbc
+
c38cbc
+static int tlb_invalidate_lock_ctor(void *obj, void *shadow_data, void *ctor_data)
c38cbc
+{
c38cbc
+	struct mutex *m = shadow_data;
c38cbc
+	mutex_init(m);
c38cbc
+
c38cbc
+	return 0;
c38cbc
+}
c38cbc
+
c38cbc
+void intel_gt_invalidate_tlbs(struct intel_gt *gt)
c38cbc
+{
c38cbc
+	static const i915_reg_t gen8_regs[] = {
c38cbc
+		[RENDER_CLASS]			= GEN8_RTCR,
c38cbc
+		[VIDEO_DECODE_CLASS]		= GEN8_M1TCR, /* , GEN8_M2TCR */
c38cbc
+		[VIDEO_ENHANCEMENT_CLASS]	= GEN8_VTCR,
c38cbc
+		[COPY_ENGINE_CLASS]		= GEN8_BTCR,
c38cbc
+	};
c38cbc
+	static const i915_reg_t gen12_regs[] = {
c38cbc
+		[RENDER_CLASS]			= GEN12_GFX_TLB_INV_CR,
c38cbc
+		[VIDEO_DECODE_CLASS]		= GEN12_VD_TLB_INV_CR,
c38cbc
+		[VIDEO_ENHANCEMENT_CLASS]	= GEN12_VE_TLB_INV_CR,
c38cbc
+		[COPY_ENGINE_CLASS]		= GEN12_BLT_TLB_INV_CR,
c38cbc
+	};
c38cbc
+	struct drm_i915_private *i915 = gt->i915;
c38cbc
+	struct intel_uncore *uncore = gt->uncore;
c38cbc
+	struct intel_engine_cs *engine;
c38cbc
+	enum intel_engine_id id;
c38cbc
+	const i915_reg_t *regs;
c38cbc
+	unsigned int num = 0;
c38cbc
+	struct mutex *tlb_invalidate_lock;
c38cbc
+
c38cbc
+	if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
c38cbc
+		return;
c38cbc
+
c38cbc
+	if (INTEL_GEN(i915) == 12) {
c38cbc
+		regs = gen12_regs;
c38cbc
+		num = ARRAY_SIZE(gen12_regs);
c38cbc
+	} else if (INTEL_GEN(i915) >= 8 && INTEL_GEN(i915) <= 11) {
c38cbc
+		regs = gen8_regs;
c38cbc
+		num = ARRAY_SIZE(gen8_regs);
c38cbc
+	} else if (INTEL_GEN(i915) < 8) {
c38cbc
+		return;
c38cbc
+	}
c38cbc
+
c38cbc
+	if (drm_WARN_ONCE(&i915->drm, !num,
c38cbc
+			  "Platform does not implement TLB invalidation!"))
c38cbc
+		return;
c38cbc
+
c38cbc
+	GEM_TRACE("\n");
c38cbc
+
c38cbc
+	assert_rpm_wakelock_held(&i915->runtime_pm);
c38cbc
+
c38cbc
+	tlb_invalidate_lock = klp_shadow_get_or_alloc(i915, KLP_CVE_2022_0330_MUTEX,
c38cbc
+						      sizeof(*tlb_invalidate_lock), GFP_KERNEL,
c38cbc
+						      tlb_invalidate_lock_ctor, NULL);
c38cbc
+	if (tlb_invalidate_lock) {
c38cbc
+		mutex_lock(tlb_invalidate_lock);
c38cbc
+		intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
c38cbc
+
c38cbc
+		for_each_engine(engine, gt, id) {
c38cbc
+			/*
c38cbc
+			 * HW architecture suggest typical invalidation time at 40us,
c38cbc
+			 * with pessimistic cases up to 100us and a recommendation to
c38cbc
+			 * cap at 1ms. We go a bit higher just in case.
c38cbc
+			 */
c38cbc
+			const unsigned int timeout_us = 100;
c38cbc
+			const unsigned int timeout_ms = 4;
c38cbc
+			struct reg_and_bit rb;
c38cbc
+
c38cbc
+			rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
c38cbc
+			if (!i915_mmio_reg_offset(rb.reg))
c38cbc
+				continue;
c38cbc
+
c38cbc
+			intel_uncore_write_fw(uncore, rb.reg, rb.bit);
c38cbc
+			if (__intel_wait_for_register_fw(uncore,
c38cbc
+							 rb.reg, rb.bit, 0,
c38cbc
+							 timeout_us, timeout_ms,
c38cbc
+							 NULL))
c38cbc
+				drm_err_ratelimited(&gt->i915->drm,
c38cbc
+						    "%s TLB invalidation did not complete in %ums!\n",
c38cbc
+						    engine->name, timeout_ms);
c38cbc
+		}
c38cbc
+
c38cbc
+		intel_uncore_forcewake_put_delayed(uncore, FORCEWAKE_ALL);
c38cbc
+		mutex_unlock(tlb_invalidate_lock);
c38cbc
+	}
c38cbc
+}
c38cbc
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
c38cbc
index 92668bcbece0..31b298618e7a 100644
c38cbc
--- a/drivers/gpu/drm/i915/i915_drv.c
c38cbc
+++ b/drivers/gpu/drm/i915/i915_drv.c
c38cbc
@@ -957,6 +957,10 @@ void i915_driver_remove(struct drm_i915_private *i915)
c38cbc
 	enable_rpm_wakeref_asserts(&i915->runtime_pm);
c38cbc
 }
c38cbc
 
c38cbc
+/* CVE-2022-0330 - kpatch gathered definitions */
c38cbc
+#include <linux/livepatch.h>
c38cbc
+#define KLP_CVE_2022_0330_MUTEX 0x2022033000000001
c38cbc
+
c38cbc
 static void i915_driver_release(struct drm_device *dev)
c38cbc
 {
c38cbc
 	struct drm_i915_private *dev_priv = to_i915(dev);
c38cbc
@@ -979,6 +983,7 @@ static void i915_driver_release(struct drm_device *dev)
c38cbc
 	intel_runtime_pm_driver_release(rpm);
c38cbc
 
c38cbc
 	i915_driver_late_release(dev_priv);
c38cbc
+	klp_shadow_free(dev_priv, KLP_CVE_2022_0330_MUTEX, NULL);
c38cbc
 }
c38cbc
 
c38cbc
 static int i915_driver_open(struct drm_device *dev, struct drm_file *file)
c38cbc
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
c38cbc
index caa9b041616b..8b2f1c8b2170 100644
c38cbc
--- a/drivers/gpu/drm/i915/i915_vma.c
c38cbc
+++ b/drivers/gpu/drm/i915/i915_vma.c
c38cbc
@@ -362,6 +362,9 @@ int i915_vma_wait_for_bind(struct i915_vma *vma)
c38cbc
 	return err;
c38cbc
 }
c38cbc
 
c38cbc
+/* CVE-2022-0330 - kpatch gathered definitions */
c38cbc
+#define I915_BO_WAS_BOUND_BIT	4
c38cbc
+
c38cbc
 /**
c38cbc
  * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
c38cbc
  * @vma: VMA to map
c38cbc
@@ -439,6 +442,9 @@ int i915_vma_bind(struct i915_vma *vma,
c38cbc
 		vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags);
c38cbc
 	}
c38cbc
 
c38cbc
+	if (vma->obj)
c38cbc
+		set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
c38cbc
+
c38cbc
 	atomic_or(bind_flags, &vma->flags);
c38cbc
 	return 0;
c38cbc
 }
c38cbc
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
c38cbc
index 9ac501bcfdad..9eb5d9e8e5a8 100644
c38cbc
--- a/drivers/gpu/drm/i915/intel_uncore.c
c38cbc
+++ b/drivers/gpu/drm/i915/intel_uncore.c
c38cbc
@@ -694,7 +694,8 @@ void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore,
c38cbc
 }
c38cbc
 
c38cbc
 static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
c38cbc
-					 enum forcewake_domains fw_domains)
c38cbc
+					 enum forcewake_domains fw_domains,
c38cbc
+					 bool delayed)
c38cbc
 {
c38cbc
 	struct intel_uncore_forcewake_domain *domain;
c38cbc
 	unsigned int tmp;
c38cbc
@@ -709,7 +710,11 @@ static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
c38cbc
 			continue;
c38cbc
 		}
c38cbc
 
c38cbc
-		uncore->funcs.force_wake_put(uncore, domain->mask);
c38cbc
+		if (delayed &&
c38cbc
+		    !(domain->uncore->fw_domains_timer & domain->mask))
c38cbc
+			fw_domain_arm_timer(domain);
c38cbc
+		else
c38cbc
+			uncore->funcs.force_wake_put(uncore, domain->mask);
c38cbc
 	}
c38cbc
 }
c38cbc
 
c38cbc
@@ -730,7 +735,20 @@ void intel_uncore_forcewake_put(struct intel_uncore *uncore,
c38cbc
 		return;
c38cbc
 
c38cbc
 	spin_lock_irqsave(&uncore->lock, irqflags);
c38cbc
-	__intel_uncore_forcewake_put(uncore, fw_domains);
c38cbc
+	__intel_uncore_forcewake_put(uncore, fw_domains, false);
c38cbc
+	spin_unlock_irqrestore(&uncore->lock, irqflags);
c38cbc
+}
c38cbc
+
c38cbc
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
c38cbc
+					enum forcewake_domains fw_domains)
c38cbc
+{
c38cbc
+	unsigned long irqflags;
c38cbc
+
c38cbc
+	if (!uncore->funcs.force_wake_put)
c38cbc
+		return;
c38cbc
+
c38cbc
+	spin_lock_irqsave(&uncore->lock, irqflags);
c38cbc
+	__intel_uncore_forcewake_put(uncore, fw_domains, true);
c38cbc
 	spin_unlock_irqrestore(&uncore->lock, irqflags);
c38cbc
 }
c38cbc
 
c38cbc
@@ -772,7 +790,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore,
c38cbc
 	if (!uncore->funcs.force_wake_put)
c38cbc
 		return;
c38cbc
 
c38cbc
-	__intel_uncore_forcewake_put(uncore, fw_domains);
c38cbc
+	__intel_uncore_forcewake_put(uncore, fw_domains, false);
c38cbc
 }
c38cbc
 
c38cbc
 void assert_forcewakes_inactive(struct intel_uncore *uncore)
c38cbc
-- 
c38cbc
2.34.1
c38cbc
c38cbc