gnu: QEMU: Fix CVE-2020-8608.
[jackhill/guix/guix.git] / gnu / packages / patches / qemu-CVE-2020-8608.patch
1 Fix CVE-2020-8608:
2
3 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8608
4 https://www.openwall.com/lists/oss-security/2020/02/06/2
5
6 Patches copied from upstream dependency repository:
7
8 https://gitlab.freedesktop.org/slirp/libslirp/commit/68ccb8021a838066f0951d4b2817eb6b6f10a843
9 https://gitlab.freedesktop.org/slirp/libslirp/commit/30648c03b27fb8d9611b723184216cd3174b6775
10
11 From 68ccb8021a838066f0951d4b2817eb6b6f10a843 Mon Sep 17 00:00:00 2001
12 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
13 Date: Mon, 27 Jan 2020 10:24:14 +0100
14 Subject: [PATCH] tcp_emu: fix unsafe snprintf() usages
15 MIME-Version: 1.0
16 Content-Type: text/plain; charset=UTF-8
17 Content-Transfer-Encoding: 8bit
18
19 Various calls to snprintf() assume that snprintf() returns "only" the
20 number of bytes written (excluding terminating NUL).
21
22 https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
23
24 "Upon successful completion, the snprintf() function shall return the
25 number of bytes that would be written to s had n been sufficiently
26 large excluding the terminating null byte."
27
28 Before patch ce131029, if there isn't enough room in "m_data" for the
29 "DCC ..." message, we overflow "m_data".
30
31 After the patch, if there isn't enough room for the same, we don't
32 overflow "m_data", but we set "m_len" out-of-bounds. The next time an
33 access is bounded by "m_len", we'll have a buffer overflow then.
34
35 Use slirp_fmt*() to fix potential OOB memory access.
36
37 Reported-by: Laszlo Ersek <lersek@redhat.com>
38 Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
39 Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
40 Message-Id: <20200127092414.169796-7-marcandre.lureau@redhat.com>
41 ---
42 src/tcp_subr.c | 44 +++++++++++++++++++++-----------------------
43 1 file changed, 21 insertions(+), 23 deletions(-)
44
45 diff --git a/src/tcp_subr.c b/src/tcp_subr.c
46 index a699117..a72c86b 100644
47 --- a/slirp/src/tcp_subr.c
48 +++ b/slirp/src/tcp_subr.c
49 @@ -643,8 +643,7 @@ int tcp_emu(struct socket *so, struct mbuf *m)
50 NTOHS(n1);
51 NTOHS(n2);
52 m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
53 - m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
54 - assert(m->m_len < M_ROOM(m));
55 + m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
56 } else {
57 *eol = '\r';
58 }
59 @@ -684,9 +683,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
60 n4 = (laddr & 0xff);
61
62 m->m_len = bptr - m->m_data; /* Adjust length */
63 - m->m_len += snprintf(bptr, M_FREEROOM(m),
64 - "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4,
65 - n5, n6, x == 7 ? buff : "");
66 + m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
67 + "ORT %d,%d,%d,%d,%d,%d\r\n%s",
68 + n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
69 return 1;
70 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
71 /*
72 @@ -719,10 +718,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
73 n4 = (laddr & 0xff);
74
75 m->m_len = bptr - m->m_data; /* Adjust length */
76 - m->m_len += snprintf(bptr, M_FREEROOM(m),
77 - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
78 - n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
79 -
80 + m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
81 + "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
82 + n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
83 return 1;
84 }
85
86 @@ -745,8 +743,8 @@ int tcp_emu(struct socket *so, struct mbuf *m)
87 if (m->m_data[m->m_len - 1] == '\0' && lport != 0 &&
88 (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
89 htons(lport), SS_FACCEPTONCE)) != NULL)
90 - m->m_len = snprintf(m->m_data, M_ROOM(m),
91 - "%d", ntohs(so->so_fport)) + 1;
92 + m->m_len = slirp_fmt0(m->m_data, M_ROOM(m),
93 + "%d", ntohs(so->so_fport));
94 return 1;
95
96 case EMU_IRC:
97 @@ -765,10 +763,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
98 return 1;
99 }
100 m->m_len = bptr - m->m_data; /* Adjust length */
101 - m->m_len += snprintf(bptr, M_FREEROOM(m),
102 - "DCC CHAT chat %lu %u%c\n",
103 - (unsigned long)ntohl(so->so_faddr.s_addr),
104 - ntohs(so->so_fport), 1);
105 + m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
106 + "DCC CHAT chat %lu %u%c\n",
107 + (unsigned long)ntohl(so->so_faddr.s_addr),
108 + ntohs(so->so_fport), 1);
109 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport,
110 &n1) == 4) {
111 if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
112 @@ -776,10 +774,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
113 return 1;
114 }
115 m->m_len = bptr - m->m_data; /* Adjust length */
116 - m->m_len += snprintf(bptr, M_FREEROOM(m),
117 - "DCC SEND %s %lu %u %u%c\n", buff,
118 - (unsigned long)ntohl(so->so_faddr.s_addr),
119 - ntohs(so->so_fport), n1, 1);
120 + m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
121 + "DCC SEND %s %lu %u %u%c\n", buff,
122 + (unsigned long)ntohl(so->so_faddr.s_addr),
123 + ntohs(so->so_fport), n1, 1);
124 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport,
125 &n1) == 4) {
126 if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
127 @@ -787,10 +785,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
128 return 1;
129 }
130 m->m_len = bptr - m->m_data; /* Adjust length */
131 - m->m_len += snprintf(bptr, M_FREEROOM(m),
132 - "DCC MOVE %s %lu %u %u%c\n", buff,
133 - (unsigned long)ntohl(so->so_faddr.s_addr),
134 - ntohs(so->so_fport), n1, 1);
135 + m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
136 + "DCC MOVE %s %lu %u %u%c\n", buff,
137 + (unsigned long)ntohl(so->so_faddr.s_addr),
138 + ntohs(so->so_fport), n1, 1);
139 }
140 return 1;
141
142 --
143 2.25.1
144
145 From 30648c03b27fb8d9611b723184216cd3174b6775 Mon Sep 17 00:00:00 2001
146 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
147 Date: Mon, 27 Jan 2020 10:24:09 +0100
148 Subject: [PATCH] util: add slirp_fmt() helpers
149 MIME-Version: 1.0
150 Content-Type: text/plain; charset=UTF-8
151 Content-Transfer-Encoding: 8bit
152
153 Various calls to snprintf() in libslirp assume that snprintf() returns
154 "only" the number of bytes written (excluding terminating NUL).
155
156 https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
157
158 "Upon successful completion, the snprintf() function shall return the
159 number of bytes that would be written to s had n been sufficiently
160 large excluding the terminating null byte."
161
162 Introduce slirp_fmt() that handles several pathological cases the
163 way libslirp usually expect:
164
165 - treat error as fatal (instead of silently returning -1)
166
167 - fmt0() will always \0 end
168
169 - return the number of bytes actually written (instead of what would
170 have been written, which would usually result in OOB later), including
171 the ending \0 for fmt0()
172
173 - warn if truncation happened (instead of ignoring)
174
175 Other less common cases can still be handled with strcpy/snprintf() etc.
176
177 Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
178 Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
179 Message-Id: <20200127092414.169796-2-marcandre.lureau@redhat.com>
180 ---
181 src/util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
182 src/util.h | 3 +++
183 2 files changed, 65 insertions(+)
184
185 diff --git a/src/util.c b/src/util.c
186 index e596087..e3b6257 100644
187 --- a/slirp/src/util.c
188 +++ b/slirp/src/util.c
189 @@ -364,3 +364,65 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str)
190 }
191 *q = '\0';
192 }
193 +
194 +static int slirp_vsnprintf(char *str, size_t size,
195 + const char *format, va_list args)
196 +{
197 + int rv = vsnprintf(str, size, format, args);
198 +
199 + if (rv < 0) {
200 + g_error("vsnprintf() failed: %s", g_strerror(errno));
201 + }
202 +
203 + return rv;
204 +}
205 +
206 +/*
207 + * A snprintf()-like function that:
208 + * - returns the number of bytes written (excluding optional \0-ending)
209 + * - dies on error
210 + * - warn on truncation
211 + */
212 +int slirp_fmt(char *str, size_t size, const char *format, ...)
213 +{
214 + va_list args;
215 + int rv;
216 +
217 + va_start(args, format);
218 + rv = slirp_vsnprintf(str, size, format, args);
219 + va_end(args);
220 +
221 + if (rv > size) {
222 + g_critical("vsnprintf() truncation");
223 + }
224 +
225 + return MIN(rv, size);
226 +}
227 +
228 +/*
229 + * A snprintf()-like function that:
230 + * - always \0-end (unless size == 0)
231 + * - returns the number of bytes actually written, including \0 ending
232 + * - dies on error
233 + * - warn on truncation
234 + */
235 +int slirp_fmt0(char *str, size_t size, const char *format, ...)
236 +{
237 + va_list args;
238 + int rv;
239 +
240 + va_start(args, format);
241 + rv = slirp_vsnprintf(str, size, format, args);
242 + va_end(args);
243 +
244 + if (rv >= size) {
245 + g_critical("vsnprintf() truncation");
246 + if (size > 0)
247 + str[size - 1] = '\0';
248 + rv = size;
249 + } else {
250 + rv += 1; /* include \0 */
251 + }
252 +
253 + return rv;
254 +}
255 diff --git a/src/util.h b/src/util.h
256 index e9c3073..5530c46 100644
257 --- a/slirp/src/util.h
258 +++ b/slirp/src/util.h
259 @@ -181,4 +181,7 @@ static inline int slirp_socket_set_fast_reuse(int fd)
260
261 void slirp_pstrcpy(char *buf, int buf_size, const char *str);
262
263 +int slirp_fmt(char *str, size_t size, const char *format, ...);
264 +int slirp_fmt0(char *str, size_t size, const char *format, ...);
265 +
266 #endif
267 --
268 2.25.1
269