Commit a7a131ac authored by Ville Syrjälä's avatar Ville Syrjälä

drm/edid: Don't accept any old garbage as a display descriptor

Currently we assume any 18 byte descriptor to be a display descritor
if only the tag byte matches the expected value. But for detailed
timing descriptors that same byte is just the lower 8 bits of
hblank, and as such can match any display descriptor tag. To
properly validate that the 18 byte descriptor is in fact a
display descriptor we must also examine bytes 0-2 (just byte 1
should actually suffice but the spec does say that bytes 0 and
2 must also always be zero for display descriptors so we check
those too).

Unlike Allen's original proposed patch to just fix is_rb() we
roll this out across the board to fix everything.

Cc: Allen Chen <allen.chen@ite.com.tw>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200124200231.10517-2-ville.syrjala@linux.intel.comAcked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarUma Shankar <uma.shankar@intel.com>
parent 7304b981
...@@ -2212,6 +2212,12 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, ...@@ -2212,6 +2212,12 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
} }
EXPORT_SYMBOL(drm_mode_find_dmt); EXPORT_SYMBOL(drm_mode_find_dmt);
static bool is_display_descriptor(const u8 d[18], u8 tag)
{
return d[0] == 0x00 && d[1] == 0x00 &&
d[2] == 0x00 && d[3] == tag;
}
typedef void detailed_cb(struct detailed_timing *timing, void *closure); typedef void detailed_cb(struct detailed_timing *timing, void *closure);
static void static void
...@@ -2273,7 +2279,10 @@ static void ...@@ -2273,7 +2279,10 @@ static void
is_rb(struct detailed_timing *t, void *data) is_rb(struct detailed_timing *t, void *data)
{ {
u8 *r = (u8 *)t; u8 *r = (u8 *)t;
if (r[3] == EDID_DETAIL_MONITOR_RANGE)
if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
return;
if (r[15] & 0x10) if (r[15] & 0x10)
*(bool *)data = true; *(bool *)data = true;
} }
...@@ -2295,7 +2304,11 @@ static void ...@@ -2295,7 +2304,11 @@ static void
find_gtf2(struct detailed_timing *t, void *data) find_gtf2(struct detailed_timing *t, void *data)
{ {
u8 *r = (u8 *)t; u8 *r = (u8 *)t;
if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02)
if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
return;
if (r[10] == 0x02)
*(u8 **)data = r; *(u8 **)data = r;
} }
...@@ -2834,7 +2847,7 @@ do_inferred_modes(struct detailed_timing *timing, void *c) ...@@ -2834,7 +2847,7 @@ do_inferred_modes(struct detailed_timing *timing, void *c)
struct detailed_non_pixel *data = &timing->data.other_data; struct detailed_non_pixel *data = &timing->data.other_data;
struct detailed_data_monitor_range *range = &data->data.range; struct detailed_data_monitor_range *range = &data->data.range;
if (data->type != EDID_DETAIL_MONITOR_RANGE) if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_MONITOR_RANGE))
return; return;
closure->modes += drm_dmt_modes_for_range(closure->connector, closure->modes += drm_dmt_modes_for_range(closure->connector,
...@@ -2913,9 +2926,10 @@ static void ...@@ -2913,9 +2926,10 @@ static void
do_established_modes(struct detailed_timing *timing, void *c) do_established_modes(struct detailed_timing *timing, void *c)
{ {
struct detailed_mode_closure *closure = c; struct detailed_mode_closure *closure = c;
struct detailed_non_pixel *data = &timing->data.other_data;
if (data->type == EDID_DETAIL_EST_TIMINGS) if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_EST_TIMINGS))
return;
closure->modes += drm_est3_modes(closure->connector, timing); closure->modes += drm_est3_modes(closure->connector, timing);
} }
...@@ -2965,21 +2979,21 @@ do_standard_modes(struct detailed_timing *timing, void *c) ...@@ -2965,21 +2979,21 @@ do_standard_modes(struct detailed_timing *timing, void *c)
struct detailed_non_pixel *data = &timing->data.other_data; struct detailed_non_pixel *data = &timing->data.other_data;
struct drm_connector *connector = closure->connector; struct drm_connector *connector = closure->connector;
struct edid *edid = closure->edid; struct edid *edid = closure->edid;
if (data->type == EDID_DETAIL_STD_MODES) {
int i; int i;
if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_STD_MODES))
return;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
struct std_timing *std; struct std_timing *std = &data->data.timings[i];
struct drm_display_mode *newmode; struct drm_display_mode *newmode;
std = &data->data.timings[i];
newmode = drm_mode_std(connector, edid, std); newmode = drm_mode_std(connector, edid, std);
if (newmode) { if (newmode) {
drm_mode_probed_add(connector, newmode); drm_mode_probed_add(connector, newmode);
closure->modes++; closure->modes++;
} }
} }
}
} }
/** /**
...@@ -3072,9 +3086,10 @@ static void ...@@ -3072,9 +3086,10 @@ static void
do_cvt_mode(struct detailed_timing *timing, void *c) do_cvt_mode(struct detailed_timing *timing, void *c)
{ {
struct detailed_mode_closure *closure = c; struct detailed_mode_closure *closure = c;
struct detailed_non_pixel *data = &timing->data.other_data;
if (data->type == EDID_DETAIL_CVT_3BYTE) if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_CVT_3BYTE))
return;
closure->modes += drm_cvt_modes(closure->connector, timing); closure->modes += drm_cvt_modes(closure->connector, timing);
} }
...@@ -4301,7 +4316,9 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) ...@@ -4301,7 +4316,9 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
static void static void
monitor_name(struct detailed_timing *t, void *data) monitor_name(struct detailed_timing *t, void *data)
{ {
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME) if (!is_display_descriptor((const u8 *)t, EDID_DETAIL_MONITOR_NAME))
return;
*(u8 **)data = t->data.other_data.data.str.str; *(u8 **)data = t->data.other_data.data.str.str;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment