6 changed files with 257 additions and 1 deletions
@ -0,0 +1,41 @@ |
|||
From: Petr Matousek <pmatouse@redhat.com> |
|||
Date: Wed, 17 Jun 2015 10:46:11 +0000 (+0200) |
|||
Subject: i8254: fix out-of-bounds memory access in pit_ioport_read() |
|||
X-Git-Tag: v2.4.0-rc0~43^2~9 |
|||
X-Git-Url: http://git.qemu.org/?p=qemu.git;a=commitdiff_plain;h=d4862a87e31a51de9eb260f25c9e99a75efe3235;hp=9dacf32d2cbd66cbcce7944ebdfd6b2df20e33b8 |
|||
|
|||
i8254: fix out-of-bounds memory access in pit_ioport_read() |
|||
|
|||
Due converting PIO to the new memory read/write api we no longer provide |
|||
separate I/O region lenghts for read and write operations. As a result, |
|||
reading from PIT Mode/Command register will end with accessing |
|||
pit->channels with invalid index. |
|||
|
|||
Fix this by ignoring read from the Mode/Command register. |
|||
|
|||
This is CVE-2015-3214. |
|||
|
|||
Reported-by: Matt Tait <matttait@google.com> |
|||
Fixes: 0505bcdec8228d8de39ab1a02644e71999e7c052 |
|||
Cc: qemu-stable@nongnu.org |
|||
Signed-off-by: Petr Matousek <pmatouse@redhat.com> |
|||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
|||
---
|
|||
|
|||
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
|
|||
index 3450c98..9b65a33 100644
|
|||
--- a/hw/timer/i8254.c
|
|||
+++ b/hw/timer/i8254.c
|
|||
@@ -196,6 +196,12 @@ static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
|
|||
PITChannelState *s; |
|||
|
|||
addr &= 3; |
|||
+
|
|||
+ if (addr == 3) {
|
|||
+ /* Mode/Command register is write only, read is ignored */
|
|||
+ return 0;
|
|||
+ }
|
|||
+
|
|||
s = &pit->channels[addr]; |
|||
if (s->status_latched) { |
|||
s->status_latched = 0; |
@ -0,0 +1,75 @@ |
|||
From d2ff85854512574e7209f295e87b0835d5b032c6 Mon Sep 17 00:00:00 2001 |
|||
From: Kevin Wolf <kwolf@redhat.com> |
|||
Date: Sun, 26 Jul 2015 23:42:53 -0400 |
|||
Subject: [PATCH] ide: Check array bounds before writing to io_buffer |
|||
(CVE-2015-5154) |
|||
|
|||
If the end_transfer_func of a command is called because enough data has |
|||
been read or written for the current PIO transfer, and it fails to |
|||
correctly call the command completion functions, the DRQ bit in the |
|||
status register and s->end_transfer_func may remain set. This allows the |
|||
guest to access further bytes in s->io_buffer beyond s->data_end, and |
|||
eventually overflowing the io_buffer. |
|||
|
|||
One case where this currently happens is emulation of the ATAPI command |
|||
START STOP UNIT. |
|||
|
|||
This patch fixes the problem by adding explicit array bounds checks |
|||
before accessing the buffer instead of relying on end_transfer_func to |
|||
function correctly. |
|||
|
|||
Cc: qemu-stable@nongnu.org |
|||
Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
|||
Reviewed-by: John Snow <jsnow@redhat.com> |
|||
---
|
|||
hw/ide/core.c | 16 ++++++++++++++++ |
|||
1 file changed, 16 insertions(+) |
|||
|
|||
diff --git a/hw/ide/core.c b/hw/ide/core.c
|
|||
index 122e955..44fcc23 100644
|
|||
--- a/hw/ide/core.c
|
|||
+++ b/hw/ide/core.c
|
|||
@@ -2021,6 +2021,10 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
|||
} |
|||
|
|||
p = s->data_ptr; |
|||
+ if (p + 2 > s->data_end) {
|
|||
+ return;
|
|||
+ }
|
|||
+
|
|||
*(uint16_t *)p = le16_to_cpu(val); |
|||
p += 2; |
|||
s->data_ptr = p; |
|||
@@ -2042,6 +2046,10 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
|||
} |
|||
|
|||
p = s->data_ptr; |
|||
+ if (p + 2 > s->data_end) {
|
|||
+ return 0;
|
|||
+ }
|
|||
+
|
|||
ret = cpu_to_le16(*(uint16_t *)p); |
|||
p += 2; |
|||
s->data_ptr = p; |
|||
@@ -2063,6 +2071,10 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
|||
} |
|||
|
|||
p = s->data_ptr; |
|||
+ if (p + 4 > s->data_end) {
|
|||
+ return;
|
|||
+ }
|
|||
+
|
|||
*(uint32_t *)p = le32_to_cpu(val); |
|||
p += 4; |
|||
s->data_ptr = p; |
|||
@@ -2084,6 +2096,10 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
|||
} |
|||
|
|||
p = s->data_ptr; |
|||
+ if (p + 4 > s->data_end) {
|
|||
+ return 0;
|
|||
+ }
|
|||
+
|
|||
ret = cpu_to_le32(*(uint32_t *)p); |
|||
p += 4; |
|||
s->data_ptr = p; |
@ -0,0 +1,26 @@ |
|||
From 03441c3a4a42beb25460dd11592539030337d0f8 Mon Sep 17 00:00:00 2001 |
|||
From: Kevin Wolf <kwolf@redhat.com> |
|||
Date: Sun, 26 Jul 2015 23:42:53 -0400 |
|||
Subject: [PATCH] ide/atapi: Fix START STOP UNIT command completion |
|||
|
|||
The command must be completed on all code paths. START STOP UNIT with |
|||
pwrcnd set should succeed without doing anything. |
|||
|
|||
Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
|||
Reviewed-by: John Snow <jsnow@redhat.com> |
|||
---
|
|||
hw/ide/atapi.c | 1 + |
|||
1 file changed, 1 insertion(+) |
|||
|
|||
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
|
|||
index 950e311..79dd167 100644
|
|||
--- a/hw/ide/atapi.c
|
|||
+++ b/hw/ide/atapi.c
|
|||
@@ -983,6 +983,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
|
|||
|
|||
if (pwrcnd) { |
|||
/* eject/load only happens for power condition == 0 */ |
|||
+ ide_atapi_cmd_ok(s);
|
|||
return; |
|||
} |
|||
|
@ -0,0 +1,69 @@ |
|||
From cb72cba83021fa42719e73a5249c12096a4d1cfc Mon Sep 17 00:00:00 2001 |
|||
From: Kevin Wolf <kwolf@redhat.com> |
|||
Date: Sun, 26 Jul 2015 23:42:53 -0400 |
|||
Subject: [PATCH] ide: Clear DRQ after handling all expected accesses |
|||
|
|||
This is additional hardening against an end_transfer_func that fails to |
|||
clear the DRQ status bit. The bit must be unset as soon as the PIO |
|||
transfer has completed, so it's better to do this in a central place |
|||
instead of duplicating the code in all commands (and forgetting it in |
|||
some). |
|||
|
|||
Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
|||
Reviewed-by: John Snow <jsnow@redhat.com> |
|||
---
|
|||
hw/ide/core.c | 16 ++++++++++++---- |
|||
1 file changed, 12 insertions(+), 4 deletions(-) |
|||
|
|||
diff --git a/hw/ide/core.c b/hw/ide/core.c
|
|||
index 44fcc23..50449ca 100644
|
|||
--- a/hw/ide/core.c
|
|||
+++ b/hw/ide/core.c
|
|||
@@ -2028,8 +2028,10 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
|||
*(uint16_t *)p = le16_to_cpu(val); |
|||
p += 2; |
|||
s->data_ptr = p; |
|||
- if (p >= s->data_end)
|
|||
+ if (p >= s->data_end) {
|
|||
+ s->status &= ~DRQ_STAT;
|
|||
s->end_transfer_func(s); |
|||
+ }
|
|||
} |
|||
|
|||
uint32_t ide_data_readw(void *opaque, uint32_t addr) |
|||
@@ -2053,8 +2055,10 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
|||
ret = cpu_to_le16(*(uint16_t *)p); |
|||
p += 2; |
|||
s->data_ptr = p; |
|||
- if (p >= s->data_end)
|
|||
+ if (p >= s->data_end) {
|
|||
+ s->status &= ~DRQ_STAT;
|
|||
s->end_transfer_func(s); |
|||
+ }
|
|||
return ret; |
|||
} |
|||
|
|||
@@ -2078,8 +2082,10 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
|||
*(uint32_t *)p = le32_to_cpu(val); |
|||
p += 4; |
|||
s->data_ptr = p; |
|||
- if (p >= s->data_end)
|
|||
+ if (p >= s->data_end) {
|
|||
+ s->status &= ~DRQ_STAT;
|
|||
s->end_transfer_func(s); |
|||
+ }
|
|||
} |
|||
|
|||
uint32_t ide_data_readl(void *opaque, uint32_t addr) |
|||
@@ -2103,8 +2109,10 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
|||
ret = cpu_to_le32(*(uint32_t *)p); |
|||
p += 4; |
|||
s->data_ptr = p; |
|||
- if (p >= s->data_end)
|
|||
+ if (p >= s->data_end) {
|
|||
+ s->status &= ~DRQ_STAT;
|
|||
s->end_transfer_func(s); |
|||
+ }
|
|||
return ret; |
|||
} |
|||
|
@ -0,0 +1,40 @@ |
|||
commit c170aad8b057223b1139d72e5ce7acceafab4fa9 |
|||
Author: Paolo Bonzini <pbonzini@redhat.com> |
|||
Date: Tue Jul 21 08:59:39 2015 +0200 |
|||
|
|||
scsi: fix buffer overflow in scsi_req_parse_cdb (CVE-2015-5158) |
|||
|
|||
This is a guest-triggerable buffer overflow present in QEMU 2.2.0 |
|||
and newer. scsi_cdb_length returns -1 as an error value, but the |
|||
caller does not check it. |
|||
|
|||
Luckily, the massive overflow means that QEMU will just SIGSEGV, |
|||
making the impact much smaller. |
|||
|
|||
Reported-by: Zhu Donghai (朱东海) <donghai.zdh@alibaba-inc.com> |
|||
Fixes: 1894df02811f6b79ea3ffbf1084599d96f316173 |
|||
Reviewed-by: Fam Zheng <famz@redhat.com> |
|||
Cc: qemu-stable@nongnu.org |
|||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
|||
|
|||
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
|
|||
index f50b2f0..f0ae462 100644
|
|||
--- a/hw/scsi/scsi-bus.c
|
|||
+++ b/hw/scsi/scsi-bus.c
|
|||
@@ -1239,10 +1239,15 @@ int scsi_cdb_length(uint8_t *buf) {
|
|||
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) |
|||
{ |
|||
int rc; |
|||
+ int len;
|
|||
|
|||
cmd->lba = -1; |
|||
- cmd->len = scsi_cdb_length(buf);
|
|||
+ len = scsi_cdb_length(buf);
|
|||
+ if (len < 0) {
|
|||
+ return -1;
|
|||
+ }
|
|||
|
|||
+ cmd->len = len;
|
|||
switch (dev->type) { |
|||
case TYPE_TAPE: |
|||
rc = scsi_req_stream_xfer(cmd, dev, buf); |
Loading…
Reference in new issue