9ae3a8
From 0ee28ebbde0313e54b0c8e0f316aa75f97c87169 Mon Sep 17 00:00:00 2001
9ae3a8
From: "Daniel P. Berrange" <berrange@redhat.com>
9ae3a8
Date: Thu, 8 Feb 2018 17:50:41 +0100
9ae3a8
Subject: [PATCH 27/27] io: skip updates to client if websocket output buffer
9ae3a8
 is non-zero
9ae3a8
9ae3a8
RH-Author: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
Message-id: <20180208175041.5634-28-berrange@redhat.com>
9ae3a8
Patchwork-id: 78959
9ae3a8
O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 27/27] io: skip updates to client if websocket output buffer is non-zero
9ae3a8
Bugzilla: 1518711
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
From: "Daniel P. Berrange" <berrange@redhat.com>
9ae3a8
9ae3a8
When getting a framebuffer update from the guest, we first check
9ae3a8
to see if there's still any queued data in the VNC send buffer.
9ae3a8
If there is, we skip the update so that we avoid having the send
9ae3a8
buffer grow without bound. Unfortunately, the code is only
9ae3a8
monitoring the normal send buffer, and not the websockets send
9ae3a8
buffer which is separate.
9ae3a8
9ae3a8
This flaw causes the websockets send buffer to grow without bound
9ae3a8
if the other end of the underlying data channel doesn't
9ae3a8
read data being sent. This can be seen with VNC if a client
9ae3a8
is on a slow WAN link and the guest OS is sending many screen
9ae3a8
updates. A malicious VNC client can act like it is on a slow
9ae3a8
link by playing a video in the guest and then reading data
9ae3a8
very slowly, causing QEMU host memory to expand arbitrarily.
9ae3a8
9ae3a8
This issue is assigned CVE-2017-15268, publically reported in
9ae3a8
9ae3a8
  https://bugs.launchpad.net/qemu/+bug/1718964
9ae3a8
9ae3a8
Reviewed-by: Eric Blake <eblake@redhat.com>
9ae3a8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
9ae3a8
The corresponding upstream fix is present in commit
9ae3a8
a7b20a8efa28e5f22c26c06cd06c2f12bc863493, however, this
9ae3a8
patch is a complete re-implementation since the upstream
9ae3a8
code for websockets is completely different to that in
9ae3a8
QEMU 1.5.3. As such ignore the Reviewed-by tag above.
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 ui/vnc-ws.c | 10 ++++++++--
9ae3a8
 ui/vnc.c    |  3 +++
9ae3a8
 2 files changed, 11 insertions(+), 2 deletions(-)
9ae3a8
9ae3a8
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
9ae3a8
index 7133be9..fbfadde 100644
9ae3a8
--- a/ui/vnc-ws.c
9ae3a8
+++ b/ui/vnc-ws.c
9ae3a8
@@ -173,8 +173,13 @@ long vnc_client_write_ws(VncState *vs)
9ae3a8
     long ret;
9ae3a8
     VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n",
9ae3a8
               vs->output.buffer, vs->output.capacity, vs->output.offset);
9ae3a8
-    vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset);
9ae3a8
-    buffer_reset(&vs->output);
9ae3a8
+    /* We don't consume more from 'output' unless we've finished
9ae3a8
+     * sending the previous websockets frame. This ensures that
9ae3a8
+     * we still correctly throttle forced framebuffer updates */
9ae3a8
+    if (vs->ws_output.offset == 0) {
9ae3a8
+        vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset);
9ae3a8
+        buffer_reset(&vs->output);
9ae3a8
+    }
9ae3a8
     ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset);
9ae3a8
     if (!ret) {
9ae3a8
         return 0;
9ae3a8
@@ -183,6 +188,7 @@ long vnc_client_write_ws(VncState *vs)
9ae3a8
     buffer_advance(&vs->ws_output, ret);
9ae3a8
 
9ae3a8
     if (vs->ws_output.offset == 0) {
9ae3a8
+        vs->force_update_offset = 0;
9ae3a8
         qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
9ae3a8
     }
9ae3a8
 
9ae3a8
diff --git a/ui/vnc.c b/ui/vnc.c
9ae3a8
index 2be87b8..99b1ab1 100644
9ae3a8
--- a/ui/vnc.c
9ae3a8
+++ b/ui/vnc.c
9ae3a8
@@ -915,6 +915,9 @@ static bool vnc_should_update(VncState *vs)
9ae3a8
          * is completely idle.
9ae3a8
          */
9ae3a8
         if (vs->output.offset < vs->throttle_output_offset &&
9ae3a8
+#ifdef CONFIG_VNC_WS
9ae3a8
+            vs->ws_output.offset  < vs->throttle_output_offset &&
9ae3a8
+#endif
9ae3a8
             vs->job_update == VNC_STATE_UPDATE_NONE) {
9ae3a8
             return true;
9ae3a8
         }
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8