diff options
author | Sudarsan Ramesh <sudarame@codeaurora.org> | 2020-11-03 17:52:12 -0500 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2020-12-10 23:13:37 -0800 |
commit | b080a9f09881d513837b579b1952f41cecec4e63 (patch) | |
tree | 94b21dbf2026d270e22cac300071b83a1c79d51c | |
parent | c8a629f173e0a9ed991979f01706229ebea23e37 (diff) | |
download | display-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.c | 4 | ||||
-rw-r--r-- | msm/dp/dp_panel.c | 23 | ||||
-rw-r--r-- | msm/dp/dp_panel.h | 2 |
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, |