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