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