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

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