disp: msm: dp: validate edid before dereferencing

Currently, when using custom edid from debugfs, the
extensions data inside the edid block is not validated
before dereferencing the extension block.

The fix adds a edid validation function to validate
any custom edids before accessing any members in the
edid block.

Change-Id: I65e596cd6743febd5d55d968908619ebd50bef29
Signed-off-by: osaisruj <osaisruj@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 386c56c..97de1b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -165,7 +165,7 @@
 	kfree(buf);
 
 	if (!debug->dp_debug.sim_mode)
-		debug->panel->set_edid(debug->panel, edid);
+		debug->panel->set_edid(debug->panel, edid, debug->edid_size);
 
 	mutex_unlock(&debug->lock);
 	return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 7e6c44a..4b006c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -16,6 +16,7 @@
 
 #include "msm_kms.h"
 #include "dp_panel.h"
+#include <drm/drm_edid.h>
 
 #define DP_PANEL_DEFAULT_BPP 24
 #define DP_MAX_DS_PORT_COUNT 1
@@ -235,8 +236,24 @@
 
 	return 0;
 }
+static int dp_panel_validate_edid(struct edid *edid, size_t edid_size)
+{
+	if (!edid || (edid_size < EDID_LENGTH))
+		return false;
 
-static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid)
+	if (EDID_LENGTH * (edid->extensions + 1) > edid_size) {
+		pr_err("edid size does not match allocated.\n");
+		return false;
+	}
+	if (!drm_edid_is_valid(edid)) {
+		pr_err("invalid edid.\n");
+		return false;
+	}
+	return true;
+}
+
+static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid,
+		size_t edid_size)
 {
 	struct dp_panel_private *panel;
 
@@ -247,7 +264,7 @@
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
-	if (edid) {
+	if (edid && dp_panel_validate_edid((struct edid *)edid, edid_size)) {
 		dp_panel->edid_ctrl->edid = (struct edid *)edid;
 		panel->custom_edid = true;
 	} else {
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 1a87a96..2c4622b 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -91,7 +91,7 @@
 	int (*get_modes)(struct dp_panel *dp_panel,
 		struct drm_connector *connector, struct dp_display_mode *mode);
 	void (*handle_sink_request)(struct dp_panel *dp_panel);
-	int (*set_edid)(struct dp_panel *dp_panel, u8 *edid);
+	int (*set_edid)(struct dp_panel *dp_panel, u8 *edid, size_t edid_size);
 	int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
 	int (*setup_hdr)(struct dp_panel *dp_panel,
 		struct drm_msm_ext_hdr_metadata *hdr_meta);