1252d1
From 68ccb8021a838066f0951d4b2817eb6b6f10a843 Mon Sep 17 00:00:00 2001
1252d1
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
1252d1
Date: Mon, 27 Jan 2020 10:24:14 +0100
1252d1
Subject: [PATCH] tcp_emu: fix unsafe snprintf() usages
1252d1
MIME-Version: 1.0
1252d1
Content-Type: text/plain; charset=UTF-8
1252d1
Content-Transfer-Encoding: 8bit
1252d1
1252d1
Various calls to snprintf() assume that snprintf() returns "only" the
1252d1
number of bytes written (excluding terminating NUL).
1252d1
1252d1
https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
1252d1
1252d1
"Upon successful completion, the snprintf() function shall return the
1252d1
number of bytes that would be written to s had n been sufficiently
1252d1
large excluding the terminating null byte."
1252d1
1252d1
Before patch ce131029, if there isn't enough room in "m_data" for the
1252d1
"DCC ..." message, we overflow "m_data".
1252d1
1252d1
After the patch, if there isn't enough room for the same, we don't
1252d1
overflow "m_data", but we set "m_len" out-of-bounds. The next time an
1252d1
access is bounded by "m_len", we'll have a buffer overflow then.
1252d1
1252d1
Use slirp_fmt*() to fix potential OOB memory access.
1252d1
1252d1
Reported-by: Laszlo Ersek <lersek@redhat.com>
1252d1
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
1252d1
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
1252d1
Message-Id: <20200127092414.169796-7-marcandre.lureau@redhat.com>
1252d1
---
1252d1
 src/tcp_subr.c | 44 +++++++++++++++++++++-----------------------
1252d1
 1 file changed, 21 insertions(+), 23 deletions(-)
1252d1
1252d1
diff -up ./slirp4netns-2244b9b6461afeccad1678fac3d6e478c28b4ad6/vendor/libslirp/src/tcp_subr.c.CVE-2020-8608 ./slirp4netns-2244b9b6461afeccad1678fac3d6e478c28b4ad6/vendor/libslirp/src/tcp_subr.c
1252d1
--- slirp4netns-2244b9b6461afeccad1678fac3d6e478c28b4ad6/vendor/libslirp/src/tcp_subr.c.CVE-2020-8608	2020-02-06 13:31:33.592822770 +0100
1252d1
+++ slirp4netns-2244b9b6461afeccad1678fac3d6e478c28b4ad6/vendor/libslirp/src/tcp_subr.c	2020-02-06 13:31:33.594822795 +0100
1252d1
@@ -640,8 +640,7 @@ int tcp_emu(struct socket *so, struct mb
1252d1
                 NTOHS(n1);
1252d1
                 NTOHS(n2);
1252d1
                 m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
1252d1
-                m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
1252d1
-                assert(m->m_len < M_ROOM(m));
1252d1
+                m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
1252d1
             } else {
1252d1
                 *eol = '\r';
1252d1
             }
1252d1
@@ -681,9 +680,9 @@ int tcp_emu(struct socket *so, struct mb
1252d1
             n4 = (laddr & 0xff);
1252d1
 
1252d1
             m->m_len = bptr - m->m_data; /* Adjust length */
1252d1
-            m->m_len += snprintf(bptr, M_FREEROOM(m),
1252d1
-                                 "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4,
1252d1
-                                 n5, n6, x == 7 ? buff : "");
1252d1
+            m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
1252d1
+                                  "ORT %d,%d,%d,%d,%d,%d\r\n%s",
1252d1
+                                  n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
1252d1
             return 1;
1252d1
         } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
1252d1
             /*
1252d1
@@ -716,10 +715,9 @@ int tcp_emu(struct socket *so, struct mb
1252d1
             n4 = (laddr & 0xff);
1252d1
 
1252d1
             m->m_len = bptr - m->m_data; /* Adjust length */
1252d1
-            m->m_len += snprintf(bptr, M_FREEROOM(m),
1252d1
-                         "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
1252d1
-                         n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
1252d1
-
1252d1
+            m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
1252d1
+                                  "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
1252d1
+                                  n1, n2, n3, n4, n5, n6, x == 7 ? buff : "");
1252d1
             return 1;
1252d1
         }
1252d1
 
1252d1
@@ -742,8 +740,8 @@ int tcp_emu(struct socket *so, struct mb
1252d1
         if (m->m_data[m->m_len - 1] == '\0' && lport != 0 &&
1252d1
             (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
1252d1
                              htons(lport), SS_FACCEPTONCE)) != NULL)
1252d1
-            m->m_len = snprintf(m->m_data, M_ROOM(m),
1252d1
-                                "%d", ntohs(so->so_fport)) + 1;
1252d1
+            m->m_len = slirp_fmt0(m->m_data, M_ROOM(m),
1252d1
+                                  "%d", ntohs(so->so_fport));
1252d1
         return 1;
1252d1
 
1252d1
     case EMU_IRC:
1252d1
@@ -762,10 +760,10 @@ int tcp_emu(struct socket *so, struct mb
1252d1
                 return 1;
1252d1
             }
1252d1
             m->m_len = bptr - m->m_data; /* Adjust length */
1252d1
-            m->m_len += snprintf(bptr, M_FREEROOM(m),
1252d1
-                                 "DCC CHAT chat %lu %u%c\n",
1252d1
-                                 (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
-                                 ntohs(so->so_fport), 1);
1252d1
+            m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
1252d1
+                                  "DCC CHAT chat %lu %u%c\n",
1252d1
+                                  (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
+                                  ntohs(so->so_fport), 1);
1252d1
         } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport,
1252d1
                           &n1) == 4) {
1252d1
             if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
1252d1
@@ -773,10 +771,10 @@ int tcp_emu(struct socket *so, struct mb
1252d1
                 return 1;
1252d1
             }
1252d1
             m->m_len = bptr - m->m_data; /* Adjust length */
1252d1
-            m->m_len += snprintf(bptr, M_FREEROOM(m),
1252d1
-                         "DCC SEND %s %lu %u %u%c\n", buff,
1252d1
-                         (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
-                         ntohs(so->so_fport), n1, 1);
1252d1
+            m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
1252d1
+                                  "DCC SEND %s %lu %u %u%c\n", buff,
1252d1
+                                  (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
+                                  ntohs(so->so_fport), n1, 1);
1252d1
         } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport,
1252d1
                           &n1) == 4) {
1252d1
             if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr),
1252d1
@@ -784,10 +782,10 @@ int tcp_emu(struct socket *so, struct mb
1252d1
                 return 1;
1252d1
             }
1252d1
             m->m_len = bptr - m->m_data; /* Adjust length */
1252d1
-            m->m_len += snprintf(bptr, M_FREEROOM(m),
1252d1
-                         "DCC MOVE %s %lu %u %u%c\n", buff,
1252d1
-                         (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
-                         ntohs(so->so_fport), n1, 1);
1252d1
+            m->m_len += slirp_fmt(bptr, M_FREEROOM(m),
1252d1
+                                  "DCC MOVE %s %lu %u %u%c\n", buff,
1252d1
+                                  (unsigned long)ntohl(so->so_faddr.s_addr),
1252d1
+                                  ntohs(so->so_fport), n1, 1);
1252d1
         }
1252d1
         return 1;
1252d1
 
1252d1
From 30648c03b27fb8d9611b723184216cd3174b6775 Mon Sep 17 00:00:00 2001
1252d1
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
1252d1
Date: Mon, 27 Jan 2020 10:24:09 +0100
1252d1
Subject: [PATCH] util: add slirp_fmt() helpers
1252d1
MIME-Version: 1.0
1252d1
Content-Type: text/plain; charset=UTF-8
1252d1
Content-Transfer-Encoding: 8bit
1252d1
1252d1
Various calls to snprintf() in libslirp assume that snprintf() returns
1252d1
"only" the number of bytes written (excluding terminating NUL).
1252d1
1252d1
https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04
1252d1
1252d1
"Upon successful completion, the snprintf() function shall return the
1252d1
number of bytes that would be written to s had n been sufficiently
1252d1
large excluding the terminating null byte."
1252d1
1252d1
Introduce slirp_fmt() that handles several pathological cases the
1252d1
way libslirp usually expect:
1252d1
1252d1
- treat error as fatal (instead of silently returning -1)
1252d1
1252d1
- fmt0() will always \0 end
1252d1
1252d1
- return the number of bytes actually written (instead of what would
1252d1
have been written, which would usually result in OOB later), including
1252d1
the ending \0 for fmt0()
1252d1
1252d1
- warn if truncation happened (instead of ignoring)
1252d1
1252d1
Other less common cases can still be handled with strcpy/snprintf() etc.
1252d1
1252d1
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
1252d1
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
1252d1
Message-Id: <20200127092414.169796-2-marcandre.lureau@redhat.com>
1252d1
---
1252d1
 src/util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1252d1
 src/util.h |  3 +++
1252d1
 2 files changed, 65 insertions(+)
1252d1
1252d1
diff --git a/src/util.c b/src/util.c
1252d1
index e596087..e3b6257 100644
1252d1
--- a/vendor/libslirp/src/util.c
1252d1
+++ b/vendor/libslirp/src/util.c
1252d1
@@ -364,3 +364,65 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str)
1252d1
     }
1252d1
     *q = '\0';
1252d1
 }
1252d1
+
1252d1
+static int slirp_vsnprintf(char *str, size_t size,
1252d1
+                           const char *format, va_list args)
1252d1
+{
1252d1
+    int rv = vsnprintf(str, size, format, args);
1252d1
+
1252d1
+    if (rv < 0) {
1252d1
+        g_error("vsnprintf() failed: %s", g_strerror(errno));
1252d1
+    }
1252d1
+
1252d1
+    return rv;
1252d1
+}
1252d1
+
1252d1
+/*
1252d1
+ * A snprintf()-like function that:
1252d1
+ * - returns the number of bytes written (excluding optional \0-ending)
1252d1
+ * - dies on error
1252d1
+ * - warn on truncation
1252d1
+ */
1252d1
+int slirp_fmt(char *str, size_t size, const char *format, ...)
1252d1
+{
1252d1
+    va_list args;
1252d1
+    int rv;
1252d1
+
1252d1
+    va_start(args, format);
1252d1
+    rv = slirp_vsnprintf(str, size, format, args);
1252d1
+    va_end(args);
1252d1
+
1252d1
+    if (rv > size) {
1252d1
+        g_critical("vsnprintf() truncation");
1252d1
+    }
1252d1
+
1252d1
+    return MIN(rv, size);
1252d1
+}
1252d1
+
1252d1
+/*
1252d1
+ * A snprintf()-like function that:
1252d1
+ * - always \0-end (unless size == 0)
1252d1
+ * - returns the number of bytes actually written, including \0 ending
1252d1
+ * - dies on error
1252d1
+ * - warn on truncation
1252d1
+ */
1252d1
+int slirp_fmt0(char *str, size_t size, const char *format, ...)
1252d1
+{
1252d1
+    va_list args;
1252d1
+    int rv;
1252d1
+
1252d1
+    va_start(args, format);
1252d1
+    rv = slirp_vsnprintf(str, size, format, args);
1252d1
+    va_end(args);
1252d1
+
1252d1
+    if (rv >= size) {
1252d1
+        g_critical("vsnprintf() truncation");
1252d1
+        if (size > 0)
1252d1
+            str[size - 1] = '\0';
1252d1
+        rv = size;
1252d1
+    } else {
1252d1
+        rv += 1; /* include \0 */
1252d1
+    }
1252d1
+
1252d1
+    return rv;
1252d1
+}
1252d1
diff --git a/src/util.h b/src/util.h
1252d1
index e9c3073..5530c46 100644
1252d1
--- a/vendor/libslirp/src/util.h
1252d1
+++ b/vendor/libslirp/src/util.h
1252d1
@@ -181,4 +181,7 @@ static inline int slirp_socket_set_fast_reuse(int fd)
1252d1
 
1252d1
 void slirp_pstrcpy(char *buf, int buf_size, const char *str);
1252d1
 
1252d1
+int slirp_fmt(char *str, size_t size, const char *format, ...);
1252d1
+int slirp_fmt0(char *str, size_t size, const char *format, ...);
1252d1
+
1252d1
 #endif
1252d1
-- 
1252d1
2.24.1
1252d1