Explorar el Código

disp: msm: sde: prevent custom ioctls from accessing unowned HW

Early wakeup ioctls from perf HAL driver can access display HW
registers and come as a sideband to atomic commits. Since the
atomic validate checks are not part of this code path it's
possible for HW access to occur during a trusted UI session.
Prevent this whenever the HW is not under this VM's ownership.
Also, move the VM ownership check for the register/deregister
event ioctl to cover both the CRTC and connector events since
new connector events are being added which can access HW.

Change-Id: I39660ae60e7e8f8a405e819c43ec42fbac3f492a
Signed-off-by: Steve Cohen <[email protected]>
Steve Cohen hace 3 años
padre
commit
9690b545df
Se han modificado 3 ficheros con 22 adiciones y 17 borrados
  1. 1 0
      msm/msm_drv.c
  2. 9 2
      msm/sde/sde_encoder.c
  3. 12 15
      msm/sde/sde_kms.c

+ 1 - 0
msm/msm_drv.c

@@ -1627,6 +1627,7 @@ int msm_ioctl_display_hint_ops(struct drm_device *dev, void *data,
 
 	SDE_EVT32(display_hint->hint_flags);
 
+	/* Any new hint added will require a check for VM ownership before HW is accessed */
 	if (display_hint->hint_flags == DRM_MSM_DISPLAY_EARLY_WAKEUP_HINT) {
 		if (!display_hint->data) {
 			DRM_ERROR("early_wakeup: wrong parameter\n");

+ 9 - 2
msm/sde/sde_encoder.c

@@ -4046,9 +4046,15 @@ static void sde_encoder_early_wakeup_work_handler(struct kthread_work *work)
 {
 	struct sde_encoder_virt *sde_enc = container_of(work,
 			struct sde_encoder_virt, early_wakeup_work);
+	struct sde_vm_ops *vm_ops;
+	struct sde_kms *sde_kms = to_sde_kms(ddev_to_msm_kms(sde_enc->base.dev));
 
-	if (!sde_enc) {
-		SDE_ERROR("invalid sde encoder\n");
+	vm_ops = sde_vm_get_ops(sde_kms);
+	sde_vm_lock(sde_kms);
+	if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) {
+		sde_vm_unlock(sde_kms);
+		SDE_DEBUG("skip early wakeup for ENC-%d, HW is owned by other VM\n",
+				DRMID(&sde_enc->base));
 		return;
 	}
 
@@ -4056,6 +4062,7 @@ static void sde_encoder_early_wakeup_work_handler(struct kthread_work *work)
 	sde_encoder_resource_control(&sde_enc->base,
 			SDE_ENC_RC_EVENT_EARLY_WAKEUP);
 	SDE_ATRACE_END("encoder_early_wakeup");
+	sde_vm_unlock(sde_kms);
 }
 
 void sde_encoder_early_wakeup(struct drm_encoder *drm_enc)

+ 12 - 15
msm/sde/sde_kms.c

@@ -5062,9 +5062,9 @@ static int _sde_kms_register_events(struct msm_kms *kms,
 		struct drm_mode_object *obj, u32 event, bool en)
 {
 	int ret = 0;
-	struct drm_crtc *crtc = NULL;
-	struct drm_connector *conn = NULL;
-	struct sde_kms *sde_kms = NULL;
+	struct drm_crtc *crtc;
+	struct drm_connector *conn;
+	struct sde_kms *sde_kms;
 	struct sde_vm_ops *vm_ops;
 
 	if (!kms || !obj) {
@@ -5073,24 +5073,19 @@ static int _sde_kms_register_events(struct msm_kms *kms,
 	}
 
 	sde_kms = to_sde_kms(kms);
+	vm_ops = sde_vm_get_ops(sde_kms);
+	sde_vm_lock(sde_kms);
+	if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) {
+		sde_vm_unlock(sde_kms);
+		SDE_DEBUG("HW is owned by other VM\n");
+		return -EACCES;
+	}
 
 	/* check vm ownership, if event registration requires HW access */
 	switch (obj->type) {
 	case DRM_MODE_OBJECT_CRTC:
-		vm_ops = sde_vm_get_ops(sde_kms);
-		sde_vm_lock(sde_kms);
-
-		if (vm_ops && vm_ops->vm_owns_hw
-				&& !vm_ops->vm_owns_hw(sde_kms)) {
-			sde_vm_unlock(sde_kms);
-			SDE_DEBUG("HW is owned by other VM\n");
-			return -EACCES;
-		}
-
 		crtc = obj_to_crtc(obj);
 		ret = sde_crtc_register_custom_event(sde_kms, crtc, event, en);
-
-		sde_vm_unlock(sde_kms);
 		break;
 	case DRM_MODE_OBJECT_CONNECTOR:
 		conn = obj_to_connector(obj);
@@ -5099,6 +5094,8 @@ static int _sde_kms_register_events(struct msm_kms *kms,
 		break;
 	}
 
+	sde_vm_unlock(sde_kms);
+
 	return ret;
 }