diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 5db4f30c8205ac6d23c472df00b9cec8988e3aef..0aa9defbe29ac298e82c88fbebcbe2a3aaea4261 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -116,8 +116,14 @@ int qcow2_read_snapshots(BlockDriverState *bs) } offset += name_size; sn->name[name_size] = '\0'; + + if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) { + ret = -EFBIG; + goto fail; + } } + assert(offset - s->snapshots_offset <= INT_MAX); s->snapshots_size = offset - s->snapshots_offset; return 0; @@ -138,7 +144,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs) uint32_t nb_snapshots; uint64_t snapshots_offset; } QEMU_PACKED header_data; - int64_t offset, snapshots_offset; + int64_t offset, snapshots_offset = 0; int ret; /* compute the size of the snapshots */ @@ -150,7 +156,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs) offset += sizeof(extra); offset += strlen(sn->id_str); offset += strlen(sn->name); + + if (offset > QCOW_MAX_SNAPSHOTS_SIZE) { + ret = -EFBIG; + goto fail; + } } + + assert(offset <= INT_MAX); snapshots_size = offset; /* Allocate space for the new snapshot list */ diff --git a/block/qcow2.h b/block/qcow2.h index f28e7d9165cefa5c2a5843d840e17777aa88916d..b49424b85e926154bb552a48f24ca9d472ffc2fc 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -48,6 +48,10 @@ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ #define QCOW_MAX_L1_SIZE 0x2000000 +/* Allow for an average of 1k per snapshot table entry, should be plenty of + * space for snapshot names and IDs */ +#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS) + /* indicate that the refcount of the referenced cluster is exactly one. */ #define QCOW_OFLAG_COPIED (1ULL << 63) /* indicate that the cluster is compressed (they never have the copied flag) */