block/vdi: Limit maximum size even futher

The block layer read and write functions do not like requests which are
bigger than INT_MAX bytes. Since the VDI bmap is read and written in a
single operation, its size is therefore limited accordingly. This
reduces the maximum VDI image size supported by QEMU to half of what it
currently is (down to approximately 512 TB).

The VDI test 084 has to be adapted accordingly. Actually, one could
clearly see that it was broken from the "Could not open
'TEST_DIR/t.IMGFMT': Invalid argument" line for an image which was
supposed to work just fine.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Lieven <pl@kamp.de>
This commit is contained in:
Max Reitz 2014-10-28 11:12:32 +01:00
parent d21de4d97f
commit d20418ee51
3 changed files with 27 additions and 14 deletions

View File

@ -120,8 +120,18 @@ typedef unsigned char uuid_t[16];
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED) #define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
/* max blocks in image is (0xffffffff / 4) */ /* The bmap will take up VDI_BLOCKS_IN_IMAGE_MAX * sizeof(uint32_t) bytes; since
#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff * the bmap is read and written in a single operation, its size needs to be
* limited to INT_MAX; furthermore, when opening an image, the bmap size is
* rounded up to be aligned on BDRV_SECTOR_SIZE.
* Therefore this should satisfy the following:
* VDI_BLOCKS_IN_IMAGE_MAX * sizeof(uint32_t) + BDRV_SECTOR_SIZE == INT_MAX + 1
* (INT_MAX + 1 is the first value not representable as an int)
* This guarantees that any value below or equal to the constant will, when
* multiplied by sizeof(uint32_t) and rounded up to a BDRV_SECTOR_SIZE boundary,
* still be below or equal to INT_MAX. */
#define VDI_BLOCKS_IN_IMAGE_MAX \
((unsigned)((INT_MAX + 1u - BDRV_SECTOR_SIZE) / sizeof(uint32_t)))
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \ #define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
(uint64_t)DEFAULT_CLUSTER_SIZE) (uint64_t)DEFAULT_CLUSTER_SIZE)

View File

@ -66,15 +66,15 @@ stat -c"disk image file size in bytes: %s" "${TEST_IMG}"
# check for image size too large # check for image size too large
# poke max image size, and appropriate blocks_in_image value # poke max image size, and appropriate blocks_in_image value
echo "Test 1: Maximum size (1024 TB):" echo "Test 1: Maximum size (512 TB - 128 MB):"
poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\xf0\xff\xff\xff\x03\x00" poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\x00\xf8\xff\xff\x01\x00"
poke_file "$TEST_IMG" "$bii_offset" "\xff\xff\xff\x3f" poke_file "$TEST_IMG" "$bii_offset" "\x80\xff\xff\x1f"
_img_info _img_info
echo echo
echo "Test 2: Size too large (1024TB + 1)" echo "Test 2: Size too large (512 TB - 128 MB + 64 kB)"
# This should be too large (-EINVAL): # This should be too large (-EINVAL):
poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\xf1\xff\xff\xff\x03\x00" poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\x01\xf8\xff\xff\x01\x00"
_img_info _img_info
echo echo
@ -89,9 +89,9 @@ _img_info
echo echo
echo "Test 4: Size valid (64M), but Blocks In Image exceeds max allowed" echo "Test 4: Size valid (64M), but Blocks In Image exceeds max allowed"
# Now check the bounds of blocks_in_image - 0x3fffffff should be the max # Now check the bounds of blocks_in_image - 0x1fffff80 should be the max
# value here, and we should get -ENOTSUP # value here, and we should get -ENOTSUP
poke_file "$TEST_IMG" "$bii_offset" "\x00\x00\x00\x40" poke_file "$TEST_IMG" "$bii_offset" "\x81\xff\xff\x1f"
_img_info _img_info
# Finally, 1MB is the only block size supported. Verify that # Finally, 1MB is the only block size supported. Verify that

View File

@ -17,17 +17,20 @@ file format: IMGFMT
virtual size: 64M (67108864 bytes) virtual size: 64M (67108864 bytes)
cluster_size: 1048576 cluster_size: 1048576
disk image file size in bytes: 1024 disk image file size in bytes: 1024
Test 1: Maximum size (1024 TB): Test 1: Maximum size (512 TB - 128 MB):
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'TEST_DIR/t.IMGFMT': Invalid argument image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 512T (562949819203584 bytes)
cluster_size: 1048576
Test 2: Size too large (1024TB + 1) Test 2: Size too large (512 TB - 128 MB + 64 kB)
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported VDI image size (size is 0x3fffffff10000, max supported is 0x3fffffff00000) qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported VDI image size (size is 0x1fffff8010000, max supported is 0x1fffff8000000)
Test 3: Size valid (64M), but Blocks In Image too small (63) Test 3: Size valid (64M), but Blocks In Image too small (63)
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (disk size 67108864, image bitmap has room for 66060288) qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (disk size 67108864, image bitmap has room for 66060288)
Test 4: Size valid (64M), but Blocks In Image exceeds max allowed Test 4: Size valid (64M), but Blocks In Image exceeds max allowed
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (too many blocks 1073741824, max is 1073741823) qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (too many blocks 536870785, max is 536870784)
Test 5: Valid Image: 64MB, Blocks In Image 64, Block Size 1MB Test 5: Valid Image: 64MB, Blocks In Image 64, Block Size 1MB
image: TEST_DIR/t.IMGFMT image: TEST_DIR/t.IMGFMT