]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/modes: parse_cmdline: Fix possible reference past end of string
authorHans de Goede <hdegoede@redhat.com>
Mon, 18 Nov 2019 15:51:22 +0000 (16:51 +0100)
committerHans de Goede <hdegoede@redhat.com>
Mon, 16 Dec 2019 11:13:17 +0000 (12:13 +0100)
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: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-1-hdegoede@redhat.com
drivers/gpu/drm/drm_modes.c

index 88232698d7a00a95b9317465a6f5fe3ae44a05cd..3c3c7435225f77e1cf8041fda0c50ab40a31c43c 100644 (file)
@@ -1568,11 +1568,34 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
        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,
                                          const struct drm_connector *connector,
                                          struct drm_cmdline_mode *mode)
 {
-       unsigned int rotation = 0;
+       unsigned int deg, margin, rotation = 0;
        char *sep = str;
 
        while ((sep = strchr(sep, ','))) {
@@ -1588,13 +1611,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
                }
 
                if (!strncmp(option, "rotate", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int deg;
-
-                       deg = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &deg))
                                return -EINVAL;
 
                        switch (deg) {
@@ -1619,57 +1636,32 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
                        }
                } else if (!strncmp(option, "reflect_x", delim - option)) {
                        rotation |= DRM_MODE_REFLECT_X;
-                       sep = delim;
                } else if (!strncmp(option, "reflect_y", delim - option)) {
                        rotation |= DRM_MODE_REFLECT_Y;
-                       sep = delim;
                } else if (!strncmp(option, "margin_right", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.right = margin;
                } else if (!strncmp(option, "margin_left", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.left = margin;
                } else if (!strncmp(option, "margin_top", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.top = margin;
                } else if (!strncmp(option, "margin_bottom", delim - option)) {
-                       const char *value = delim + 1;
-                       unsigned int margin;
-
-                       margin = simple_strtol(value, &sep, 10);
-
-                       /* Make sure we have parsed something */
-                       if (sep == value)
+                       if (drm_mode_parse_cmdline_int(delim, &margin))
                                return -EINVAL;
 
                        mode->tv_margins.bottom = margin;
                } else {
                        return -EINVAL;
                }
+               sep = delim;
        }
 
        mode->rotation_reflection = rotation;