Commit 8582e244 authored by Hans de Goede's avatar Hans de Goede

drm/modes: parse_cmdline: Fix possible reference past end of string

Before this commit, if the last option of a video=... option is for
example "rotate" without a "=<value>" after it then delim will point to
the terminating 0 of the string, and value which is sets to <delim + 1>
will point one position past the end of the string.

This commit fixes this by enforcing that the contents of delim equals '='
as it should be for options which take a value, this check is done in a
new drm_mode_parse_cmdline_int helper function which factors out the
common integer parsing code for all the options which take an int.
Acked-by: default avatarMaxime Ripard <mripard@kernel.org>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-1-hdegoede@redhat.com
parent 49a37dc3
...@@ -1568,11 +1568,34 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, ...@@ -1568,11 +1568,34 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
return 0; return 0;
} }
static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
{
const char *value;
char *endp;
/*
* delim must point to the '=', otherwise it is a syntax error and
* if delim points to the terminating zero, then delim + 1 wil point
* past the end of the string.
*/
if (*delim != '=')
return -EINVAL;
value = delim + 1;
*int_ret = simple_strtol(value, &endp, 10);
/* Make sure we have parsed something */
if (endp == value)
return -EINVAL;
return 0;
}
static int drm_mode_parse_cmdline_options(char *str, size_t len, static int drm_mode_parse_cmdline_options(char *str, size_t len,
const struct drm_connector *connector, const struct drm_connector *connector,
struct drm_cmdline_mode *mode) struct drm_cmdline_mode *mode)
{ {
unsigned int rotation = 0; unsigned int deg, margin, rotation = 0;
char *sep = str; char *sep = str;
while ((sep = strchr(sep, ','))) { while ((sep = strchr(sep, ','))) {
...@@ -1588,13 +1611,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len, ...@@ -1588,13 +1611,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
} }
if (!strncmp(option, "rotate", delim - option)) { if (!strncmp(option, "rotate", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &deg))
unsigned int deg;
deg = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
switch (deg) { switch (deg) {
...@@ -1619,57 +1636,32 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len, ...@@ -1619,57 +1636,32 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
} }
} else if (!strncmp(option, "reflect_x", delim - option)) { } else if (!strncmp(option, "reflect_x", delim - option)) {
rotation |= DRM_MODE_REFLECT_X; rotation |= DRM_MODE_REFLECT_X;
sep = delim;
} else if (!strncmp(option, "reflect_y", delim - option)) { } else if (!strncmp(option, "reflect_y", delim - option)) {
rotation |= DRM_MODE_REFLECT_Y; rotation |= DRM_MODE_REFLECT_Y;
sep = delim;
} else if (!strncmp(option, "margin_right", delim - option)) { } else if (!strncmp(option, "margin_right", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.right = margin; mode->tv_margins.right = margin;
} else if (!strncmp(option, "margin_left", delim - option)) { } else if (!strncmp(option, "margin_left", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.left = margin; mode->tv_margins.left = margin;
} else if (!strncmp(option, "margin_top", delim - option)) { } else if (!strncmp(option, "margin_top", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.top = margin; mode->tv_margins.top = margin;
} else if (!strncmp(option, "margin_bottom", delim - option)) { } else if (!strncmp(option, "margin_bottom", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.bottom = margin; mode->tv_margins.bottom = margin;
} else { } else {
return -EINVAL; return -EINVAL;
} }
sep = delim;
} }
mode->rotation_reflection = rotation; mode->rotation_reflection = rotation;
......
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