9b514c3a2525346079b49df126e23fd9fd395da1
[oweals/openwrt.git] /
1 From fade8b3cf37785297b4f8a9bbd13ab107208af5a Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Mon, 18 Nov 2019 16:51:22 +0100
4 Subject: [PATCH] drm/modes: parse_cmdline: Fix possible reference past
5  end of string
6
7 Commit 8582e244e5fe72d2e9ace186fa8f3ed3bb4122e1 upstream.
8
9 Before this commit, if the last option of a video=... option is for
10 example "rotate" without a "=<value>" after it then delim will point to
11 the terminating 0 of the string, and value which is sets to <delim + 1>
12 will point one position past the end of the string.
13
14 This commit fixes this by enforcing that the contents of delim equals '='
15 as it should be for options which take a value, this check is done in a
16 new drm_mode_parse_cmdline_int helper function which factors out the
17 common integer parsing code for all the options which take an int.
18
19 Acked-by: Maxime Ripard <mripard@kernel.org>
20 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
21 Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-1-hdegoede@redhat.com
22 ---
23  drivers/gpu/drm/drm_modes.c | 68 ++++++++++++++++---------------------
24  1 file changed, 30 insertions(+), 38 deletions(-)
25
26 --- a/drivers/gpu/drm/drm_modes.c
27 +++ b/drivers/gpu/drm/drm_modes.c
28 @@ -1568,11 +1568,34 @@ static int drm_mode_parse_cmdline_res_mo
29         return 0;
30  }
31  
32 +static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
33 +{
34 +       const char *value;
35 +       char *endp;
36 +
37 +       /*
38 +        * delim must point to the '=', otherwise it is a syntax error and
39 +        * if delim points to the terminating zero, then delim + 1 wil point
40 +        * past the end of the string.
41 +        */
42 +       if (*delim != '=')
43 +               return -EINVAL;
44 +
45 +       value = delim + 1;
46 +       *int_ret = simple_strtol(value, &endp, 10);
47 +
48 +       /* Make sure we have parsed something */
49 +       if (endp == value)
50 +               return -EINVAL;
51 +
52 +       return 0;
53 +}
54 +
55  static int drm_mode_parse_cmdline_options(char *str, size_t len,
56                                           const struct drm_connector *connector,
57                                           struct drm_cmdline_mode *mode)
58  {
59 -       unsigned int rotation = 0;
60 +       unsigned int deg, margin, rotation = 0;
61         char *sep = str;
62  
63         while ((sep = strchr(sep, ','))) {
64 @@ -1588,13 +1611,7 @@ static int drm_mode_parse_cmdline_option
65                 }
66  
67                 if (!strncmp(option, "rotate", delim - option)) {
68 -                       const char *value = delim + 1;
69 -                       unsigned int deg;
70 -
71 -                       deg = simple_strtol(value, &sep, 10);
72 -
73 -                       /* Make sure we have parsed something */
74 -                       if (sep == value)
75 +                       if (drm_mode_parse_cmdline_int(delim, &deg))
76                                 return -EINVAL;
77  
78                         switch (deg) {
79 @@ -1619,57 +1636,32 @@ static int drm_mode_parse_cmdline_option
80                         }
81                 } else if (!strncmp(option, "reflect_x", delim - option)) {
82                         rotation |= DRM_MODE_REFLECT_X;
83 -                       sep = delim;
84                 } else if (!strncmp(option, "reflect_y", delim - option)) {
85                         rotation |= DRM_MODE_REFLECT_Y;
86 -                       sep = delim;
87                 } else if (!strncmp(option, "margin_right", delim - option)) {
88 -                       const char *value = delim + 1;
89 -                       unsigned int margin;
90 -
91 -                       margin = simple_strtol(value, &sep, 10);
92 -
93 -                       /* Make sure we have parsed something */
94 -                       if (sep == value)
95 +                       if (drm_mode_parse_cmdline_int(delim, &margin))
96                                 return -EINVAL;
97  
98                         mode->tv_margins.right = margin;
99                 } else if (!strncmp(option, "margin_left", delim - option)) {
100 -                       const char *value = delim + 1;
101 -                       unsigned int margin;
102 -
103 -                       margin = simple_strtol(value, &sep, 10);
104 -
105 -                       /* Make sure we have parsed something */
106 -                       if (sep == value)
107 +                       if (drm_mode_parse_cmdline_int(delim, &margin))
108                                 return -EINVAL;
109  
110                         mode->tv_margins.left = margin;
111                 } else if (!strncmp(option, "margin_top", delim - option)) {
112 -                       const char *value = delim + 1;
113 -                       unsigned int margin;
114 -
115 -                       margin = simple_strtol(value, &sep, 10);
116 -
117 -                       /* Make sure we have parsed something */
118 -                       if (sep == value)
119 +                       if (drm_mode_parse_cmdline_int(delim, &margin))
120                                 return -EINVAL;
121  
122                         mode->tv_margins.top = margin;
123                 } else if (!strncmp(option, "margin_bottom", delim - option)) {
124 -                       const char *value = delim + 1;
125 -                       unsigned int margin;
126 -
127 -                       margin = simple_strtol(value, &sep, 10);
128 -
129 -                       /* Make sure we have parsed something */
130 -                       if (sep == value)
131 +                       if (drm_mode_parse_cmdline_int(delim, &margin))
132                                 return -EINVAL;
133  
134                         mode->tv_margins.bottom = margin;
135                 } else {
136                         return -EINVAL;
137                 }
138 +               sep = delim;
139         }
140  
141         if (!(rotation & DRM_MODE_ROTATE_MASK))