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