xen/CVE-2015-1779-qemuu-incrementally-decode-websocket-frames.patch
Charles Arnold 39134eb9d2 - bsc#962758 - VUL-0: CVE-2013-4539: xen: tsc210x: buffer overrun
on invalid state load
  CVE-2013-4539-qemut-tsc210x-fix-buffer-overrun-on-invalid-state-load.patch

- bsc#962632 - VUL-0: CVE-2015-1779: xen: vnc: insufficient
  resource limiting in VNC websockets decoder
  CVE-2015-1779-qemuu-limit-size-of-HTTP-headers-from-websockets-clients.patch
  CVE-2015-1779-qemuu-incrementally-decode-websocket-frames.patch
- bsc#962642 - VUL-0: CVE-2013-4537: xen: ssi-sd: buffer overrun on
  invalid state load
  CVE-2013-4537-qemut-ssi-sd-fix-buffer-overrun-on-invalid-state-load.patch
- bsc#962627 - VUL-0: CVE-2014-7815: xen: vnc: insufficient
  bits_per_pixel from the client sanitization
  CVE-2014-7815-qemut-vnc-sanitize-bits_per_pixel-from-the-client.patch

- bsc#962335 - VUL-0: CVE-2013-4538: xen: ssd0323: fix buffer
  overun on invalid state
  CVE-2013-4538-qemut-ssd0323-fix-buffer-overun-on-invalid-state.patch
- bsc#962360 - VUL-0: CVE-2015-7512: xen: net: pcnet: buffer
  overflow in non-loopback mode
  CVE-2015-7512-qemuu-net-pcnet-buffer-overflow-in-non-loopback-mode.patch
  CVE-2015-7512-qemut-net-pcnet-buffer-overflow-in-non-loopback-mode.patch

- bsc#961692 - VUL-0: CVE-2016-1714: xen: nvram: OOB r/w access in
  processing firmware configurations
  CVE-2016-1714-qemuu-fw_cfg-add-check-to-validate-current-entry-value.patch
  CVE-2016-1714-qemut-fw_cfg-add-check-to-validate-current-entry-value.patch

- bsc#961358 - VUL-0: CVE-2015-8613: xen: qemu: scsi: stack based
  buffer overflow in megasas_ctrl_get_info

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=395
2016-01-20 16:26:32 +00:00

223 lines
8.3 KiB
Diff

References: bsc#962632 CVE-2015-1779
Subject: CVE-2015-1779: incrementally decode websocket frames
From: Daniel P. Berrange berrange@redhat.com Mon Mar 23 22:58:21 2015 +0000
Date: Wed Apr 1 17:11:34 2015 +0200:
Git: a2bebfd6e09d285aa793cae3fb0fc3a39a9fee6e
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>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Index: xen-4.6.0-testing/tools/qemu-xen-dir-remote/ui/vnc-ws.c
===================================================================
--- xen-4.6.0-testing.orig/tools/qemu-xen-dir-remote/ui/vnc-ws.c
+++ xen-4.6.0-testing/tools/qemu-xen-dir-remote/ui/vnc-ws.c
@@ -115,7 +115,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);
@@ -125,18 +125,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;
@@ -274,15 +295,14 @@ void vncws_encode_frame(Buffer *output,
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 */
@@ -292,7 +312,7 @@ int vncws_decode_frame(Buffer *input, ui
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 */
@@ -309,40 +329,57 @@ int vncws_decode_frame(Buffer *input, ui
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;
+}
- if (input->offset < *frame_size) {
- /* frame not complete */
+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;
+
+ *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;
Index: xen-4.6.0-testing/tools/qemu-xen-dir-remote/ui/vnc-ws.h
===================================================================
--- xen-4.6.0-testing.orig/tools/qemu-xen-dir-remote/ui/vnc-ws.h
+++ xen-4.6.0-testing/tools/qemu-xen-dir-remote/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 */
Index: xen-4.6.0-testing/tools/qemu-xen-dir-remote/ui/vnc.h
===================================================================
--- xen-4.6.0-testing.orig/tools/qemu-xen-dir-remote/ui/vnc.h
+++ xen-4.6.0-testing/tools/qemu-xen-dir-remote/ui/vnc.h
@@ -302,6 +302,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;