aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/qcow2-snapshot.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 53dc1635ec..582eb3386a 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -68,6 +68,7 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
QCowSnapshot *sn;
int i, id_str_size, name_size;
int64_t offset;
+ uint64_t table_length = 0;
int ret;
if (!s->nb_snapshots) {
@@ -82,6 +83,8 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
for(i = 0; i < s->nb_snapshots; i++) {
bool truncate_unknown_extra_data = false;
+ table_length = ROUND_UP(table_length, 8);
+
/* Read statically sized part of the snapshot header */
offset = ROUND_UP(offset, 8);
ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
@@ -184,7 +187,16 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
offset += name_size;
sn->name[name_size] = '\0';
- if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) {
+ /* Note that the extra data may have been truncated */
+ table_length += sizeof(h) + sn->extra_data_size + id_str_size +
+ name_size;
+ if (!repair) {
+ assert(table_length == offset - s->snapshots_offset);
+ }
+
+ if (table_length > QCOW_MAX_SNAPSHOTS_SIZE ||
+ offset - s->snapshots_offset > INT_MAX)
+ {
ret = -EFBIG;
error_setg(errp, "Snapshot table is too big");
goto fail;