9ae3a8
From 03f2b3e5198471d80c3740450113643dff2109ce Mon Sep 17 00:00:00 2001
9ae3a8
From: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Date: Thu, 16 Jul 2015 16:15:58 +0200
9ae3a8
Subject: [PATCH 1/3] ide: Check array bounds before writing to io_buffer
9ae3a8
 (CVE-2015-5154)
9ae3a8
9ae3a8
Message-id: <1437056160-3284-2-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: n/a
9ae3a8
O-Subject: [virt-devel] [RHEL/RHEV-7 qemu-kvm(-rhev) EMBARGOED PATCH 1/3] ide:
9ae3a8
        Check array bounds before writing to io_buffer (CVE-2015-5154)
9ae3a8
Bugzilla: 1243690
9ae3a8
RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
9ae3a8
RH-Acked-by: John Snow <jsnow@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
If the end_transfer_func of a command is called because enough data has
9ae3a8
been read or written for the current PIO transfer, and it fails to
9ae3a8
correctly call the command completion functions, the DRQ bit in the
9ae3a8
status register and s->end_transfer_func may remain set. This allows the
9ae3a8
guest to access further bytes in s->io_buffer beyond s->data_end, and
9ae3a8
eventually overflowing the io_buffer.
9ae3a8
9ae3a8
One case where this currently happens is emulation of the ATAPI command
9ae3a8
START STOP UNIT.
9ae3a8
9ae3a8
This patch fixes the problem by adding explicit array bounds checks
9ae3a8
before accessing the buffer instead of relying on end_transfer_func to
9ae3a8
function correctly.
9ae3a8
9ae3a8
Cc: qemu-stable@nongnu.org
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
---
9ae3a8
 hw/ide/core.c | 16 ++++++++++++++++
9ae3a8
 1 file changed, 16 insertions(+)
9ae3a8
9ae3a8
diff --git a/hw/ide/core.c b/hw/ide/core.c
9ae3a8
index d9fdb03..29bda6b 100644
9ae3a8
--- a/hw/ide/core.c
9ae3a8
+++ b/hw/ide/core.c
9ae3a8
@@ -1850,6 +1850,10 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
9ae3a8
     }
9ae3a8
 
9ae3a8
     p = s->data_ptr;
9ae3a8
+    if (p + 2 > s->data_end) {
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     *(uint16_t *)p = le16_to_cpu(val);
9ae3a8
     p += 2;
9ae3a8
     s->data_ptr = p;
9ae3a8
@@ -1871,6 +1875,10 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
9ae3a8
     }
9ae3a8
 
9ae3a8
     p = s->data_ptr;
9ae3a8
+    if (p + 2 > s->data_end) {
9ae3a8
+        return 0;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     ret = cpu_to_le16(*(uint16_t *)p);
9ae3a8
     p += 2;
9ae3a8
     s->data_ptr = p;
9ae3a8
@@ -1892,6 +1900,10 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
9ae3a8
     }
9ae3a8
 
9ae3a8
     p = s->data_ptr;
9ae3a8
+    if (p + 4 > s->data_end) {
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     *(uint32_t *)p = le32_to_cpu(val);
9ae3a8
     p += 4;
9ae3a8
     s->data_ptr = p;
9ae3a8
@@ -1913,6 +1925,10 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
9ae3a8
     }
9ae3a8
 
9ae3a8
     p = s->data_ptr;
9ae3a8
+    if (p + 4 > s->data_end) {
9ae3a8
+        return 0;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     ret = cpu_to_le32(*(uint32_t *)p);
9ae3a8
     p += 4;
9ae3a8
     s->data_ptr = p;
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8