فهرست منبع

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: I8a2cc45477416a8f8c4cff882bd53d14012e29f4
Signed-off-by: Sudarsan Ramesh <[email protected]>
Sudarsan Ramesh 4 سال پیش
والد
کامیت
c6b636fe0b
3فایلهای تغییر یافته به همراه24 افزوده شده و 5 حذف شده
  1. 2 2
      msm/dp/dp_debug.c
  2. 21 2
      msm/dp/dp_panel.c
  3. 1 1
      msm/dp/dp_panel.h

+ 2 - 2
msm/dp/dp_debug.c

@@ -157,7 +157,7 @@ static ssize_t dp_debug_write_edid(struct file *file,
 	edid = debug->edid;
 bail:
 	kfree(buf);
-	debug->panel->set_edid(debug->panel, edid);
+	debug->panel->set_edid(debug->panel, edid, debug->edid_size);
 
 	/*
 	 * print edid status as this code is executed
@@ -1617,7 +1617,7 @@ static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
 		debug->ctrl->set_sim_mode(debug->ctrl, false);
 		debug->dp_debug.sim_mode = false;
 
-		debug->panel->set_edid(debug->panel, 0);
+		debug->panel->set_edid(debug->panel, 0, 0);
 		if (debug->edid) {
 			devm_kfree(debug->dev, debug->edid);
 			debug->edid = NULL;

+ 21 - 2
msm/dp/dp_panel.c

@@ -9,6 +9,7 @@
 #include "dp_debug.h"
 #include <drm/drm_dsc.h>
 #include "sde_dsc_helper.h"
+#include <drm/drm_edid.h>
 
 #define DP_KHZ_TO_HZ 1000
 #define DP_PANEL_DEFAULT_BPP 24
@@ -1616,7 +1617,25 @@ static int dp_panel_set_default_link_params(struct dp_panel *dp_panel)
 	return 0;
 }
 
-static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid)
+static bool dp_panel_validate_edid(struct edid *edid, size_t edid_size)
+{
+	if (!edid || (edid_size < EDID_LENGTH))
+		return false;
+
+	if (EDID_LENGTH * (edid->extensions + 1) > edid_size) {
+		DP_ERR("edid size does not match allocated.\n");
+		return false;
+	}
+
+	if (!drm_edid_is_valid(edid)) {
+		DP_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;
 
@@ -1627,7 +1646,7 @@ static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid)
 
 	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 {

+ 1 - 1
msm/dp/dp_panel.h

@@ -148,7 +148,7 @@ struct dp_panel {
 	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,