ae23c9
From 3f33dce627f419cbc77a9f6406b3353077697740 Mon Sep 17 00:00:00 2001
ae23c9
From: Xiao Wang <jasowang@redhat.com>
ae23c9
Date: Fri, 11 Jan 2019 07:59:00 +0000
ae23c9
Subject: [PATCH 05/11] net: drop too large packet early
ae23c9
MIME-Version: 1.0
ae23c9
Content-Type: text/plain; charset=UTF-8
ae23c9
Content-Transfer-Encoding: 8bit
ae23c9
ae23c9
RH-Author: Xiao Wang <jasowang@redhat.com>
ae23c9
Message-id: <20190111075904.2030-6-jasowang@redhat.com>
ae23c9
Patchwork-id: 83979
ae23c9
O-Subject: [RHEL8 qemu-kvm PATCH 5/9] net: drop too large packet early
ae23c9
Bugzilla: 1636784
ae23c9
RH-Acked-by: Thomas Huth <thuth@redhat.com>
ae23c9
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
ae23c9
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
ae23c9
RH-Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>
ae23c9
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
ae23c9
ae23c9
We try to detect and drop too large packet (>INT_MAX) in 1592a9947036
ae23c9
("net: ignore packet size greater than INT_MAX") during packet
ae23c9
delivering. Unfortunately, this is not sufficient as we may hit
ae23c9
another integer overflow when trying to queue such large packet in
ae23c9
qemu_net_queue_append_iov():
ae23c9
ae23c9
- size of the allocation may overflow on 32bit
ae23c9
- packet->size is integer which may overflow even on 64bit
ae23c9
ae23c9
Fixing this by moving the check to qemu_sendv_packet_async() which is
ae23c9
the entrance of all networking codes and reduce the limit to
ae23c9
NET_BUFSIZE to be more conservative. This works since:
ae23c9
ae23c9
- For the callers that call qemu_sendv_packet_async() directly, they
ae23c9
  only care about if zero is returned to determine whether to prevent
ae23c9
  the source from producing more packets. A callback will be triggered
ae23c9
  if peer can accept more then source could be enabled. This is
ae23c9
  usually used by high speed networking implementation like virtio-net
ae23c9
  or netmap.
ae23c9
- For the callers that call qemu_sendv_packet() that calls
ae23c9
  qemu_sendv_packet_async() indirectly, they often ignore the return
ae23c9
  value. In this case qemu will just the drop packets if peer can't
ae23c9
  receive.
ae23c9
ae23c9
Qemu will copy the packet if it was queued. So it was safe for both
ae23c9
kinds of the callers to assume the packet was sent.
ae23c9
ae23c9
Since we move the check from qemu_deliver_packet_iov() to
ae23c9
qemu_sendv_packet_async(), it would be safer to make
ae23c9
qemu_deliver_packet_iov() static to prevent any external user in the
ae23c9
future.
ae23c9
ae23c9
This is a revised patch of CVE-2018-17963.
ae23c9
ae23c9
Cc: qemu-stable@nongnu.org
ae23c9
Cc: Li Qiang <liq3ea@163.com>
ae23c9
Fixes: 1592a9947036 ("net: ignore packet size greater than INT_MAX")
ae23c9
Reported-by: Li Qiang <liq3ea@gmail.com>
ae23c9
Reviewed-by: Li Qiang <liq3ea@gmail.com>
ae23c9
Signed-off-by: Jason Wang <jasowang@redhat.com>
ae23c9
Reviewed-by: Thomas Huth <thuth@redhat.com>
ae23c9
Message-id: 20181204035347.6148-2-jasowang@redhat.com
ae23c9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
ae23c9
(cherry picked from commit 25c01bd19d0e4b66f357618aeefda1ef7a41e21a)
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 include/net/net.h |  6 ------
ae23c9
 net/net.c         | 28 +++++++++++++++++-----------
ae23c9
 2 files changed, 17 insertions(+), 17 deletions(-)
ae23c9
ae23c9
diff --git a/include/net/net.h b/include/net/net.h
ae23c9
index 1f7341e..df4df25 100644
ae23c9
--- a/include/net/net.h
ae23c9
+++ b/include/net/net.h
ae23c9
@@ -170,12 +170,6 @@ void qemu_check_nic_model(NICInfo *nd, const char *model);
ae23c9
 int qemu_find_nic_model(NICInfo *nd, const char * const *models,
ae23c9
                         const char *default_model);
ae23c9
 
ae23c9
-ssize_t qemu_deliver_packet_iov(NetClientState *sender,
ae23c9
-                            unsigned flags,
ae23c9
-                            const struct iovec *iov,
ae23c9
-                            int iovcnt,
ae23c9
-                            void *opaque);
ae23c9
-
ae23c9
 void print_net_client(Monitor *mon, NetClientState *nc);
ae23c9
 void hmp_info_network(Monitor *mon, const QDict *qdict);
ae23c9
 void net_socket_rs_init(SocketReadState *rs,
ae23c9
diff --git a/net/net.c b/net/net.c
ae23c9
index c991243..6e5c335 100644
ae23c9
--- a/net/net.c
ae23c9
+++ b/net/net.c
ae23c9
@@ -231,6 +231,11 @@ static void qemu_net_client_destructor(NetClientState *nc)
ae23c9
 {
ae23c9
     g_free(nc);
ae23c9
 }
ae23c9
+static ssize_t qemu_deliver_packet_iov(NetClientState *sender,
ae23c9
+                                       unsigned flags,
ae23c9
+                                       const struct iovec *iov,
ae23c9
+                                       int iovcnt,
ae23c9
+                                       void *opaque);
ae23c9
 
ae23c9
 static void qemu_net_client_setup(NetClientState *nc,
ae23c9
                                   NetClientInfo *info,
ae23c9
@@ -705,22 +710,18 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
ae23c9
     return ret;
ae23c9
 }
ae23c9
 
ae23c9
-ssize_t qemu_deliver_packet_iov(NetClientState *sender,
ae23c9
-                                unsigned flags,
ae23c9
-                                const struct iovec *iov,
ae23c9
-                                int iovcnt,
ae23c9
-                                void *opaque)
ae23c9
+static ssize_t qemu_deliver_packet_iov(NetClientState *sender,
ae23c9
+                                       unsigned flags,
ae23c9
+                                       const struct iovec *iov,
ae23c9
+                                       int iovcnt,
ae23c9
+                                       void *opaque)
ae23c9
 {
ae23c9
     NetClientState *nc = opaque;
ae23c9
-    size_t size = iov_size(iov, iovcnt);
ae23c9
     int ret;
ae23c9
 
ae23c9
-    if (size > INT_MAX) {
ae23c9
-        return size;
ae23c9
-    }
ae23c9
 
ae23c9
     if (nc->link_down) {
ae23c9
-        return size;
ae23c9
+        return iov_size(iov, iovcnt);
ae23c9
     }
ae23c9
 
ae23c9
     if (nc->receive_disabled) {
ae23c9
@@ -745,10 +746,15 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender,
ae23c9
                                 NetPacketSent *sent_cb)
ae23c9
 {
ae23c9
     NetQueue *queue;
ae23c9
+    size_t size = iov_size(iov, iovcnt);
ae23c9
     int ret;
ae23c9
 
ae23c9
+    if (size > NET_BUFSIZE) {
ae23c9
+        return size;
ae23c9
+    }
ae23c9
+
ae23c9
     if (sender->link_down || !sender->peer) {
ae23c9
-        return iov_size(iov, iovcnt);
ae23c9
+        return size;
ae23c9
     }
ae23c9
 
ae23c9
     /* Let filters handle the packet first */
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9