205 lines
6.6 KiB
Diff
205 lines
6.6 KiB
Diff
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
|
Date: Tue, 22 May 2018 13:59:06 -0700
|
|
Subject: drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
|
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
|
|
|
commit 4f7af1948abcb18b4772fe1bcd84d7d27d96258c upstream.
|
|
|
|
For Gen7, the original cmdparser motive was to permit limited
|
|
use of register read/write instructions in unprivileged BB's.
|
|
This worked by copying the user supplied bb to a kmd owned
|
|
bb, and running it in secure mode, from the ggtt, only if
|
|
the scanner finds no unsafe commands or registers.
|
|
|
|
For Gen8+ we can't use this same technique because running bb's
|
|
from the ggtt also disables access to ppgtt space. But we also
|
|
do not actually require 'secure' execution since we are only
|
|
trying to reduce the available command/register set. Instead we
|
|
will copy the user buffer to a kmd owned read-only bb in ppgtt,
|
|
and run in the usual non-secure mode.
|
|
|
|
Note that ro pages are only supported by ppgtt (not ggtt), but
|
|
luckily that's exactly what we need.
|
|
|
|
Add the required paths to map the shadow buffer to ppgtt ro for Gen8+
|
|
|
|
v2: IS_GEN7/IS_GEN (Mika)
|
|
v3: rebase
|
|
v4: rebase
|
|
v5: rebase
|
|
|
|
Signed-off-by: Jon Bloomfield <jon.bloomfield@intel.com>
|
|
Cc: Tony Luck <tony.luck@intel.com>
|
|
Cc: Dave Airlie <airlied@redhat.com>
|
|
Cc: Takashi Iwai <tiwai@suse.de>
|
|
Cc: Tyler Hicks <tyhicks@canonical.com>
|
|
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
|
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
|
---
|
|
drivers/gpu/drm/i915/i915_drv.h | 14 ++++++
|
|
drivers/gpu/drm/i915/i915_gem.c | 16 +++++-
|
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 57 +++++++++++++++-------
|
|
3 files changed, 68 insertions(+), 19 deletions(-)
|
|
|
|
Index: linux/drivers/gpu/drm/i915/i915_drv.h
|
|
===================================================================
|
|
--- linux.orig/drivers/gpu/drm/i915/i915_drv.h
|
|
+++ linux/drivers/gpu/drm/i915/i915_drv.h
|
|
@@ -2496,6 +2496,12 @@ intel_info(const struct drm_i915_private
|
|
#define IS_GEN9_LP(dev_priv) (IS_GEN9(dev_priv) && IS_LP(dev_priv))
|
|
#define IS_GEN9_BC(dev_priv) (IS_GEN9(dev_priv) && !IS_LP(dev_priv))
|
|
|
|
+/*
|
|
+ * The Gen7 cmdparser copies the scanned buffer to the ggtt for execution
|
|
+ * All later gens can run the final buffer from the ppgtt
|
|
+ */
|
|
+#define CMDPARSER_USES_GGTT(dev_priv) IS_GEN7(dev_priv)
|
|
+
|
|
#define ENGINE_MASK(id) BIT(id)
|
|
#define RENDER_RING ENGINE_MASK(RCS)
|
|
#define BSD_RING ENGINE_MASK(VCS)
|
|
@@ -2946,6 +2952,14 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
|
u64 alignment,
|
|
u64 flags);
|
|
|
|
+struct i915_vma * __must_check
|
|
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
|
+ struct i915_address_space *vm,
|
|
+ const struct i915_ggtt_view *view,
|
|
+ u64 size,
|
|
+ u64 alignment,
|
|
+ u64 flags);
|
|
+
|
|
int i915_gem_object_unbind(struct drm_i915_gem_object *obj);
|
|
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
|
|
|
|
Index: linux/drivers/gpu/drm/i915/i915_gem.c
|
|
===================================================================
|
|
--- linux.orig/drivers/gpu/drm/i915/i915_gem.c
|
|
+++ linux/drivers/gpu/drm/i915/i915_gem.c
|
|
@@ -4425,6 +4425,20 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
|
{
|
|
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
|
struct i915_address_space *vm = &dev_priv->ggtt.vm;
|
|
+
|
|
+ return i915_gem_object_pin(obj, vm, view, size, alignment,
|
|
+ flags | PIN_GLOBAL);
|
|
+}
|
|
+
|
|
+struct i915_vma *
|
|
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
|
+ struct i915_address_space *vm,
|
|
+ const struct i915_ggtt_view *view,
|
|
+ u64 size,
|
|
+ u64 alignment,
|
|
+ u64 flags)
|
|
+{
|
|
+ struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
|
struct i915_vma *vma;
|
|
int ret;
|
|
|
|
@@ -4488,7 +4502,7 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
- ret = i915_vma_pin(vma, size, alignment, flags | PIN_GLOBAL);
|
|
+ ret = i915_vma_pin(vma, size, alignment, flags);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
Index: linux/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
|
===================================================================
|
|
--- linux.orig/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
|
+++ linux/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
|
@@ -1894,6 +1894,33 @@ static int i915_reset_gen7_sol_offsets(s
|
|
return 0;
|
|
}
|
|
|
|
+static struct i915_vma *
|
|
+shadow_batch_pin(struct i915_execbuffer *eb, struct drm_i915_gem_object *obj)
|
|
+{
|
|
+ struct drm_i915_private *dev_priv = eb->i915;
|
|
+ struct i915_address_space *vm;
|
|
+ u64 flags;
|
|
+
|
|
+ /*
|
|
+ * PPGTT backed shadow buffers must be mapped RO, to prevent
|
|
+ * post-scan tampering
|
|
+ */
|
|
+ if (CMDPARSER_USES_GGTT(dev_priv)) {
|
|
+ flags = PIN_GLOBAL;
|
|
+ vm = &dev_priv->ggtt.vm;
|
|
+ eb->batch_flags |= I915_DISPATCH_SECURE;
|
|
+ } else if (eb->vm->has_read_only) {
|
|
+ flags = PIN_USER;
|
|
+ vm = eb->vm;
|
|
+ i915_gem_object_set_readonly(obj);
|
|
+ } else {
|
|
+ DRM_DEBUG("Cannot prevent post-scan tampering without RO capable vm\n");
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+
|
|
+ return i915_gem_object_pin(obj, vm, NULL, 0, 0, flags);
|
|
+}
|
|
+
|
|
static struct i915_vma *eb_parse(struct i915_execbuffer *eb)
|
|
{
|
|
struct drm_i915_gem_object *shadow_batch_obj;
|
|
@@ -1911,14 +1938,21 @@ static struct i915_vma *eb_parse(struct
|
|
eb->batch_start_offset,
|
|
eb->batch_len);
|
|
if (err) {
|
|
- if (err == -EACCES) /* unhandled chained batch */
|
|
+ /*
|
|
+ * Unsafe GGTT-backed buffers can still be submitted safely
|
|
+ * as non-secure.
|
|
+ * For PPGTT backing however, we have no choice but to forcibly
|
|
+ * reject unsafe buffers
|
|
+ */
|
|
+ if (CMDPARSER_USES_GGTT(eb->i915) && (err == -EACCES))
|
|
+ /* Execute original buffer non-secure */
|
|
vma = NULL;
|
|
else
|
|
vma = ERR_PTR(err);
|
|
goto out;
|
|
}
|
|
|
|
- vma = i915_gem_object_ggtt_pin(shadow_batch_obj, NULL, 0, 0, 0);
|
|
+ vma = shadow_batch_pin(eb, shadow_batch_obj);
|
|
if (IS_ERR(vma))
|
|
goto out;
|
|
|
|
@@ -1927,7 +1961,9 @@ static struct i915_vma *eb_parse(struct
|
|
__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_REF;
|
|
vma->exec_flags = &eb->flags[eb->buffer_count];
|
|
eb->buffer_count++;
|
|
-
|
|
+ eb->batch_start_offset = 0;
|
|
+ eb->batch = vma;
|
|
+ /* eb->batch_len unchanged */
|
|
out:
|
|
i915_gem_object_unpin_pages(shadow_batch_obj);
|
|
return vma;
|
|
@@ -2313,21 +2349,6 @@ i915_gem_do_execbuffer(struct drm_device
|
|
err = PTR_ERR(vma);
|
|
goto err_vma;
|
|
}
|
|
-
|
|
- if (vma) {
|
|
- /*
|
|
- * Batch parsed and accepted:
|
|
- *
|
|
- * Set the DISPATCH_SECURE bit to remove the NON_SECURE
|
|
- * bit from MI_BATCH_BUFFER_START commands issued in
|
|
- * the dispatch_execbuffer implementations. We
|
|
- * specifically don't want that set on batches the
|
|
- * command parser has accepted.
|
|
- */
|
|
- eb.batch_flags |= I915_DISPATCH_SECURE;
|
|
- eb.batch_start_offset = 0;
|
|
- eb.batch = vma;
|
|
- }
|
|
}
|
|
|
|
if (eb.batch_len == 0)
|