--- /dev/null
+From william.xuanziyang@huawei.com Thu Jan 27 15:48:25 2022
+From: Ziyang Xuan <william.xuanziyang@huawei.com>
+Date: Sat, 22 Jan 2022 18:25:06 +0800
+Subject: can: bcm: fix UAF of bcm op
+To: <gregkh@linuxfoundation.org>, <socketcan@hartkopp.net>, <mkl@pengutronix.de>, <davem@davemloft.net>, <stable@vger.kernel.org>
+Cc: <netdev@vger.kernel.org>, <linux-can@vger.kernel.org>
+Message-ID: <20220122102506.2898032-1-william.xuanziyang@huawei.com>
+
+From: Ziyang Xuan <william.xuanziyang@huawei.com>
+
+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 <william.xuanziyang@huawei.com>
+Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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))
--- /dev/null
+From 7938d61591d33394a21bdd7797a245b65428f44c Mon Sep 17 00:00:00 2001
+From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+Date: Tue, 19 Oct 2021 13:27:10 +0100
+Subject: drm/i915: Flush TLBs before releasing backing store
+
+From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+
+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 <tvrtko.ursulin@intel.com>
+Reported-by: Sushma Venkatesh Reddy <sushma.venkatesh.reddy@intel.com>
+Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Acked-by: Dave Airlie <airlied@redhat.com>
+Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
+Cc: Jon Bloomfield <jon.bloomfield@intel.com>
+Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+Cc: Jani Nikula <jani.nikula@intel.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+ }
+