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