qcow2: Keep track of the snapshot table length

When repairing the snapshot table, we truncate entries that have too
much extra data.  This frees up space that we do not have to count
towards the snapshot table size.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 20191011152814.14791-12-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Max Reitz 2019-10-11 17:28:09 +02:00
parent f91f1f159b
commit 624143355c
1 changed files with 13 additions and 1 deletions

View File

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