9b514c3a2525346079b49df126e23fd9fd395da1
[openwrt/staging/blocktrron.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))