diff options
Diffstat (limited to 'meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch')
-rw-r--r-- | meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch new file mode 100644 index 0000000000..ab09e8b039 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch | |||
@@ -0,0 +1,266 @@ | |||
1 | From b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4 Mon Sep 17 00:00:00 2001 | ||
2 | From: BALATON Zoltan <balaton@eik.bme.hu> | ||
3 | Date: Thu, 21 May 2020 21:39:44 +0200 | ||
4 | Subject: [PATCH 5/5] sm501: Replace hand written implementation with pixman | ||
5 | where possible | ||
6 | |||
7 | Besides being faster this should also prevent malicious guests to | ||
8 | abuse 2D engine to overwrite data or cause a crash. | ||
9 | |||
10 | Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> | ||
11 | Message-id: 58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu | ||
12 | Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> | ||
13 | |||
14 | Upstream-Status: Backport | ||
15 | CVE: CVE-2020-12829 | ||
16 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
17 | |||
18 | --- | ||
19 | hw/display/sm501.c | 207 ++++++++++++++++++++++++++------------------- | ||
20 | 1 file changed, 119 insertions(+), 88 deletions(-) | ||
21 | |||
22 | diff --git a/hw/display/sm501.c b/hw/display/sm501.c | ||
23 | index 5ed57703d8..8bf4d111f4 100644 | ||
24 | --- a/hw/display/sm501.c | ||
25 | +++ b/hw/display/sm501.c | ||
26 | @@ -706,13 +706,12 @@ static void sm501_2d_operation(SM501State *s) | ||
27 | /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ | ||
28 | int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; | ||
29 | int rop = s->twoD_control & 0xFF; | ||
30 | - int dst_x = (s->twoD_destination >> 16) & 0x01FFF; | ||
31 | - int dst_y = s->twoD_destination & 0xFFFF; | ||
32 | - int width = (s->twoD_dimension >> 16) & 0x1FFF; | ||
33 | - int height = s->twoD_dimension & 0xFFFF; | ||
34 | + unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF; | ||
35 | + unsigned int dst_y = s->twoD_destination & 0xFFFF; | ||
36 | + unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF; | ||
37 | + unsigned int height = s->twoD_dimension & 0xFFFF; | ||
38 | uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; | ||
39 | - uint8_t *dst = s->local_mem + dst_base; | ||
40 | - int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; | ||
41 | + unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; | ||
42 | int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; | ||
43 | int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); | ||
44 | |||
45 | @@ -721,104 +720,136 @@ static void sm501_2d_operation(SM501State *s) | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | - if (rop_mode == 0) { | ||
50 | - if (rop != 0xcc) { | ||
51 | - /* Anything other than plain copies are not supported */ | ||
52 | - qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not " | ||
53 | - "supported.\n", rop); | ||
54 | - } | ||
55 | - } else { | ||
56 | - if (rop2_source_is_pattern && rop != 0x5) { | ||
57 | - /* For pattern source, we support only inverse dest */ | ||
58 | - qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and " | ||
59 | - "rop %x is not supported.\n", rop); | ||
60 | - } else { | ||
61 | - if (rop != 0x5 && rop != 0xc) { | ||
62 | - /* Anything other than plain copies or inverse dest is not | ||
63 | - * supported */ | ||
64 | - qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not " | ||
65 | - "supported.\n", rop); | ||
66 | - } | ||
67 | - } | ||
68 | - } | ||
69 | - | ||
70 | if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { | ||
71 | qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | + if (!dst_pitch) { | ||
76 | + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n"); | ||
77 | + return; | ||
78 | + } | ||
79 | + | ||
80 | + if (!width || !height) { | ||
81 | + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n"); | ||
82 | + return; | ||
83 | + } | ||
84 | + | ||
85 | + if (rtl) { | ||
86 | + dst_x -= width - 1; | ||
87 | + dst_y -= height - 1; | ||
88 | + } | ||
89 | + | ||
90 | + if (dst_base >= get_local_mem_size(s) || dst_base + | ||
91 | + (dst_x + width + (dst_y + height) * (dst_pitch + width)) * | ||
92 | + (1 << format) >= get_local_mem_size(s)) { | ||
93 | + qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); | ||
94 | + return; | ||
95 | + } | ||
96 | + | ||
97 | switch (cmd) { | ||
98 | - case 0x00: /* copy area */ | ||
99 | + case 0: /* BitBlt */ | ||
100 | { | ||
101 | - int src_x = (s->twoD_source >> 16) & 0x01FFF; | ||
102 | - int src_y = s->twoD_source & 0xFFFF; | ||
103 | + unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF; | ||
104 | + unsigned int src_y = s->twoD_source & 0xFFFF; | ||
105 | uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; | ||
106 | - uint8_t *src = s->local_mem + src_base; | ||
107 | - int src_pitch = s->twoD_pitch & 0x1FFF; | ||
108 | - | ||
109 | -#define COPY_AREA(_bpp, _pixel_type, rtl) { \ | ||
110 | - int y, x, index_d, index_s; \ | ||
111 | - for (y = 0; y < height; y++) { \ | ||
112 | - for (x = 0; x < width; x++) { \ | ||
113 | - _pixel_type val; \ | ||
114 | - \ | ||
115 | - if (rtl) { \ | ||
116 | - index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ | ||
117 | - index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ | ||
118 | - } else { \ | ||
119 | - index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ | ||
120 | - index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ | ||
121 | - } \ | ||
122 | - if (rop_mode == 1 && rop == 5) { \ | ||
123 | - /* Invert dest */ \ | ||
124 | - val = ~*(_pixel_type *)&dst[index_d]; \ | ||
125 | - } else { \ | ||
126 | - val = *(_pixel_type *)&src[index_s]; \ | ||
127 | - } \ | ||
128 | - *(_pixel_type *)&dst[index_d] = val; \ | ||
129 | - } \ | ||
130 | - } \ | ||
131 | - } | ||
132 | - switch (format) { | ||
133 | - case 0: | ||
134 | - COPY_AREA(1, uint8_t, rtl); | ||
135 | - break; | ||
136 | - case 1: | ||
137 | - COPY_AREA(2, uint16_t, rtl); | ||
138 | - break; | ||
139 | - case 2: | ||
140 | - COPY_AREA(4, uint32_t, rtl); | ||
141 | - break; | ||
142 | + unsigned int src_pitch = s->twoD_pitch & 0x1FFF; | ||
143 | + | ||
144 | + if (!src_pitch) { | ||
145 | + qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n"); | ||
146 | + return; | ||
147 | + } | ||
148 | + | ||
149 | + if (rtl) { | ||
150 | + src_x -= width - 1; | ||
151 | + src_y -= height - 1; | ||
152 | + } | ||
153 | + | ||
154 | + if (src_base >= get_local_mem_size(s) || src_base + | ||
155 | + (src_x + width + (src_y + height) * (src_pitch + width)) * | ||
156 | + (1 << format) >= get_local_mem_size(s)) { | ||
157 | + qemu_log_mask(LOG_GUEST_ERROR, | ||
158 | + "sm501: 2D op src is outside vram.\n"); | ||
159 | + return; | ||
160 | + } | ||
161 | + | ||
162 | + if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) { | ||
163 | + /* Invert dest, is there a way to do this with pixman? */ | ||
164 | + unsigned int x, y, i; | ||
165 | + uint8_t *d = s->local_mem + dst_base; | ||
166 | + | ||
167 | + for (y = 0; y < height; y++) { | ||
168 | + i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format); | ||
169 | + for (x = 0; x < width; x++, i += (1 << format)) { | ||
170 | + switch (format) { | ||
171 | + case 0: | ||
172 | + d[i] = ~d[i]; | ||
173 | + break; | ||
174 | + case 1: | ||
175 | + *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i]; | ||
176 | + break; | ||
177 | + case 2: | ||
178 | + *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i]; | ||
179 | + break; | ||
180 | + } | ||
181 | + } | ||
182 | + } | ||
183 | + } else { | ||
184 | + /* Do copy src for unimplemented ops, better than unpainted area */ | ||
185 | + if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) || | ||
186 | + (!rop_mode && rop != 0xcc)) { | ||
187 | + qemu_log_mask(LOG_UNIMP, | ||
188 | + "sm501: rop%d op %x%s not implemented\n", | ||
189 | + (rop_mode ? 2 : 3), rop, | ||
190 | + (rop2_source_is_pattern ? | ||
191 | + " with pattern source" : "")); | ||
192 | + } | ||
193 | + /* Check for overlaps, this could be made more exact */ | ||
194 | + uint32_t sb, se, db, de; | ||
195 | + sb = src_base + src_x + src_y * (width + src_pitch); | ||
196 | + se = sb + width + height * (width + src_pitch); | ||
197 | + db = dst_base + dst_x + dst_y * (width + dst_pitch); | ||
198 | + de = db + width + height * (width + dst_pitch); | ||
199 | + if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { | ||
200 | + /* regions may overlap: copy via temporary */ | ||
201 | + int llb = width * (1 << format); | ||
202 | + int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); | ||
203 | + uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * | ||
204 | + height); | ||
205 | + pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, | ||
206 | + src_pitch * (1 << format) / sizeof(uint32_t), | ||
207 | + tmp_stride, 8 * (1 << format), 8 * (1 << format), | ||
208 | + src_x, src_y, 0, 0, width, height); | ||
209 | + pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], | ||
210 | + tmp_stride, | ||
211 | + dst_pitch * (1 << format) / sizeof(uint32_t), | ||
212 | + 8 * (1 << format), 8 * (1 << format), | ||
213 | + 0, 0, dst_x, dst_y, width, height); | ||
214 | + g_free(tmp); | ||
215 | + } else { | ||
216 | + pixman_blt((uint32_t *)&s->local_mem[src_base], | ||
217 | + (uint32_t *)&s->local_mem[dst_base], | ||
218 | + src_pitch * (1 << format) / sizeof(uint32_t), | ||
219 | + dst_pitch * (1 << format) / sizeof(uint32_t), | ||
220 | + 8 * (1 << format), 8 * (1 << format), | ||
221 | + src_x, src_y, dst_x, dst_y, width, height); | ||
222 | + } | ||
223 | } | ||
224 | break; | ||
225 | } | ||
226 | - case 0x01: /* fill rectangle */ | ||
227 | + case 1: /* Rectangle Fill */ | ||
228 | { | ||
229 | uint32_t color = s->twoD_foreground; | ||
230 | |||
231 | -#define FILL_RECT(_bpp, _pixel_type) { \ | ||
232 | - int y, x; \ | ||
233 | - for (y = 0; y < height; y++) { \ | ||
234 | - for (x = 0; x < width; x++) { \ | ||
235 | - int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ | ||
236 | - *(_pixel_type *)&dst[index] = (_pixel_type)color; \ | ||
237 | - } \ | ||
238 | - } \ | ||
239 | - } | ||
240 | - | ||
241 | - switch (format) { | ||
242 | - case 0: | ||
243 | - FILL_RECT(1, uint8_t); | ||
244 | - break; | ||
245 | - case 1: | ||
246 | - color = cpu_to_le16(color); | ||
247 | - FILL_RECT(2, uint16_t); | ||
248 | - break; | ||
249 | - case 2: | ||
250 | + if (format == 2) { | ||
251 | color = cpu_to_le32(color); | ||
252 | - FILL_RECT(4, uint32_t); | ||
253 | - break; | ||
254 | + } else if (format == 1) { | ||
255 | + color = cpu_to_le16(color); | ||
256 | } | ||
257 | + | ||
258 | + pixman_fill((uint32_t *)&s->local_mem[dst_base], | ||
259 | + dst_pitch * (1 << format) / sizeof(uint32_t), | ||
260 | + 8 * (1 << format), dst_x, dst_y, width, height, color); | ||
261 | break; | ||
262 | } | ||
263 | default: | ||
264 | -- | ||
265 | 2.25.1 | ||
266 | |||