From 605027b02ec0651889e07ee5d6f8d75ce60f2f6a Mon Sep 17 00:00:00 2001
From: CentOS Sources <bugs@centos.org>
Date: Tue, 27 Oct 2015 08:25:57 +0000
Subject: [PATCH] import qemu-kvm-1.5.3-86.el7_1.8

---
 SOURCES/kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch  |  253 +++++++++++++++++++++++++++++++
 SPECS/qemu-kvm.spec                                                    |   22 ++
 SOURCES/kvm-qtest-ide-test-disable-flush-test.patch                    |   86 ++++++++++
 SOURCES/kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch |   70 ++++++++
 4 files changed, 430 insertions(+), 1 deletions(-)

diff --git a/SOURCES/kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch b/SOURCES/kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch
new file mode 100644
index 0000000..234ec1e
--- /dev/null
+++ b/SOURCES/kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch
@@ -0,0 +1,253 @@
+From 2eae7bb4e94710164926c670334a83bf9d347c2f Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Tue, 22 Sep 2015 17:44:53 +0200
+Subject: [PATCH 1/2] CVE-2015-1779: incrementally decode websocket frames
+
+Message-id: <1442943894-7638-2-git-send-email-kraxel@redhat.com>
+Patchwork-id: 67884
+O-Subject: [RHEL-7.1.z qemu-kvm PATCH 1/2] CVE-2015-1779: incrementally decode websocket frames
+Bugzilla: 1205050
+RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
+RH-Acked-by: Thomas Huth <thuth@redhat.com>
+RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
+
+From: "Daniel P. Berrange" <berrange@redhat.com>
+
+The logic for decoding websocket frames wants to fully
+decode the frame header and payload, before allowing the
+VNC server to see any of the payload data. There is no
+size limit on websocket payloads, so this allows a
+malicious network client to consume 2^64 bytes in memory
+in QEMU. It can trigger this denial of service before
+the VNC server even performs any authentication.
+
+The fix is to decode the header, and then incrementally
+decode the payload data as it is needed. With this fix
+the websocket decoder will allow at most 4k of data to
+be buffered before decoding and processing payload.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+
+[ kraxel: fix frequent spurious disconnects, suggested by Peter Maydell ]
+
+  @@ -361,7 +361,7 @@ int vncws_decode_frame_payload(Buffer *input,
+  -        *payload_size = input->offset;
+  +        *payload_size = *payload_remain;
+
+[ kraxel: fix 32bit build ]
+
+  @@ -306,7 +306,7 @@ struct VncState
+  -    uint64_t ws_payload_remain;
+  +    size_t ws_payload_remain;
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+(cherry picked from commit a2bebfd6e09d285aa793cae3fb0fc3a39a9fee6e)
+Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
+---
+ ui/vnc-ws.c | 105 ++++++++++++++++++++++++++++++++++++++++--------------------
+ ui/vnc-ws.h |   9 ++++--
+ ui/vnc.h    |   2 ++
+ 3 files changed, 80 insertions(+), 36 deletions(-)
+
+diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
+index df89315..a7d457c 100644
+--- a/ui/vnc-ws.c
++++ b/ui/vnc-ws.c
+@@ -114,7 +114,7 @@ long vnc_client_read_ws(VncState *vs)
+ {
+     int ret, err;
+     uint8_t *payload;
+-    size_t payload_size, frame_size;
++    size_t payload_size, header_size;
+     VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer,
+             vs->ws_input.capacity, vs->ws_input.offset);
+     buffer_reserve(&vs->ws_input, 4096);
+@@ -124,18 +124,39 @@ long vnc_client_read_ws(VncState *vs)
+     }
+     vs->ws_input.offset += ret;
+ 
+-    /* make sure that nothing is left in the ws_input buffer */
++    ret = 0;
++    /* consume as much of ws_input buffer as possible */
+     do {
+-        err = vncws_decode_frame(&vs->ws_input, &payload,
+-                              &payload_size, &frame_size);
+-        if (err <= 0) {
+-            return err;
++        if (vs->ws_payload_remain == 0) {
++            err = vncws_decode_frame_header(&vs->ws_input,
++                                            &header_size,
++                                            &vs->ws_payload_remain,
++                                            &vs->ws_payload_mask);
++            if (err <= 0) {
++                return err;
++            }
++
++            buffer_advance(&vs->ws_input, header_size);
+         }
++        if (vs->ws_payload_remain != 0) {
++            err = vncws_decode_frame_payload(&vs->ws_input,
++                                             &vs->ws_payload_remain,
++                                             &vs->ws_payload_mask,
++                                             &payload,
++                                             &payload_size);
++            if (err < 0) {
++                return err;
++            }
++            if (err == 0) {
++                return ret;
++            }
++            ret += err;
+ 
+-        buffer_reserve(&vs->input, payload_size);
+-        buffer_append(&vs->input, payload, payload_size);
++            buffer_reserve(&vs->input, payload_size);
++            buffer_append(&vs->input, payload, payload_size);
+ 
+-        buffer_advance(&vs->ws_input, frame_size);
++            buffer_advance(&vs->ws_input, payload_size);
++        }
+     } while (vs->ws_input.offset > 0);
+ 
+     return ret;
+@@ -273,15 +294,14 @@ void vncws_encode_frame(Buffer *output, const void *payload,
+     buffer_append(output, payload, payload_size);
+ }
+ 
+-int vncws_decode_frame(Buffer *input, uint8_t **payload,
+-                           size_t *payload_size, size_t *frame_size)
++int vncws_decode_frame_header(Buffer *input,
++                              size_t *header_size,
++                              size_t *payload_remain,
++                              WsMask *payload_mask)
+ {
+     unsigned char opcode = 0, fin = 0, has_mask = 0;
+-    size_t header_size = 0;
+-    uint32_t *payload32;
++    size_t payload_len;
+     WsHeader *header = (WsHeader *)input->buffer;
+-    WsMask mask;
+-    int i;
+ 
+     if (input->offset < WS_HEAD_MIN_LEN + 4) {
+         /* header not complete */
+@@ -291,7 +311,7 @@ int vncws_decode_frame(Buffer *input, uint8_t **payload,
+     fin = (header->b0 & 0x80) >> 7;
+     opcode = header->b0 & 0x0f;
+     has_mask = (header->b1 & 0x80) >> 7;
+-    *payload_size = header->b1 & 0x7f;
++    payload_len = header->b1 & 0x7f;
+ 
+     if (opcode == WS_OPCODE_CLOSE) {
+         /* disconnect */
+@@ -308,40 +328,57 @@ int vncws_decode_frame(Buffer *input, uint8_t **payload,
+         return -2;
+     }
+ 
+-    if (*payload_size < 126) {
+-        header_size = 6;
+-        mask = header->u.m;
+-    } else if (*payload_size == 126 && input->offset >= 8) {
+-        *payload_size = be16_to_cpu(header->u.s16.l16);
+-        header_size = 8;
+-        mask = header->u.s16.m16;
+-    } else if (*payload_size == 127 && input->offset >= 14) {
+-        *payload_size = be64_to_cpu(header->u.s64.l64);
+-        header_size = 14;
+-        mask = header->u.s64.m64;
++    if (payload_len < 126) {
++        *payload_remain = payload_len;
++        *header_size = 6;
++        *payload_mask = header->u.m;
++    } else if (payload_len == 126 && input->offset >= 8) {
++        *payload_remain = be16_to_cpu(header->u.s16.l16);
++        *header_size = 8;
++        *payload_mask = header->u.s16.m16;
++    } else if (payload_len == 127 && input->offset >= 14) {
++        *payload_remain = be64_to_cpu(header->u.s64.l64);
++        *header_size = 14;
++        *payload_mask = header->u.s64.m64;
+     } else {
+         /* header not complete */
+         return 0;
+     }
+ 
+-    *frame_size = header_size + *payload_size;
++    return 1;
++}
++
++int vncws_decode_frame_payload(Buffer *input,
++                               size_t *payload_remain, WsMask *payload_mask,
++                               uint8_t **payload, size_t *payload_size)
++{
++    size_t i;
++    uint32_t *payload32;
+ 
+-    if (input->offset < *frame_size) {
+-        /* frame not complete */
++    *payload = input->buffer;
++    /* If we aren't at the end of the payload, then drop
++     * off the last bytes, so we're always multiple of 4
++     * for purpose of unmasking, except at end of payload
++     */
++    if (input->offset < *payload_remain) {
++        *payload_size = input->offset - (input->offset % 4);
++    } else {
++        *payload_size = *payload_remain;
++    }
++    if (*payload_size == 0) {
+         return 0;
+     }
+-
+-    *payload = input->buffer + header_size;
++    *payload_remain -= *payload_size;
+ 
+     /* unmask frame */
+     /* process 1 frame (32 bit op) */
+     payload32 = (uint32_t *)(*payload);
+     for (i = 0; i < *payload_size / 4; i++) {
+-        payload32[i] ^= mask.u;
++        payload32[i] ^= payload_mask->u;
+     }
+     /* process the remaining bytes (if any) */
+     for (i *= 4; i < *payload_size; i++) {
+-        (*payload)[i] ^= mask.c[i % 4];
++        (*payload)[i] ^= payload_mask->c[i % 4];
+     }
+ 
+     return 1;
+diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
+index 95c1b0a..6e93fa0 100644
+--- a/ui/vnc-ws.h
++++ b/ui/vnc-ws.h
+@@ -83,7 +83,12 @@ long vnc_client_read_ws(VncState *vs);
+ void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size);
+ void vncws_encode_frame(Buffer *output, const void *payload,
+             const size_t payload_size);
+-int vncws_decode_frame(Buffer *input, uint8_t **payload,
+-                               size_t *payload_size, size_t *frame_size);
++int vncws_decode_frame_header(Buffer *input,
++                              size_t *header_size,
++                              size_t *payload_remain,
++                              WsMask *payload_mask);
++int vncws_decode_frame_payload(Buffer *input,
++                               size_t *payload_remain, WsMask *payload_mask,
++                               uint8_t **payload, size_t *payload_size);
+ 
+ #endif /* __QEMU_UI_VNC_WS_H */
+diff --git a/ui/vnc.h b/ui/vnc.h
+index 6e99213..0efc5c6 100644
+--- a/ui/vnc.h
++++ b/ui/vnc.h
+@@ -290,6 +290,8 @@ struct VncState
+ #ifdef CONFIG_VNC_WS
+     Buffer ws_input;
+     Buffer ws_output;
++    size_t ws_payload_remain;
++    WsMask ws_payload_mask;
+ #endif
+     /* current output mode information */
+     VncWritePixels *write_pixels;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch b/SOURCES/kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch
new file mode 100644
index 0000000..4d3de63
--- /dev/null
+++ b/SOURCES/kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch
@@ -0,0 +1,70 @@
+From 7721e2e58f7cd2fcf835800622b8a7e1cdeb4557 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Tue, 22 Sep 2015 17:44:54 +0200
+Subject: [PATCH 2/2] CVE-2015-1779: limit size of HTTP headers from websockets
+ clients
+
+Message-id: <1442943894-7638-3-git-send-email-kraxel@redhat.com>
+Patchwork-id: 67885
+O-Subject: [RHEL-7.1.z qemu-kvm PATCH 2/2] CVE-2015-1779: limit size of HTTP headers from websockets clients
+Bugzilla: 1205050
+RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
+RH-Acked-by: Thomas Huth <thuth@redhat.com>
+RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
+
+From: "Daniel P. Berrange" <berrange@redhat.com>
+
+The VNC server websockets decoder will read and buffer data from
+websockets clients until it sees the end of the HTTP headers,
+as indicated by \r\n\r\n. In theory this allows a malicious to
+trick QEMU into consuming an arbitrary amount of RAM. In practice,
+because QEMU runs g_strstr_len() across the buffered header data,
+it will spend increasingly long burning CPU time searching for
+the substring match and less & less time reading data. So while
+this does cause arbitrary memory growth, the bigger problem is
+that QEMU will be burning 100% of available CPU time.
+
+A novnc websockets client typically sends headers of around
+512 bytes in length. As such it is reasonable to place a 4096
+byte limit on the amount of data buffered while searching for
+the end of HTTP headers.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+(cherry picked from commit 2cdb5e142fb93e875fa53c52864ef5eb8d5d8b41)
+Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
+---
+ ui/vnc-ws.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
+index a7d457c..7133be9 100644
+--- a/ui/vnc-ws.c
++++ b/ui/vnc-ws.c
+@@ -88,8 +88,11 @@ void vncws_handshake_read(void *opaque)
+     VncState *vs = opaque;
+     uint8_t *handshake_end;
+     long ret;
+-    buffer_reserve(&vs->ws_input, 4096);
+-    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);
++    /* Typical HTTP headers from novnc are 512 bytes, so limiting
++     * total header size to 4096 is easily enough. */
++    size_t want = 4096 - vs->ws_input.offset;
++    buffer_reserve(&vs->ws_input, want);
++    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want);
+ 
+     if (!ret) {
+         if (vs->csock == -1) {
+@@ -106,6 +109,9 @@ void vncws_handshake_read(void *opaque)
+         vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
+         buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
+                 strlen(WS_HANDSHAKE_END));
++    } else if (vs->ws_input.offset >= 4096) {
++        VNC_DEBUG("End of headers not found in first 4096 bytes\n");
++        vnc_client_error(vs);
+     }
+ }
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/kvm-qtest-ide-test-disable-flush-test.patch b/SOURCES/kvm-qtest-ide-test-disable-flush-test.patch
new file mode 100644
index 0000000..7624cff
--- /dev/null
+++ b/SOURCES/kvm-qtest-ide-test-disable-flush-test.patch
@@ -0,0 +1,86 @@
+From 699e404550228859f73ce42f36c6da538e1b0fb1 Mon Sep 17 00:00:00 2001
+Message-Id: <699e404550228859f73ce42f36c6da538e1b0fb1.1445289321.git.jen@redhat.com>
+From: John Snow <jsnow@redhat.com>
+Date: Mon, 19 Oct 2015 17:58:34 -0400
+Subject: [CHANGE] qtest/ide-test: disable flush-test
+To: rhvirt-patches@redhat.com,
+    jen@redhat.com
+
+RH-Author: John Snow <jsnow@redhat.com>
+Message-id: <1445277514-26179-2-git-send-email-jsnow@redhat.com>
+Patchwork-id: 68184
+O-Subject: [RHEL-7.1.z qemu-kvm PATCH 1/1] qtest/ide-test: disable flush-test
+Bugzilla: 1273098
+RH-Acked-by: Jeff Nelson <jenelson@redhat.com>
+RH-Acked-by: Wei Huang <wei@redhat.com>
+RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
+
+One of the tests downstream causes a race that can result in build
+failures. For 7.3, we intend to fix the test properly, but for 7.1.z
+and 7.2.*, we disable the test as a workaround.
+
+Signed-off-by: John Snow <jsnow@redhat.com>
+Signed-off-by: Jeff E. Nelson <jen@redhat.com>
+---
+ tests/ide-test.c | 38 --------------------------------------
+ 1 file changed, 38 deletions(-)
+
+diff --git a/tests/ide-test.c b/tests/ide-test.c
+index 51f9239..43b7fd6 100644
+--- a/tests/ide-test.c
++++ b/tests/ide-test.c
+@@ -425,43 +425,6 @@ static void test_identify(void)
+     ide_test_quit();
+ }
+ 
+-static void test_flush(void)
+-{
+-    uint8_t data;
+-
+-    ide_test_start(
+-        "-vnc none "
+-        "-drive file=blkdebug::%s,if=ide,cache=writeback",
+-        tmp_path);
+-
+-    /* Delay the completion of the flush request until we explicitly do it */
+-    qmp("{'execute':'human-monitor-command', 'arguments': { "
+-        "'command-line': 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }");
+-
+-    /* FLUSH CACHE command on device 0*/
+-    outb(IDE_BASE + reg_device, 0);
+-    outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+-
+-    /* Check status while request is in flight*/
+-    data = inb(IDE_BASE + reg_status);
+-    assert_bit_set(data, BSY | DRDY);
+-    assert_bit_clear(data, DF | ERR | DRQ);
+-
+-    /* Complete the command */
+-    qmp("{'execute':'human-monitor-command', 'arguments': { "
+-        "'command-line': 'qemu-io ide0-hd0 \"resume A\"'} }");
+-
+-    /* Check registers */
+-    data = inb(IDE_BASE + reg_device);
+-    g_assert_cmpint(data & DEV, ==, 0);
+-
+-    data = inb(IDE_BASE + reg_status);
+-    assert_bit_set(data, DRDY);
+-    assert_bit_clear(data, BSY | DF | ERR | DRQ);
+-
+-    ide_test_quit();
+-}
+-
+ static void test_flush_nodev(void)
+ {
+     ide_test_start("");
+@@ -505,7 +468,6 @@ int main(int argc, char **argv)
+     qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
+     qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
+ 
+-    qtest_add_func("/ide/flush", test_flush);
+     qtest_add_func("/ide/flush_nodev", test_flush_nodev);
+ 
+     ret = g_test_run();
+-- 
+2.4.3
+
diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec
index 86f4a7a..0820ccb 100644
--- a/SPECS/qemu-kvm.spec
+++ b/SPECS/qemu-kvm.spec
@@ -72,7 +72,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: %{pkgname}%{?pkgsuffix}
 Version: 1.5.3
-Release: 86%{?dist}.6
+Release: 86%{?dist}.8
 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped
 Epoch: 10
 License: GPLv2+ and LGPLv2+ and BSD
@@ -2859,6 +2859,12 @@
 Patch1404: kvm-rtl8139-skip-offload-on-short-TCP-header-CVE-2015-51.patch
 # For bz#1248764 - CVE-2015-5165 qemu-kvm: Qemu: rtl8139 uninitialized heap memory information leakage to guest [rhel-7.1.z]
 Patch1405: kvm-rtl8139-check-TCP-Data-Offset-field-CVE-2015-5165.patch
+# For bz#1205050 - CVE-2015-1779 qemu-kvm: qemu: vnc: insufficient resource limiting in VNC websockets decoder [rhel-7.1.z]
+Patch1406: kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch
+# For bz#1205050 - CVE-2015-1779 qemu-kvm: qemu: vnc: insufficient resource limiting in VNC websockets decoder [rhel-7.1.z]
+Patch1407: kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch
+# For bz#1273098 - qemu-kvm build failure race condition in tests/ide-test
+Patch1408: kvm-qtest-ide-test-disable-flush-test.patch
 
 
 BuildRequires: zlib-devel
@@ -4472,6 +4478,9 @@
 %patch1403 -p1
 %patch1404 -p1
 %patch1405 -p1
+%patch1406 -p1
+%patch1407 -p1
+%patch1408 -p1
 
 %build
 buildarch="%{kvm_target}-softmmu"
@@ -4916,6 +4925,17 @@
 %{_libdir}/pkgconfig/libcacard.pc
 
 %changelog
+* Mon Oct 19 2015 Jeff E. Nelson <jen@redhat.com> - 1.5.3-86.el7_1.8
+- kvm-qtest-ide-test-disable-flush-test.patch [bz#1273098]
+- Resolves: bz#1273098
+  (qemu-kvm build failure race condition in tests/ide-test)
+
+* Fri Oct 09 2015 Miroslav Rezanina <mrezanin@redhat.com> - 1.5.3-86.el7_1.7
+- kvm-CVE-2015-1779-incrementally-decode-websocket-frames.patch [bz#1205050]
+- kvm-CVE-2015-1779-limit-size-of-HTTP-headers-from-websoc.patch [bz#1205050]
+- Resolves: bz#1205050
+  (CVE-2015-1779 qemu-kvm: qemu: vnc: insufficient resource limiting in VNC websockets decoder [rhel-7.1.z])
+
 * Thu Aug 06 2015 Miroslav Rezanina <mrezanin@redhat.com> - 1.5.3-86.el7_1.6
 - kvm-rtl8139-avoid-nested-ifs-in-IP-header-parsing-CVE-20.patch [bz#1248764]
 - kvm-rtl8139-drop-tautologous-if-ip-.-statement-CVE-2015-.patch [bz#1248764]

--
Gitblit v1.8.0