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
6 Patches copied from upstream dependency repository:
8 https://gitlab.freedesktop.org/slirp/libslirp/commit/68ccb8021a838066f0951d4b2817eb6b6f10a843
9 https://gitlab.freedesktop.org/slirp/libslirp/commit/30648c03b27fb8d9611b723184216cd3174b6775
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
16 Content-Type: text/plain; charset=UTF-8
17 Content-Transfer-Encoding: 8bit
19 Various calls to snprintf() assume that snprintf() returns "only" the
20 number of bytes written (excluding terminating NUL).
22 https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
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."
28 Before patch ce131029, if there isn't enough room in "m_data" for the
29 "DCC ..." message, we overflow "m_data".
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.
35 Use slirp_fmt*() to fix potential OOB memory access.
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>
42 src/tcp_subr.c | 44 +++++++++++++++++++++-----------------------
43 1 file changed, 21 insertions(+), 23 deletions(-)
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)
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);
59 @@ -684,9 +683,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
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 : "");
70 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
72 @@ -719,10 +718,9 @@ int tcp_emu(struct socket *so, struct mbuf *m)
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 : "");
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 : "");
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));
97 @@ -765,10 +763,10 @@ int tcp_emu(struct socket *so, struct mbuf *m)
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,
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)
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,
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)
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);
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
150 Content-Type: text/plain; charset=UTF-8
151 Content-Transfer-Encoding: 8bit
153 Various calls to snprintf() in libslirp assume that snprintf() returns
154 "only" the number of bytes written (excluding terminating NUL).
156 https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
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."
162 Introduce slirp_fmt() that handles several pathological cases the
163 way libslirp usually expect:
165 - treat error as fatal (instead of silently returning -1)
167 - fmt0() will always \0 end
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()
173 - warn if truncation happened (instead of ignoring)
175 Other less common cases can still be handled with strcpy/snprintf() etc.
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>
181 src/util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
183 2 files changed, 65 insertions(+)
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)
194 +static int slirp_vsnprintf(char *str, size_t size,
195 + const char *format, va_list args)
197 + int rv = vsnprintf(str, size, format, args);
200 + g_error("vsnprintf() failed: %s", g_strerror(errno));
207 + * A snprintf()-like function that:
208 + * - returns the number of bytes written (excluding optional \0-ending)
210 + * - warn on truncation
212 +int slirp_fmt(char *str, size_t size, const char *format, ...)
217 + va_start(args, format);
218 + rv = slirp_vsnprintf(str, size, format, args);
222 + g_critical("vsnprintf() truncation");
225 + return MIN(rv, size);
229 + * A snprintf()-like function that:
230 + * - always \0-end (unless size == 0)
231 + * - returns the number of bytes actually written, including \0 ending
233 + * - warn on truncation
235 +int slirp_fmt0(char *str, size_t size, const char *format, ...)
240 + va_start(args, format);
241 + rv = slirp_vsnprintf(str, size, format, args);
245 + g_critical("vsnprintf() truncation");
247 + str[size - 1] = '\0';
250 + rv += 1; /* include \0 */
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)
261 void slirp_pstrcpy(char *buf, int buf_size, const char *str);
263 +int slirp_fmt(char *str, size_t size, const char *format, ...);
264 +int slirp_fmt0(char *str, size_t size, const char *format, ...);