diff mbox series

[v5,1/6] drm/damage_helper: Check if damage clips has valid values

Message ID 20201213183930.349592-1-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show
Series [v5,1/6] drm/damage_helper: Check if damage clips has valid values | expand

Commit Message

Souza, Jose Dec. 13, 2020, 6:39 p.m. UTC
Userspace can set a damage clip with a negative coordinate, negative
width or height or larger than the plane.
This invalid values could cause issues in some HW or even worst enable
security flaws.

v2:
- add debug messages to let userspace know why atomic commit failed
due invalid damage clips

Cc: Simon Ser <contact@emersion.fr>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Deepak Rawat <drawat@vmware.com>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c |  4 +-
 drivers/gpu/drm/drm_damage_helper.c | 59 ++++++++++++++++++++++++-----
 include/drm/drm_damage_helper.h     |  4 +-
 3 files changed, 55 insertions(+), 12 deletions(-)

Comments

Simon Ser Dec. 14, 2020, 8:55 a.m. UTC | #1
> Userspace can set a damage clip with a negative coordinate, negative
> width or height or larger than the plane.
> This invalid values could cause issues in some HW or even worst enable
> security flaws.
>
> v2:
> - add debug messages to let userspace know why atomic commit failed
> due invalid damage clips
>
> Cc: Simon Ser <contact@emersion.fr>
> Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Deepak Rawat <drawat@vmware.com>
> Cc: dri-devel@lists.freedesktop.org
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>

After looking at the kernel code, it seems like the kernel already checks for
all of that in drm_atomic_plane_check. Are you aware of this?

> +	w = drm_rect_width(&plane_state->src) >> 16;
> +	h = drm_rect_height(&plane_state->src) >> 16;

The docs say this should be in FB coordinates, not in SRC_* coordinates. So we
shouldn't need to check any SRC_* prop here.
Gwan-gyeong Mun Dec. 14, 2020, 9:27 a.m. UTC | #2
On Mon, 2020-12-14 at 08:55 +0000, Simon Ser wrote:
> > Userspace can set a damage clip with a negative coordinate,
> > negative
> > width or height or larger than the plane.
> > This invalid values could cause issues in some HW or even worst
> > enable
> > security flaws.
> > 
> > v2:
> > - add debug messages to let userspace know why atomic commit failed
> > due invalid damage clips
> > 
> > Cc: Simon Ser <contact@emersion.fr>
> > Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> > Cc: Sean Paul <seanpaul@chromium.org>
> > Cc: Fabio Estevam <festevam@gmail.com>
> > Cc: Deepak Rawat <drawat@vmware.com>
> > Cc: dri-devel@lists.freedesktop.org
> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> 
> After looking at the kernel code, it seems like the kernel already
> checks for
> all of that in drm_atomic_plane_check. Are you aware of this?
> 
> > +	w = drm_rect_width(&plane_state->src) >> 16;
> > +	h = drm_rect_height(&plane_state->src) >> 16;
> 
> The docs say this should be in FB coordinates, not in SRC_*
> coordinates. So we
> shouldn't need to check any SRC_* prop here.
> 
I agree the Simon's opinion. it does check between plane's frame buffer
src geometry and damage clips. (Plane's damage clip might exist outside
of fb src geometry.)
Daniel Vetter Dec. 14, 2020, 9:55 a.m. UTC | #3
On Mon, Dec 14, 2020 at 09:27:30AM +0000, Mun, Gwan-gyeong wrote:
> On Mon, 2020-12-14 at 08:55 +0000, Simon Ser wrote:
> > > Userspace can set a damage clip with a negative coordinate,
> > > negative
> > > width or height or larger than the plane.
> > > This invalid values could cause issues in some HW or even worst
> > > enable
> > > security flaws.
> > > 
> > > v2:
> > > - add debug messages to let userspace know why atomic commit failed
> > > due invalid damage clips
> > > 
> > > Cc: Simon Ser <contact@emersion.fr>
> > > Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> > > Cc: Sean Paul <seanpaul@chromium.org>
> > > Cc: Fabio Estevam <festevam@gmail.com>
> > > Cc: Deepak Rawat <drawat@vmware.com>
> > > Cc: dri-devel@lists.freedesktop.org
> > > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> > 
> > After looking at the kernel code, it seems like the kernel already
> > checks for
> > all of that in drm_atomic_plane_check. Are you aware of this?
> > 
> > > +	w = drm_rect_width(&plane_state->src) >> 16;
> > > +	h = drm_rect_height(&plane_state->src) >> 16;
> > 
> > The docs say this should be in FB coordinates, not in SRC_*
> > coordinates. So we
> > shouldn't need to check any SRC_* prop here.
> > 
> I agree the Simon's opinion. it does check between plane's frame buffer
> src geometry and damage clips. (Plane's damage clip might exist outside
> of fb src geometry.)

Since this is causing confusion, please make sure that the igt for damage
clips validates this correctly. I think some of the igts that vmwgfx
people have created have still not yet landed, so we definitely want to
land these.

Note that basic damage clips tests should be fully generic, i.e. not tied
to anything driver specific like our psr testcases are.
-Daniel
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ba1507036f26..c6b341ecae2c 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -897,7 +897,9 @@  drm_atomic_helper_check_planes(struct drm_device *dev,
 
 		drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
 
-		drm_atomic_helper_check_plane_damage(state, new_plane_state);
+		ret = drm_atomic_helper_check_plane_damage(state, new_plane_state);
+		if (ret)
+			return ret;
 
 		if (!funcs || !funcs->atomic_check)
 			continue;
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index 3a4126dc2520..69a557aaa8cf 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -33,6 +33,7 @@ 
 #include <drm/drm_atomic.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
+#include <drm/drm_print.h>
 
 /**
  * DOC: overview
@@ -104,36 +105,76 @@  void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
 EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
 
 /**
- * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
+ * drm_atomic_helper_check_plane_damage - Verify plane damage clips on
+ * atomic_check.
  * @state: The driver state object.
- * @plane_state: Plane state for which to verify damage.
+ * @plane_state: Plane state for which to verify damage clips.
  *
- * This helper function makes sure that damage from plane state is discarded
- * for full modeset. If there are more reasons a driver would want to do a full
- * plane update rather than processing individual damage regions, then those
- * cases should be taken care of here.
+ * This helper checks if all damage clips has valid values and makes sure that
+ * damage clips from plane state is discarded for full modeset. If there are
+ * more reasons a driver would want to do a full plane update rather than
+ * processing individual damage regions, then those cases should be taken care
+ * of here.
  *
  * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
  * full plane update should happen. It also ensure helper iterator will return
  * &drm_plane_state.src as damage.
+ *
+ * Return: Zero on success, negative errno on failure.
  */
-void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
-					  struct drm_plane_state *plane_state)
+int drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
+					 struct drm_plane_state *plane_state)
 {
+	struct drm_mode_rect *damage_clips;
 	struct drm_crtc_state *crtc_state;
+	unsigned int num_clips, w, h;
+
+	num_clips = drm_plane_get_damage_clips_count(plane_state);
+	if (!num_clips)
+		return 0;
 
 	if (plane_state->crtc) {
 		crtc_state = drm_atomic_get_new_crtc_state(state,
 							   plane_state->crtc);
 
 		if (WARN_ON(!crtc_state))
-			return;
+			return 0;
 
 		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
 			drm_property_blob_put(plane_state->fb_damage_clips);
 			plane_state->fb_damage_clips = NULL;
+			return 0;
+		}
+	}
+
+	w = drm_rect_width(&plane_state->src) >> 16;
+	h = drm_rect_height(&plane_state->src) >> 16;
+	damage_clips = drm_plane_get_damage_clips(plane_state);
+
+	for (; num_clips; num_clips--, damage_clips++) {
+		if (damage_clips->x1 < 0 || damage_clips->x2 < 0 ||
+		    damage_clips->y1 < 0 || damage_clips->y2 < 0) {
+			drm_dbg_atomic(state->dev,
+				       "Invalid damage clip, negative coordinate\n");
+			return -EINVAL;
+		}
+
+		if (damage_clips->x2 < damage_clips->x1 ||
+		    damage_clips->y2 < damage_clips->y1) {
+			drm_dbg_atomic(state->dev,
+				       "Invalid damage clip, negative width or height\n");
+			return -EINVAL;
+		}
+
+		if ((damage_clips->x2 - damage_clips->x1) > w ||
+		    (damage_clips->y2 - damage_clips->y1) > h) {
+			drm_dbg_atomic(state->dev,
+				       "Invalid damage clip, width or height larger than plane\n");
+			return -EINVAL;
 		}
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
 
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
index 40c34a5bf149..5e344d1a2b22 100644
--- a/include/drm/drm_damage_helper.h
+++ b/include/drm/drm_damage_helper.h
@@ -65,8 +65,8 @@  struct drm_atomic_helper_damage_iter {
 };
 
 void drm_plane_enable_fb_damage_clips(struct drm_plane *plane);
-void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
-					  struct drm_plane_state *plane_state);
+int drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
+					 struct drm_plane_state *plane_state);
 int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
 			      struct drm_file *file_priv, unsigned int flags,
 			      unsigned int color, struct drm_clip_rect *clips,