qcow2: add overlap check for bitmap directory

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-id: 20180705151515.779173-1-vsementsov@virtuozzo.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2018-07-05 18:15:15 +03:00 committed by Max Reitz
parent 85456e0d16
commit 0e4e4318ea
5 changed files with 64 additions and 37 deletions

View File

@ -775,7 +775,12 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
} }
} }
ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size); /* Actually, even in in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY is not
* necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating bitmap
* directory in-place (actually, turn-off the extension), which is checked
* in qcow2_check_metadata_overlap() */
ret = qcow2_pre_write_overlap_check(
bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }

View File

@ -2705,6 +2705,16 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
} }
} }
if ((chk & QCOW2_OL_BITMAP_DIRECTORY) &&
(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS))
{
if (overlaps_with(s->bitmap_directory_offset,
s->bitmap_directory_size))
{
return QCOW2_OL_BITMAP_DIRECTORY;
}
}
return 0; return 0;
} }

View File

@ -679,6 +679,11 @@ static QemuOptsList qcow2_runtime_opts = {
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
.help = "Check for unintended writes into an inactive L2 table", .help = "Check for unintended writes into an inactive L2 table",
}, },
{
.name = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
.type = QEMU_OPT_BOOL,
.help = "Check for unintended writes into the bitmap directory",
},
{ {
.name = QCOW2_OPT_CACHE_SIZE, .name = QCOW2_OPT_CACHE_SIZE,
.type = QEMU_OPT_SIZE, .type = QEMU_OPT_SIZE,
@ -712,14 +717,15 @@ static QemuOptsList qcow2_runtime_opts = {
}; };
static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = { static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = {
[QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER, [QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
[QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1, [QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
[QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2, [QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
[QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE, [QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
[QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK, [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE, [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
[QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1, [QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
[QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2, [QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
[QCOW2_OL_BITMAP_DIRECTORY_BITNR] = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
}; };
static void cache_clean_timer_cb(void *opaque) static void cache_clean_timer_cb(void *opaque)

View File

@ -94,6 +94,7 @@
#define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table" #define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table"
#define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1" #define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1"
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2" #define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
#define QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY "overlap-check.bitmap-directory"
#define QCOW2_OPT_CACHE_SIZE "cache-size" #define QCOW2_OPT_CACHE_SIZE "cache-size"
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size" #define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size" #define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
@ -400,34 +401,36 @@ typedef enum QCow2ClusterType {
} QCow2ClusterType; } QCow2ClusterType;
typedef enum QCow2MetadataOverlap { typedef enum QCow2MetadataOverlap {
QCOW2_OL_MAIN_HEADER_BITNR = 0, QCOW2_OL_MAIN_HEADER_BITNR = 0,
QCOW2_OL_ACTIVE_L1_BITNR = 1, QCOW2_OL_ACTIVE_L1_BITNR = 1,
QCOW2_OL_ACTIVE_L2_BITNR = 2, QCOW2_OL_ACTIVE_L2_BITNR = 2,
QCOW2_OL_REFCOUNT_TABLE_BITNR = 3, QCOW2_OL_REFCOUNT_TABLE_BITNR = 3,
QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4, QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4,
QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5, QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5,
QCOW2_OL_INACTIVE_L1_BITNR = 6, QCOW2_OL_INACTIVE_L1_BITNR = 6,
QCOW2_OL_INACTIVE_L2_BITNR = 7, QCOW2_OL_INACTIVE_L2_BITNR = 7,
QCOW2_OL_BITMAP_DIRECTORY_BITNR = 8,
QCOW2_OL_MAX_BITNR = 8, QCOW2_OL_MAX_BITNR = 9,
QCOW2_OL_NONE = 0, QCOW2_OL_NONE = 0,
QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR), QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR),
QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR), QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR),
QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR), QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR),
QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR), QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR),
QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR), QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR),
QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR), QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR),
QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR), QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR),
/* NOTE: Checking overlaps with inactive L2 tables will result in bdrv /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv
* reads. */ * reads. */
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR), QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
QCOW2_OL_BITMAP_DIRECTORY = (1 << QCOW2_OL_BITMAP_DIRECTORY_BITNR),
} QCow2MetadataOverlap; } QCow2MetadataOverlap;
/* Perform all overlap checks which can be done in constant time */ /* Perform all overlap checks which can be done in constant time */
#define QCOW2_OL_CONSTANT \ #define QCOW2_OL_CONSTANT \
(QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \ (QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \
QCOW2_OL_SNAPSHOT_TABLE) QCOW2_OL_SNAPSHOT_TABLE | QCOW2_OL_BITMAP_DIRECTORY)
/* Perform all overlap checks which don't require disk access */ /* Perform all overlap checks which don't require disk access */
#define QCOW2_OL_CACHED \ #define QCOW2_OL_CACHED \

View File

@ -2696,18 +2696,21 @@
# @template: Specifies a template mode which can be adjusted using the other # @template: Specifies a template mode which can be adjusted using the other
# flags, defaults to 'cached' # flags, defaults to 'cached'
# #
# @bitmap-directory: since 3.0
#
# Since: 2.9 # Since: 2.9
## ##
{ 'struct': 'Qcow2OverlapCheckFlags', { 'struct': 'Qcow2OverlapCheckFlags',
'data': { '*template': 'Qcow2OverlapCheckMode', 'data': { '*template': 'Qcow2OverlapCheckMode',
'*main-header': 'bool', '*main-header': 'bool',
'*active-l1': 'bool', '*active-l1': 'bool',
'*active-l2': 'bool', '*active-l2': 'bool',
'*refcount-table': 'bool', '*refcount-table': 'bool',
'*refcount-block': 'bool', '*refcount-block': 'bool',
'*snapshot-table': 'bool', '*snapshot-table': 'bool',
'*inactive-l1': 'bool', '*inactive-l1': 'bool',
'*inactive-l2': 'bool' } } '*inactive-l2': 'bool',
'*bitmap-directory': 'bool' } }
## ##
# @Qcow2OverlapChecks: # @Qcow2OverlapChecks: