9ae3a8
From 62121d1bd1f17f5b9822b98f4ee2c9fd159b50e5 Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Wed, 20 May 2015 08:39:09 +0200
9ae3a8
Subject: [PATCH 2/6] CVE-2015-1779: limit size of HTTP headers from websockets
9ae3a8
 clients
9ae3a8
9ae3a8
Message-id: <1432111149-11644-3-git-send-email-kraxel@redhat.com>
9ae3a8
Patchwork-id: 65097
9ae3a8
O-Subject: [RHEL-7.2 qemu-kvm PATCH 2/2] CVE-2015-1779: limit size of HTTP headers from websockets clients
9ae3a8
Bugzilla: 1206497
9ae3a8
RH-Acked-by: Thomas Huth <thuth@redhat.com>
9ae3a8
RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
9ae3a8
RH-Acked-by: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
9ae3a8
From: "Daniel P. Berrange" <berrange@redhat.com>
9ae3a8
9ae3a8
The VNC server websockets decoder will read and buffer data from
9ae3a8
websockets clients until it sees the end of the HTTP headers,
9ae3a8
as indicated by \r\n\r\n. In theory this allows a malicious to
9ae3a8
trick QEMU into consuming an arbitrary amount of RAM. In practice,
9ae3a8
because QEMU runs g_strstr_len() across the buffered header data,
9ae3a8
it will spend increasingly long burning CPU time searching for
9ae3a8
the substring match and less & less time reading data. So while
9ae3a8
this does cause arbitrary memory growth, the bigger problem is
9ae3a8
that QEMU will be burning 100% of available CPU time.
9ae3a8
9ae3a8
A novnc websockets client typically sends headers of around
9ae3a8
512 bytes in length. As such it is reasonable to place a 4096
9ae3a8
byte limit on the amount of data buffered while searching for
9ae3a8
the end of HTTP headers.
9ae3a8
9ae3a8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit 2cdb5e142fb93e875fa53c52864ef5eb8d5d8b41)
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 ui/vnc-ws.c | 10 ++++++++--
9ae3a8
 1 file changed, 8 insertions(+), 2 deletions(-)
9ae3a8
9ae3a8
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
9ae3a8
index a7d457c..7133be9 100644
9ae3a8
--- a/ui/vnc-ws.c
9ae3a8
+++ b/ui/vnc-ws.c
9ae3a8
@@ -88,8 +88,11 @@ void vncws_handshake_read(void *opaque)
9ae3a8
     VncState *vs = opaque;
9ae3a8
     uint8_t *handshake_end;
9ae3a8
     long ret;
9ae3a8
-    buffer_reserve(&vs->ws_input, 4096);
9ae3a8
-    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);
9ae3a8
+    /* Typical HTTP headers from novnc are 512 bytes, so limiting
9ae3a8
+     * total header size to 4096 is easily enough. */
9ae3a8
+    size_t want = 4096 - vs->ws_input.offset;
9ae3a8
+    buffer_reserve(&vs->ws_input, want);
9ae3a8
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want);
9ae3a8
 
9ae3a8
     if (!ret) {
9ae3a8
         if (vs->csock == -1) {
9ae3a8
@@ -106,6 +109,9 @@ void vncws_handshake_read(void *opaque)
9ae3a8
         vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
9ae3a8
         buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
9ae3a8
                 strlen(WS_HANDSHAKE_END));
9ae3a8
+    } else if (vs->ws_input.offset >= 4096) {
9ae3a8
+        VNC_DEBUG("End of headers not found in first 4096 bytes\n");
9ae3a8
+        vnc_client_error(vs);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8