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>
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

szülő
348e9b397c
commit
c6b636fe0b
@@ -157,7 +157,7 @@ static ssize_t dp_debug_write_edid(struct file *file,
|
|||||||
edid = debug->edid;
|
edid = debug->edid;
|
||||||
bail:
|
bail:
|
||||||
kfree(buf);
|
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
|
* 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->ctrl->set_sim_mode(debug->ctrl, false);
|
||||||
debug->dp_debug.sim_mode = 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) {
|
if (debug->edid) {
|
||||||
devm_kfree(debug->dev, debug->edid);
|
devm_kfree(debug->dev, debug->edid);
|
||||||
debug->edid = NULL;
|
debug->edid = NULL;
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include "dp_debug.h"
|
#include "dp_debug.h"
|
||||||
#include <drm/drm_dsc.h>
|
#include <drm/drm_dsc.h>
|
||||||
#include "sde_dsc_helper.h"
|
#include "sde_dsc_helper.h"
|
||||||
|
#include <drm/drm_edid.h>
|
||||||
|
|
||||||
#define DP_KHZ_TO_HZ 1000
|
#define DP_KHZ_TO_HZ 1000
|
||||||
#define DP_PANEL_DEFAULT_BPP 24
|
#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;
|
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;
|
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);
|
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;
|
dp_panel->edid_ctrl->edid = (struct edid *)edid;
|
||||||
panel->custom_edid = true;
|
panel->custom_edid = true;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -148,7 +148,7 @@ struct dp_panel {
|
|||||||
int (*get_modes)(struct dp_panel *dp_panel,
|
int (*get_modes)(struct dp_panel *dp_panel,
|
||||||
struct drm_connector *connector, struct dp_display_mode *mode);
|
struct drm_connector *connector, struct dp_display_mode *mode);
|
||||||
void (*handle_sink_request)(struct dp_panel *dp_panel);
|
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 (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
|
||||||
int (*setup_hdr)(struct dp_panel *dp_panel,
|
int (*setup_hdr)(struct dp_panel *dp_panel,
|
||||||
struct drm_msm_ext_hdr_metadata *hdr_meta,
|
struct drm_msm_ext_hdr_metadata *hdr_meta,
|
||||||
|
Reference in New Issue
Block a user