9ae3a8
From 7262d3c7280343601ab3b0be0d469ffb867b86d7 Mon Sep 17 00:00:00 2001
9ae3a8
From: Markus Armbruster <armbru@redhat.com>
9ae3a8
Date: Fri, 31 Oct 2014 16:29:55 +0100
9ae3a8
Subject: [PATCH 18/19] ide: Treat read/write beyond end as invalid
9ae3a8
9ae3a8
Message-id: <1414772996-17272-5-git-send-email-armbru@redhat.com>
9ae3a8
Patchwork-id: 62015
9ae3a8
O-Subject: [PATCH RHEL-7.1 qemu-kvm 4/5] ide: Treat read/write beyond end as invalid
9ae3a8
Bugzilla: 1085232
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Fam Zheng <famz@redhat.com>
9ae3a8
9ae3a8
The block layer fails such reads and writes just fine.  However, they
9ae3a8
then get treated like valid operations that fail: the error action
9ae3a8
gets executed.  Unwanted; reporting the error to the guest is the only
9ae3a8
sensible action.
9ae3a8
9ae3a8
Reject them before passing them to the block layer.  This bypasses the
9ae3a8
error action and I/O accounting.  Not quite correct for DMA, because
9ae3a8
DMA can fail after some success, and when that happens, the part that
9ae3a8
succeeded isn't counted.  Tolerable, because I/O accounting is an
9ae3a8
inconsistent mess anyway.
9ae3a8
9ae3a8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
(cherry picked from commit 58ac321135af890b503ebe56d0d00e184779918f)
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/ide/core.c | 28 ++++++++++++++++++++++++++++
9ae3a8
 1 file changed, 28 insertions(+)
9ae3a8
9ae3a8
diff --git a/hw/ide/core.c b/hw/ide/core.c
9ae3a8
index 98128fb..4c36f52 100644
9ae3a8
--- a/hw/ide/core.c
9ae3a8
+++ b/hw/ide/core.c
9ae3a8
@@ -513,6 +513,18 @@ static void ide_rw_error(IDEState *s) {
9ae3a8
     ide_set_irq(s->bus);
9ae3a8
 }
9ae3a8
 
9ae3a8
+static bool ide_sect_range_ok(IDEState *s,
9ae3a8
+                              uint64_t sector, uint64_t nb_sectors)
9ae3a8
+{
9ae3a8
+    uint64_t total_sectors;
9ae3a8
+
9ae3a8
+    bdrv_get_geometry(s->bs, &total_sectors);
9ae3a8
+    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
9ae3a8
+        return false;
9ae3a8
+    }
9ae3a8
+    return true;
9ae3a8
+}
9ae3a8
+
9ae3a8
 static void ide_sector_read_cb(void *opaque, int ret)
9ae3a8
 {
9ae3a8
     IDEState *s = opaque;
9ae3a8
@@ -568,6 +580,11 @@ void ide_sector_read(IDEState *s)
9ae3a8
     printf("sector=%" PRId64 "\n", sector_num);
9ae3a8
 #endif
9ae3a8
 
9ae3a8
+    if (!ide_sect_range_ok(s, sector_num, n)) {
9ae3a8
+        ide_rw_error(s);
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     s->iov.iov_base = s->io_buffer;
9ae3a8
     s->iov.iov_len  = n * BDRV_SECTOR_SIZE;
9ae3a8
     qemu_iovec_init_external(&s->qiov, &s->iov, 1);
9ae3a8
@@ -685,6 +702,12 @@ void ide_dma_cb(void *opaque, int ret)
9ae3a8
            sector_num, n, s->dma_cmd);
9ae3a8
 #endif
9ae3a8
 
9ae3a8
+    if (!ide_sect_range_ok(s, sector_num, n)) {
9ae3a8
+        dma_buf_commit(s);
9ae3a8
+        ide_dma_error(s);
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     switch (s->dma_cmd) {
9ae3a8
     case IDE_DMA_READ:
9ae3a8
         s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
9ae3a8
@@ -804,6 +827,11 @@ void ide_sector_write(IDEState *s)
9ae3a8
         n = s->req_nb_sectors;
9ae3a8
     }
9ae3a8
 
9ae3a8
+    if (!ide_sect_range_ok(s, sector_num, n)) {
9ae3a8
+        ide_rw_error(s);
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     s->iov.iov_base = s->io_buffer;
9ae3a8
     s->iov.iov_len  = n * BDRV_SECTOR_SIZE;
9ae3a8
     qemu_iovec_init_external(&s->qiov, &s->iov, 1);
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8