From e94ce5a020d031a4bf9d92d9124f835f3d4f4ffd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Jan 2022 16:17:50 +0100 Subject: [PATCH] 4.14-stable patches added patches: can-bcm-fix-uaf-of-bcm-op.patch drm-i915-flush-tlbs-before-releasing-backing-store.patch --- queue-4.14/can-bcm-fix-uaf-of-bcm-op.patch | 67 ++++++ ...-tlbs-before-releasing-backing-store.patch | 206 ++++++++++++++++++ queue-4.14/series | 2 + 3 files changed, 275 insertions(+) create mode 100644 queue-4.14/can-bcm-fix-uaf-of-bcm-op.patch create mode 100644 queue-4.14/drm-i915-flush-tlbs-before-releasing-backing-store.patch create mode 100644 queue-4.14/series diff --git a/queue-4.14/can-bcm-fix-uaf-of-bcm-op.patch b/queue-4.14/can-bcm-fix-uaf-of-bcm-op.patch new file mode 100644 index 00000000000..cb81849fdb7 --- /dev/null +++ b/queue-4.14/can-bcm-fix-uaf-of-bcm-op.patch @@ -0,0 +1,67 @@ +From william.xuanziyang@huawei.com Thu Jan 27 15:48:25 2022 +From: Ziyang Xuan +Date: Sat, 22 Jan 2022 18:25:06 +0800 +Subject: can: bcm: fix UAF of bcm op +To: , , , , +Cc: , +Message-ID: <20220122102506.2898032-1-william.xuanziyang@huawei.com> + +From: Ziyang Xuan + +Stopping tasklet and hrtimer rely on the active state of tasklet and +hrtimer sequentially in bcm_remove_op(), the op object will be freed +if they are all unactive. Assume the hrtimer timeout is short, the +hrtimer cb has been excuted after tasklet conditional judgment which +must be false after last round tasklet_kill() and before condition +hrtimer_active(), it is false when execute to hrtimer_active(). Bug +is triggerd, because the stopping action is end and the op object +will be freed, but the tasklet is scheduled. The resources of the op +object will occur UAF bug. + +Move hrtimer_cancel() behind tasklet_kill() and switch 'while () {...}' +to 'do {...} while ()' to fix the op UAF problem. + +Fixes: a06393ed0316 ("can: bcm: fix hrtimer/tasklet termination in bcm op removal") +Reported-by: syzbot+5ca851459ed04c778d1d@syzkaller.appspotmail.com +Cc: stable@vger.kernel.org +Signed-off-by: Ziyang Xuan +Acked-by: Oliver Hartkopp +Signed-off-by: Greg Kroah-Hartman +--- + net/can/bcm.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -762,21 +762,21 @@ static struct bcm_op *bcm_find_op(struct + static void bcm_remove_op(struct bcm_op *op) + { + if (op->tsklet.func) { +- while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) || +- test_bit(TASKLET_STATE_RUN, &op->tsklet.state) || +- hrtimer_active(&op->timer)) { +- hrtimer_cancel(&op->timer); ++ do { + tasklet_kill(&op->tsklet); +- } ++ hrtimer_cancel(&op->timer); ++ } while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) || ++ test_bit(TASKLET_STATE_RUN, &op->tsklet.state) || ++ hrtimer_active(&op->timer)); + } + + if (op->thrtsklet.func) { +- while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) || +- test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) || +- hrtimer_active(&op->thrtimer)) { +- hrtimer_cancel(&op->thrtimer); ++ do { + tasklet_kill(&op->thrtsklet); +- } ++ hrtimer_cancel(&op->thrtimer); ++ } while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) || ++ test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) || ++ hrtimer_active(&op->thrtimer)); + } + + if ((op->frames) && (op->frames != &op->sframe)) diff --git a/queue-4.14/drm-i915-flush-tlbs-before-releasing-backing-store.patch b/queue-4.14/drm-i915-flush-tlbs-before-releasing-backing-store.patch new file mode 100644 index 00000000000..aae4baba8b4 --- /dev/null +++ b/queue-4.14/drm-i915-flush-tlbs-before-releasing-backing-store.patch @@ -0,0 +1,206 @@ +From 7938d61591d33394a21bdd7797a245b65428f44c Mon Sep 17 00:00:00 2001 +From: Tvrtko Ursulin +Date: Tue, 19 Oct 2021 13:27:10 +0100 +Subject: drm/i915: Flush TLBs before releasing backing store + +From: Tvrtko Ursulin + +commit 7938d61591d33394a21bdd7797a245b65428f44c upstream. + +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: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem.c | 84 ++++++++++++++++++++++++++++++++- + drivers/gpu/drm/i915/i915_gem_object.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 6 ++ + drivers/gpu/drm/i915/i915_vma.c | 4 + + 5 files changed, 96 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -2166,6 +2166,8 @@ struct drm_i915_private { + + struct intel_uncore uncore; + ++ struct mutex tlb_invalidate_lock; ++ + struct i915_virtual_gpu vgpu; + + struct intel_gvt *gvt; +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -2220,6 +2220,76 @@ static void __i915_gem_object_reset_page + 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; ++} ++ ++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; ++ ++ if (INTEL_GEN(dev_priv) < 8) ++ return; ++ ++ assert_rpm_wakelock_held(dev_priv); ++ ++ mutex_lock(&dev_priv->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(&dev_priv->tlb_invalidate_lock); ++} ++ + void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, + enum i915_mm_subclass subclass) + { +@@ -2257,8 +2327,18 @@ void __i915_gem_object_put_pages(struct + + __i915_gem_object_reset_page_iter(obj); + +- if (!IS_ERR(pages)) ++ if (!IS_ERR(pages)) { ++ 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); ++ } ++ } ++ + obj->ops->put_pages(obj, pages); ++ } + + unlock: + mutex_unlock(&obj->mm.lock); +@@ -4972,6 +5052,8 @@ i915_gem_load_init(struct drm_i915_priva + + spin_lock_init(&dev_priv->fb_tracking.lock); + ++ mutex_init(&dev_priv->tlb_invalidate_lock); ++ + return 0; + + err_priorities: +--- a/drivers/gpu/drm/i915/i915_gem_object.h ++++ b/drivers/gpu/drm/i915/i915_gem_object.h +@@ -135,6 +135,7 @@ struct drm_i915_gem_object { + * activity? + */ + #define I915_BO_ACTIVE_REF 0 ++#define I915_BO_WAS_BOUND_BIT 1 + + /* + * Is the object to be mapped as read-only to the GPU +--- a/drivers/gpu/drm/i915/i915_reg.h ++++ b/drivers/gpu/drm/i915/i915_reg.h +@@ -2380,6 +2380,12 @@ enum i915_power_well_id { + #define GAMT_CHKN_BIT_REG _MMIO(0x4ab8) + #define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1<<28) + ++#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) ++ + #if 0 + #define PRB0_TAIL _MMIO(0x2030) + #define PRB0_HEAD _MMIO(0x2034) +--- a/drivers/gpu/drm/i915/i915_vma.c ++++ b/drivers/gpu/drm/i915/i915_vma.c +@@ -272,6 +272,10 @@ int i915_vma_bind(struct i915_vma *vma, + return ret; + + vma->flags |= bind_flags; ++ ++ if (vma->obj) ++ set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags); ++ + return 0; + } + diff --git a/queue-4.14/series b/queue-4.14/series new file mode 100644 index 00000000000..feedf79021d --- /dev/null +++ b/queue-4.14/series @@ -0,0 +1,2 @@ +drm-i915-flush-tlbs-before-releasing-backing-store.patch +can-bcm-fix-uaf-of-bcm-op.patch -- 2.47.2