Blame SOURCES/kvm-raw-Check-byte-range-uniformly.patch

383d26
From f0714015bbe871d1f0c1fe9d8b8c7bd2afc2a0a0 Mon Sep 17 00:00:00 2001
383d26
From: Fam Zheng <famz@redhat.com>
383d26
Date: Fri, 29 Jun 2018 06:11:42 +0200
383d26
Subject: [PATCH 38/57] raw: Check byte range uniformly
383d26
383d26
RH-Author: Fam Zheng <famz@redhat.com>
383d26
Message-id: <20180629061153.12687-3-famz@redhat.com>
383d26
Patchwork-id: 81152
383d26
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 02/13] raw: Check byte range uniformly
383d26
Bugzilla: 1482537
383d26
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
RH-Acked-by: Max Reitz <mreitz@redhat.com>
383d26
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
383d26
383d26
We don't verify the request range against s->size in the I/O callbacks
383d26
except for raw_co_pwritev. This is inconsistent (especially for
383d26
raw_co_pwrite_zeroes and raw_co_pdiscard), so fix them, in the meanwhile
383d26
make the helper reusable by the coming new callbacks.
383d26
383d26
Note that in most cases the block layer already verifies the request
383d26
byte range against our reported image length, before invoking the driver
383d26
callbacks.  The exception is during image creating, after
383d26
blk_set_allow_write_beyond_eof(blk, true) is called. But in that case,
383d26
the requests are not directly from the user or guest. So there is no
383d26
visible behavior change in adding the check code.
383d26
383d26
The int64_t -> uint64_t inconsistency, as shown by the type casting, is
383d26
pre-existing due to the interface.
383d26
383d26
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
Reviewed-by: Eric Blake <eblake@redhat.com>
383d26
Signed-off-by: Fam Zheng <famz@redhat.com>
383d26
Message-id: 20180601092648.24614-3-famz@redhat.com
383d26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
(cherry picked from commit 384455385248762e74a080978f18f0c8f74757fe)
383d26
Signed-off-by: Fam Zheng <famz@redhat.com>
383d26
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
383d26
---
383d26
 block/raw-format.c | 64 +++++++++++++++++++++++++++++++++---------------------
383d26
 1 file changed, 39 insertions(+), 25 deletions(-)
383d26
383d26
diff --git a/block/raw-format.c b/block/raw-format.c
383d26
index fe33693..b69a067 100644
383d26
--- a/block/raw-format.c
383d26
+++ b/block/raw-format.c
383d26
@@ -167,16 +167,37 @@ static void raw_reopen_abort(BDRVReopenState *state)
383d26
     state->opaque = NULL;
383d26
 }
383d26
 
383d26
+/* Check and adjust the offset, against 'offset' and 'size' options. */
383d26
+static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset,
383d26
+                                    uint64_t bytes, bool is_write)
383d26
+{
383d26
+    BDRVRawState *s = bs->opaque;
383d26
+
383d26
+    if (s->has_size && (*offset > s->size || bytes > (s->size - *offset))) {
383d26
+        /* There's not enough space for the write, or the read request is
383d26
+         * out-of-range. Don't read/write anything to prevent leaking out of
383d26
+         * the size specified in options. */
383d26
+        return is_write ? -ENOSPC : -EINVAL;;
383d26
+    }
383d26
+
383d26
+    if (*offset > INT64_MAX - s->offset) {
383d26
+        return -EINVAL;
383d26
+    }
383d26
+    *offset += s->offset;
383d26
+
383d26
+    return 0;
383d26
+}
383d26
+
383d26
 static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
383d26
                                       uint64_t bytes, QEMUIOVector *qiov,
383d26
                                       int flags)
383d26
 {
383d26
-    BDRVRawState *s = bs->opaque;
383d26
+    int ret;
383d26
 
383d26
-    if (offset > UINT64_MAX - s->offset) {
383d26
-        return -EINVAL;
383d26
+    ret = raw_adjust_offset(bs, &offset, bytes, false);
383d26
+    if (ret) {
383d26
+        return ret;
383d26
     }
383d26
-    offset += s->offset;
383d26
 
383d26
     BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
383d26
     return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
383d26
@@ -186,23 +207,11 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
383d26
                                        uint64_t bytes, QEMUIOVector *qiov,
383d26
                                        int flags)
383d26
 {
383d26
-    BDRVRawState *s = bs->opaque;
383d26
     void *buf = NULL;
383d26
     BlockDriver *drv;
383d26
     QEMUIOVector local_qiov;
383d26
     int ret;
383d26
 
383d26
-    if (s->has_size && (offset > s->size || bytes > (s->size - offset))) {
383d26
-        /* There's not enough space for the data. Don't write anything and just
383d26
-         * fail to prevent leaking out of the size specified in options. */
383d26
-        return -ENOSPC;
383d26
-    }
383d26
-
383d26
-    if (offset > UINT64_MAX - s->offset) {
383d26
-        ret = -EINVAL;
383d26
-        goto fail;
383d26
-    }
383d26
-
383d26
     if (bs->probed && offset < BLOCK_PROBE_BUF_SIZE && bytes) {
383d26
         /* Handling partial writes would be a pain - so we just
383d26
          * require that guests have 512-byte request alignment if
383d26
@@ -237,7 +246,10 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
383d26
         qiov = &local_qiov;
383d26
     }
383d26
 
383d26
-    offset += s->offset;
383d26
+    ret = raw_adjust_offset(bs, &offset, bytes, true);
383d26
+    if (ret) {
383d26
+        goto fail;
383d26
+    }
383d26
 
383d26
     BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
383d26
     ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
383d26
@@ -267,22 +279,24 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
383d26
                                              int64_t offset, int bytes,
383d26
                                              BdrvRequestFlags flags)
383d26
 {
383d26
-    BDRVRawState *s = bs->opaque;
383d26
-    if (offset > UINT64_MAX - s->offset) {
383d26
-        return -EINVAL;
383d26
+    int ret;
383d26
+
383d26
+    ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
383d26
+    if (ret) {
383d26
+        return ret;
383d26
     }
383d26
-    offset += s->offset;
383d26
     return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
383d26
 }
383d26
 
383d26
 static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
383d26
                                         int64_t offset, int bytes)
383d26
 {
383d26
-    BDRVRawState *s = bs->opaque;
383d26
-    if (offset > UINT64_MAX - s->offset) {
383d26
-        return -EINVAL;
383d26
+    int ret;
383d26
+
383d26
+    ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
383d26
+    if (ret) {
383d26
+        return ret;
383d26
     }
383d26
-    offset += s->offset;
383d26
     return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
383d26
 }
383d26
 
383d26
-- 
383d26
1.8.3.1
383d26