Skip to content

Commit 0e4e431

Browse files
Vladimir Sementsov-OgievskiyXanClic
Vladimir Sementsov-Ogievskiy
authored andcommitted
qcow2: add overlap check for bitmap directory
Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> Message-id: [email protected] Signed-off-by: Max Reitz <[email protected]>
1 parent 85456e0 commit 0e4e431

File tree

5 files changed

+66
-39
lines changed

5 files changed

+66
-39
lines changed

block/qcow2-bitmap.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,12 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
775775
}
776776
}
777777

778-
ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size);
778+
/* Actually, even in in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY is not
779+
* necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating bitmap
780+
* directory in-place (actually, turn-off the extension), which is checked
781+
* in qcow2_check_metadata_overlap() */
782+
ret = qcow2_pre_write_overlap_check(
783+
bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size);
779784
if (ret < 0) {
780785
goto fail;
781786
}

block/qcow2-refcount.c

+10
Original file line numberDiff line numberDiff line change
@@ -2705,6 +2705,16 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
27052705
}
27062706
}
27072707

2708+
if ((chk & QCOW2_OL_BITMAP_DIRECTORY) &&
2709+
(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS))
2710+
{
2711+
if (overlaps_with(s->bitmap_directory_offset,
2712+
s->bitmap_directory_size))
2713+
{
2714+
return QCOW2_OL_BITMAP_DIRECTORY;
2715+
}
2716+
}
2717+
27082718
return 0;
27092719
}
27102720

block/qcow2.c

+14-8
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,11 @@ static QemuOptsList qcow2_runtime_opts = {
679679
.type = QEMU_OPT_BOOL,
680680
.help = "Check for unintended writes into an inactive L2 table",
681681
},
682+
{
683+
.name = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
684+
.type = QEMU_OPT_BOOL,
685+
.help = "Check for unintended writes into the bitmap directory",
686+
},
682687
{
683688
.name = QCOW2_OPT_CACHE_SIZE,
684689
.type = QEMU_OPT_SIZE,
@@ -712,14 +717,15 @@ static QemuOptsList qcow2_runtime_opts = {
712717
};
713718

714719
static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = {
715-
[QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
716-
[QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
717-
[QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
718-
[QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
719-
[QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
720-
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
721-
[QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
722-
[QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
720+
[QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
721+
[QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
722+
[QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
723+
[QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
724+
[QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
725+
[QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
726+
[QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
727+
[QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
728+
[QCOW2_OL_BITMAP_DIRECTORY_BITNR] = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
723729
};
724730

725731
static void cache_clean_timer_cb(void *opaque)

block/qcow2.h

+24-21
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
#define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table"
9595
#define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1"
9696
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
97+
#define QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY "overlap-check.bitmap-directory"
9798
#define QCOW2_OPT_CACHE_SIZE "cache-size"
9899
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
99100
#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
@@ -400,34 +401,36 @@ typedef enum QCow2ClusterType {
400401
} QCow2ClusterType;
401402

402403
typedef enum QCow2MetadataOverlap {
403-
QCOW2_OL_MAIN_HEADER_BITNR = 0,
404-
QCOW2_OL_ACTIVE_L1_BITNR = 1,
405-
QCOW2_OL_ACTIVE_L2_BITNR = 2,
406-
QCOW2_OL_REFCOUNT_TABLE_BITNR = 3,
407-
QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4,
408-
QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5,
409-
QCOW2_OL_INACTIVE_L1_BITNR = 6,
410-
QCOW2_OL_INACTIVE_L2_BITNR = 7,
411-
412-
QCOW2_OL_MAX_BITNR = 8,
413-
414-
QCOW2_OL_NONE = 0,
415-
QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR),
416-
QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR),
417-
QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR),
418-
QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR),
419-
QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR),
420-
QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR),
421-
QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR),
404+
QCOW2_OL_MAIN_HEADER_BITNR = 0,
405+
QCOW2_OL_ACTIVE_L1_BITNR = 1,
406+
QCOW2_OL_ACTIVE_L2_BITNR = 2,
407+
QCOW2_OL_REFCOUNT_TABLE_BITNR = 3,
408+
QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4,
409+
QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5,
410+
QCOW2_OL_INACTIVE_L1_BITNR = 6,
411+
QCOW2_OL_INACTIVE_L2_BITNR = 7,
412+
QCOW2_OL_BITMAP_DIRECTORY_BITNR = 8,
413+
414+
QCOW2_OL_MAX_BITNR = 9,
415+
416+
QCOW2_OL_NONE = 0,
417+
QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR),
418+
QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR),
419+
QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR),
420+
QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR),
421+
QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR),
422+
QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR),
423+
QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR),
422424
/* NOTE: Checking overlaps with inactive L2 tables will result in bdrv
423425
* reads. */
424-
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
426+
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
427+
QCOW2_OL_BITMAP_DIRECTORY = (1 << QCOW2_OL_BITMAP_DIRECTORY_BITNR),
425428
} QCow2MetadataOverlap;
426429

427430
/* Perform all overlap checks which can be done in constant time */
428431
#define QCOW2_OL_CONSTANT \
429432
(QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \
430-
QCOW2_OL_SNAPSHOT_TABLE)
433+
QCOW2_OL_SNAPSHOT_TABLE | QCOW2_OL_BITMAP_DIRECTORY)
431434

432435
/* Perform all overlap checks which don't require disk access */
433436
#define QCOW2_OL_CACHED \

qapi/block-core.json

+12-9
Original file line numberDiff line numberDiff line change
@@ -2696,18 +2696,21 @@
26962696
# @template: Specifies a template mode which can be adjusted using the other
26972697
# flags, defaults to 'cached'
26982698
#
2699+
# @bitmap-directory: since 3.0
2700+
#
26992701
# Since: 2.9
27002702
##
27012703
{ 'struct': 'Qcow2OverlapCheckFlags',
2702-
'data': { '*template': 'Qcow2OverlapCheckMode',
2703-
'*main-header': 'bool',
2704-
'*active-l1': 'bool',
2705-
'*active-l2': 'bool',
2706-
'*refcount-table': 'bool',
2707-
'*refcount-block': 'bool',
2708-
'*snapshot-table': 'bool',
2709-
'*inactive-l1': 'bool',
2710-
'*inactive-l2': 'bool' } }
2704+
'data': { '*template': 'Qcow2OverlapCheckMode',
2705+
'*main-header': 'bool',
2706+
'*active-l1': 'bool',
2707+
'*active-l2': 'bool',
2708+
'*refcount-table': 'bool',
2709+
'*refcount-block': 'bool',
2710+
'*snapshot-table': 'bool',
2711+
'*inactive-l1': 'bool',
2712+
'*inactive-l2': 'bool',
2713+
'*bitmap-directory': 'bool' } }
27112714

27122715
##
27132716
# @Qcow2OverlapChecks:

0 commit comments

Comments
 (0)