There are many existing qcow2 images that specify a backing file but no format. This has been the source of CVEs in the past, but has become more prominent of a problem now that libvirt has switched to -blockdev. With older -drive, at least the probing was always done by qemu (so the only risk of a changed format between successive boots of a guest was if qemu was upgraded and probed differently). But with newer -blockdev, libvirt must specify a format; if libvirt guesses raw where the image was formatted, this results in data corruption visible to the guest; conversely, if libvirt guesses qcow2 where qemu was using raw, this can result in potential security holes, so modern libvirt instead refuses to use images without explicit backing format. The change in libvirt to reject images without explicit backing format has pointed out that a number of tools have been far too reliant on probing in the past. It's time to set a better example in our own iotests of properly setting this parameter. iotest calls to create, rebase, and convert are all impacted to some degree. It's a bit annoying that we are inconsistent on command line - while all of those accept -o backing_file=...,backing_fmt=..., the shortcuts are different: create and rebase have -b and -F, while convert has -B but no -F. (amend has no shortcuts, but the previous patch just deprecated the use of amend to change backing chains). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20200706203954.341758-9-eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
309 lines
12 KiB
Bash
Executable file
309 lines
12 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Test some qemu-img convert cases
|
|
#
|
|
# Copyright (C) 2015 Red Hat, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
# creator
|
|
owner=kwolf@redhat.com
|
|
|
|
seq="$(basename $0)"
|
|
echo "QA output created by $seq"
|
|
|
|
status=1 # failure is the default!
|
|
|
|
_cleanup()
|
|
{
|
|
for img in "$TEST_IMG".[123]; do
|
|
_rm_test_img "$img"
|
|
done
|
|
_cleanup_test_img
|
|
}
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
# get standard environment, filters and checks
|
|
. ./common.rc
|
|
. ./common.filter
|
|
|
|
_supported_fmt qcow2
|
|
_supported_proto file
|
|
_supported_os Linux
|
|
|
|
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x11 0 64M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Check allocation status regression with -B ==="
|
|
echo
|
|
|
|
_make_test_img -b "$TEST_IMG".base -F $IMGFMT
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base \
|
|
-o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
|
|
echo
|
|
echo "=== Check that zero clusters are kept in overlay ==="
|
|
echo
|
|
|
|
_make_test_img -b "$TEST_IMG".base -F $IMGFMT
|
|
|
|
$QEMU_IO -c "write -P 0 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
|
|
"$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
|
|
"$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IO -c "write -z 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
|
|
"$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
|
|
"$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Converting to an overlay larger than its backing file ==="
|
|
echo
|
|
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 256M
|
|
# Needs to be at least how much an L2 table covers
|
|
# (64 kB/entry * 64 kB / 8 B/entry = 512 MB)
|
|
# That way, qcow2 will yield at least two status request responses.
|
|
# With just a single response, it would always say "Allocated in the
|
|
# backing file", so the optimization qemu-img convert tries to do is
|
|
# done automatically. Once it has to be queried twice, however (and
|
|
# one of the queries is completely after the end of the backing file),
|
|
# the block layer will automatically add a ZERO flag that qemu-img
|
|
# convert used to follow up with a zero write to the target.
|
|
# We do not want such a zero write, however, because we are past the
|
|
# end of the backing file on the target as well, so we do not need to
|
|
# write anything there.
|
|
_make_test_img -b "$TEST_IMG".base 768M -F $IMGFMT
|
|
|
|
# Use compat=0.10 as the output so there is no zero cluster support
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \
|
|
-o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
|
|
# See that nothing has been allocated past 64M
|
|
$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
|
|
# Just before the end of the backing file
|
|
$QEMU_IO -c 'write -P 0x11 255M 1M' "$TEST_IMG".base 2>&1 | _filter_qemu_io
|
|
# Somewhere in the second L2 table
|
|
$QEMU_IO -c 'write -P 0x22 600M 1M' "$TEST_IMG" 2>&1 | _filter_qemu_io
|
|
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \
|
|
-o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
|
|
|
|
$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
|
|
$QEMU_IO -c 'read -P 0x11 255M 1M' \
|
|
-c 'read -P 0x22 600M 1M' \
|
|
"$TEST_IMG".orig \
|
|
| _filter_qemu_io
|
|
|
|
|
|
echo
|
|
echo "=== Concatenate multiple source images ==="
|
|
echo
|
|
|
|
TEST_IMG="$TEST_IMG".1 _make_test_img 4M
|
|
TEST_IMG="$TEST_IMG".2 _make_test_img 4M
|
|
TEST_IMG="$TEST_IMG".3 _make_test_img 4M
|
|
|
|
$QEMU_IO -c "write -P 0x11 0 64k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x22 0 64k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x33 0 64k" "$TEST_IMG".3 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
# -B can't be combined with concatenation
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
|
|
|
|
|
|
echo
|
|
echo "=== Compression with misaligned allocations and image sizes ==="
|
|
echo
|
|
|
|
TEST_IMG="$TEST_IMG".1 _make_test_img 1023k -o cluster_size=1024
|
|
TEST_IMG="$TEST_IMG".2 _make_test_img 1023k -o cluster_size=1024
|
|
|
|
$QEMU_IO -c "write -P 0x11 16k 16k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x22 130k 130k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x33 1022k 1k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x44 0k 1k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[12] "$TEST_IMG"
|
|
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0 0k 16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 16k 16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32k 98k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 130k 130k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 260k 762k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 1022k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x44 1023k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 1024k 1022k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Full allocation with -S 0 ==="
|
|
echo
|
|
|
|
# Standalone image
|
|
_make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0 3M 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
echo
|
|
echo convert -S 0:
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0:
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
# With backing file
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x11 0 32M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
_make_test_img -b "$TEST_IMG".base 64M -F $IMGFMT
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
echo
|
|
echo convert -S 0 with source backing file:
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0 with source backing file:
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
# With keeping the backing file
|
|
echo
|
|
echo convert -S 0 -B ...
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0 -B ...
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
|
|
echo
|
|
echo "=== Non-zero -S ==="
|
|
echo
|
|
|
|
_make_test_img 64M -o cluster_size=1k
|
|
$QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
for min_sparse in 4k 8k; do
|
|
echo
|
|
echo convert -S $min_sparse
|
|
$QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S $min_sparse
|
|
# For compressed images, -S values other than 0 are ignored
|
|
$QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -c -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
done
|
|
|
|
|
|
echo
|
|
echo '=== -n to a non-zero image ==='
|
|
echo
|
|
|
|
# Keep source zero
|
|
_make_test_img 64M
|
|
|
|
# Output is not zero, but has bdrv_has_zero_init() == 1
|
|
TEST_IMG="$TEST_IMG".orig _make_test_img 64M
|
|
$QEMU_IO -c "write -P 42 0 64k" "$TEST_IMG".orig | _filter_qemu_io
|
|
|
|
# Convert with -n, which should not assume that the target is zeroed
|
|
$QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig
|
|
|
|
$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig
|
|
|
|
echo
|
|
echo '=== -n -B to an image without a backing file ==='
|
|
echo
|
|
|
|
# Base for the output
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 64M
|
|
|
|
# Output that does have $TEST_IMG.base set as its (implicit) backing file
|
|
TEST_IMG="$TEST_IMG".orig _make_test_img 64M
|
|
|
|
# Convert with -n, which should not confuse -B with "target BDS has a
|
|
# backing file"
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig
|
|
|
|
echo
|
|
echo '=== -n incompatible with -o ==='
|
|
echo
|
|
|
|
$QEMU_IMG convert -O $IMGFMT -o preallocation=metadata -n \
|
|
"$TEST_IMG" "$TEST_IMG".orig && echo "unexpected success"
|
|
|
|
# success, all done
|
|
echo '*** done'
|
|
rm -f $seq.full
|
|
status=0
|