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