Blame SOURCES/kvm-io-skip-updates-to-client-if-websocket-output-buffer.patch

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