|
|
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 |
|