summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudarsan Ramesh <sudarame@codeaurora.org>2020-11-03 17:52:12 -0500
committerGerrit - the friendly Code Review server <code-review@localhost>2020-12-10 23:13:37 -0800
commitb080a9f09881d513837b579b1952f41cecec4e63 (patch)
tree94b21dbf2026d270e22cac300071b83a1c79d51c
parentc8a629f173e0a9ed991979f01706229ebea23e37 (diff)
downloaddisplay-drivers-b080a9f09881d513837b579b1952f41cecec4e63.tar.gz
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 <sudarame@codeaurora.org>
-rw-r--r--msm/dp/dp_debug.c4
-rw-r--r--msm/dp/dp_panel.c23
-rw-r--r--msm/dp/dp_panel.h2
3 files changed, 24 insertions, 5 deletions
diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c
index 0459adce..6303c1cf 100644
--- a/msm/dp/dp_debug.c
+++ b/msm/dp/dp_debug.c
@@ -154,7 +154,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
@@ -1628,7 +1628,7 @@ static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
debug->aux->set_sim_mode(debug->aux, false, NULL, NULL);
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;
diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c
index 74f915b5..1c01b0ee 100644
--- a/msm/dp/dp_panel.c
+++ b/msm/dp/dp_panel.c
@@ -7,6 +7,7 @@
#include <linux/unistd.h>
#include <drm/drm_fixed.h>
#include "dp_debug.h"
+#include <drm/drm_edid.h>
#define DP_KHZ_TO_HZ 1000
#define DP_PANEL_DEFAULT_BPP 24
@@ -1937,7 +1938,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;
@@ -1948,7 +1967,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 {
diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h
index dbc5ba98..36629c3c 100644
--- a/msm/dp/dp_panel.h
+++ b/msm/dp/dp_panel.h
@@ -146,7 +146,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,