5e0a924
From: Kevin Wolf <kwolf@redhat.com>
5e0a924
Date: Sun, 26 Jul 2015 23:42:53 -0400
5e0a924
Subject: [PATCH] ide: Check array bounds before writing to io_buffer
5e0a924
 (CVE-2015-5154)
5e0a924
5e0a924
If the end_transfer_func of a command is called because enough data has
5e0a924
been read or written for the current PIO transfer, and it fails to
5e0a924
correctly call the command completion functions, the DRQ bit in the
5e0a924
status register and s->end_transfer_func may remain set. This allows the
5e0a924
guest to access further bytes in s->io_buffer beyond s->data_end, and
5e0a924
eventually overflowing the io_buffer.
5e0a924
5e0a924
One case where this currently happens is emulation of the ATAPI command
5e0a924
START STOP UNIT.
5e0a924
5e0a924
This patch fixes the problem by adding explicit array bounds checks
5e0a924
before accessing the buffer instead of relying on end_transfer_func to
5e0a924
function correctly.
5e0a924
5e0a924
Cc: qemu-stable@nongnu.org
5e0a924
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5e0a924
Reviewed-by: John Snow <jsnow@redhat.com>
5e0a924
(cherry picked from commit d2ff85854512574e7209f295e87b0835d5b032c6)
5e0a924
---
5e0a924
 hw/ide/core.c | 16 ++++++++++++++++
5e0a924
 1 file changed, 16 insertions(+)
5e0a924
5e0a924
diff --git a/hw/ide/core.c b/hw/ide/core.c
5e0a924
index 50691fc..a5a62cd 100644
5e0a924
--- a/hw/ide/core.c
5e0a924
+++ b/hw/ide/core.c
5e0a924
@@ -1931,6 +1931,10 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
5e0a924
     }
5e0a924
 
5e0a924
     p = s->data_ptr;
5e0a924
+    if (p + 2 > s->data_end) {
5e0a924
+        return;
5e0a924
+    }
5e0a924
+
5e0a924
     *(uint16_t *)p = le16_to_cpu(val);
5e0a924
     p += 2;
5e0a924
     s->data_ptr = p;
5e0a924
@@ -1952,6 +1956,10 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
5e0a924
     }
5e0a924
 
5e0a924
     p = s->data_ptr;
5e0a924
+    if (p + 2 > s->data_end) {
5e0a924
+        return 0;
5e0a924
+    }
5e0a924
+
5e0a924
     ret = cpu_to_le16(*(uint16_t *)p);
5e0a924
     p += 2;
5e0a924
     s->data_ptr = p;
5e0a924
@@ -1973,6 +1981,10 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
5e0a924
     }
5e0a924
 
5e0a924
     p = s->data_ptr;
5e0a924
+    if (p + 4 > s->data_end) {
5e0a924
+        return;
5e0a924
+    }
5e0a924
+
5e0a924
     *(uint32_t *)p = le32_to_cpu(val);
5e0a924
     p += 4;
5e0a924
     s->data_ptr = p;
5e0a924
@@ -1994,6 +2006,10 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
5e0a924
     }
5e0a924
 
5e0a924
     p = s->data_ptr;
5e0a924
+    if (p + 4 > s->data_end) {
5e0a924
+        return 0;
5e0a924
+    }
5e0a924
+
5e0a924
     ret = cpu_to_le32(*(uint32_t *)p);
5e0a924
     p += 4;
5e0a924
     s->data_ptr = p;