qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

060 (16931B)


      1 #!/usr/bin/env bash
      2 # group: rw auto quick
      3 #
      4 # Test case for image corruption (overlapping data structures) in qcow2
      5 #
      6 # Copyright (C) 2013 Red Hat, Inc.
      7 #
      8 # This program is free software; you can redistribute it and/or modify
      9 # it under the terms of the GNU General Public License as published by
     10 # the Free Software Foundation; either version 2 of the License, or
     11 # (at your option) any later version.
     12 #
     13 # This program is distributed in the hope that it will be useful,
     14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 # GNU General Public License for more details.
     17 #
     18 # You should have received a copy of the GNU General Public License
     19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     20 #
     21 
     22 # creator
     23 owner=hreitz@redhat.com
     24 
     25 seq="$(basename $0)"
     26 echo "QA output created by $seq"
     27 
     28 status=1	# failure is the default!
     29 
     30 _cleanup()
     31 {
     32 	_cleanup_test_img
     33 }
     34 trap "_cleanup; exit \$status" 0 1 2 3 15
     35 
     36 # Sometimes the error line might be dumped before/after an event
     37 # randomly.  Mask it out for specific test that may trigger this
     38 # uncertainty for current test for now.
     39 _filter_io_error()
     40 {
     41     sed '/Input\/output error/d'
     42 }
     43 
     44 # get standard environment, filters and checks
     45 . ./common.rc
     46 . ./common.filter
     47 
     48 # This tests qcow2-specific low-level functionality
     49 _supported_fmt qcow2
     50 _supported_proto file fuse
     51 _supported_os Linux
     52 # These tests only work for compat=1.1 images without an external
     53 # data file with refcount_bits=16
     54 _unsupported_imgopts 'compat=0.10' data_file \
     55     'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
     56 
     57 # The repair process will create a large file - so check for availability first
     58 _require_large_file 64G
     59 
     60 rt_offset=65536  # 0x10000 (XXX: just an assumption)
     61 rb_offset=131072 # 0x20000 (XXX: just an assumption)
     62 l1_offset=196608 # 0x30000 (XXX: just an assumption)
     63 l2_offset=262144 # 0x40000 (XXX: just an assumption)
     64 l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
     65 
     66 OPEN_RW="open -o overlap-check=all $TEST_IMG"
     67 # Overlap checks are done before write operations only, therefore opening an
     68 # image read-only makes the overlap-check option irrelevant
     69 OPEN_RO="open -r $TEST_IMG"
     70 
     71 echo
     72 echo "=== Testing L2 reference into L1 ==="
     73 echo
     74 _make_test_img 64M
     75 # Link first L1 entry (first L2 table) onto itself
     76 # (Note the MSb in the L1 entry is set, ensuring the refcount is one - else any
     77 # later write will result in a COW operation, effectively ruining this attempt
     78 # on image corruption)
     79 poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
     80 _check_test_img
     81 
     82 # The corrupt bit should not be set anyway
     83 _qcow2_dump_header | grep incompatible_features
     84 
     85 # Try to write something, thereby forcing the corrupt bit to be set
     86 $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
     87 
     88 # The corrupt bit must now be set
     89 _qcow2_dump_header | grep incompatible_features
     90 
     91 # This information should be available through qemu-img info
     92 _img_info --format-specific
     93 
     94 # Try to open the image R/W (which should fail)
     95 $QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
     96                                             | _filter_testdir \
     97                                             | _filter_imgfmt
     98 
     99 # Try to open it RO (which should succeed)
    100 $QEMU_IO -c "$OPEN_RO" -c "read 0 512" | _filter_qemu_io
    101 
    102 # We could now try to fix the image, but this would probably fail (how should an
    103 # L2 table linked onto the L1 table be fixed?)
    104 
    105 echo
    106 echo "=== Testing cluster data reference into refcount block ==="
    107 echo
    108 _make_test_img 64M
    109 # Allocate L2 table
    110 truncate -s "$(($l2_offset+65536))" "$TEST_IMG"
    111 poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x00\x00"
    112 # Mark cluster as used
    113 poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
    114 # Redirect new data cluster onto refcount block
    115 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
    116 _check_test_img
    117 _qcow2_dump_header | grep incompatible_features
    118 $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
    119 _qcow2_dump_header | grep incompatible_features
    120 
    121 # Try to fix it
    122 _check_test_img -r all
    123 
    124 # The corrupt bit should be cleared
    125 _qcow2_dump_header | grep incompatible_features
    126 
    127 # Look if it's really really fixed
    128 $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
    129 _qcow2_dump_header | grep incompatible_features
    130 
    131 echo
    132 echo "=== Testing cluster data reference into inactive L2 table ==="
    133 echo
    134 _make_test_img 64M
    135 $QEMU_IO -c "$OPEN_RW" -c "write -P 1 0 512" | _filter_qemu_io
    136 $QEMU_IMG snapshot -c foo "$TEST_IMG"
    137 $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
    138 # The inactive L2 table remains at its old offset
    139 poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
    140                       "\x80\x00\x00\x00\x00\x04\x00\x00"
    141 _check_test_img
    142 _qcow2_dump_header | grep incompatible_features
    143 $QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
    144 _qcow2_dump_header | grep incompatible_features
    145 _check_test_img -r all
    146 _qcow2_dump_header | grep incompatible_features
    147 $QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
    148 _qcow2_dump_header | grep incompatible_features
    149 
    150 # Check data
    151 $QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
    152 $QEMU_IMG snapshot -a foo "$TEST_IMG"
    153 _check_test_img
    154 $QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io
    155 
    156 echo
    157 echo "=== Testing overlap while COW is in flight ==="
    158 echo
    159 BACKING_IMG=$TEST_IMG.base
    160 TEST_IMG=$BACKING_IMG _make_test_img 1G
    161 
    162 $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
    163 
    164 _make_test_img -b "$BACKING_IMG" -F $IMGFMT 1G
    165 # Write two clusters, the second one enforces creation of an L2 table after
    166 # the first data cluster.
    167 $QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
    168 # Free the first cluster. This cluster will soon enough be reallocated and
    169 # used for COW.
    170 poke_file "$TEST_IMG" "$l2_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
    171 poke_file "$TEST_IMG" "$(($rb_offset+10))" "\x00\x00"
    172 # Now, corrupt the image by marking the second L2 table cluster as free.
    173 poke_file "$TEST_IMG" "$(($rb_offset+12))" "\x00\x00"
    174 # Start a write operation requiring COW on the image stopping it right before
    175 # doing the read; then, trigger the corruption prevention by writing anything to
    176 # any unallocated cluster, leading to an attempt to overwrite the second L2
    177 # table. Finally, resume the COW write and see it fail (but not crash).
    178 echo "open -o file.driver=blkdebug $TEST_IMG
    179 break cow_read 0
    180 aio_write 0k 1k
    181 wait_break 0
    182 write 64k 64k
    183 resume 0" | $QEMU_IO | _filter_qemu_io
    184 
    185 echo
    186 echo "=== Testing unallocated image header ==="
    187 echo
    188 _make_test_img 64M
    189 # Create L1/L2
    190 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    191 poke_file "$TEST_IMG" "$rb_offset" "\x00\x00"
    192 $QEMU_IO -c "write 64k 64k" "$TEST_IMG" | _filter_qemu_io
    193 
    194 echo
    195 echo "=== Testing unaligned L1 entry ==="
    196 echo
    197 _make_test_img 64M
    198 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    199 # This will be masked with ~(512 - 1) = ~0x1ff, so whether the lower 9 bits are
    200 # aligned or not does not matter
    201 poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00"
    202 $QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io
    203 
    204 # Test how well zero cluster expansion can cope with this
    205 _make_test_img 64M
    206 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    207 poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00"
    208 $QEMU_IMG amend -o compat=0.10 "$TEST_IMG"
    209 
    210 echo
    211 echo "=== Testing unaligned L2 entry ==="
    212 echo
    213 _make_test_img 64M
    214 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    215 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
    216 $QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io
    217 
    218 echo
    219 echo "=== Testing unaligned pre-allocated zero cluster ==="
    220 echo
    221 _make_test_img 64M
    222 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    223 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x01"
    224 # zero cluster expansion
    225 $QEMU_IMG amend -o compat=0.10 "$TEST_IMG"
    226 
    227 echo
    228 echo "=== Testing unaligned reftable entry ==="
    229 echo
    230 _make_test_img 64M
    231 poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x02\x2a\x00"
    232 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    233 
    234 echo
    235 echo "=== Testing non-fatal corruption on freeing ==="
    236 echo
    237 _make_test_img 64M
    238 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    239 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
    240 $QEMU_IO -c "discard 0 64k" "$TEST_IMG" | _filter_qemu_io
    241 
    242 echo
    243 echo "=== Testing read-only corruption report ==="
    244 echo
    245 _make_test_img 64M
    246 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    247 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
    248 # Should only emit a single error message
    249 $QEMU_IO -c "$OPEN_RO" -c "read 0 64k" -c "read 0 64k" | _filter_qemu_io
    250 
    251 echo
    252 echo "=== Testing non-fatal and then fatal corruption report ==="
    253 echo
    254 _make_test_img 64M
    255 $QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
    256 poke_file "$TEST_IMG" "$l2_offset"        "\x80\x00\x00\x00\x00\x05\x2a\x00"
    257 poke_file "$TEST_IMG" "$(($l2_offset+8))" "\x80\x00\x00\x00\x00\x06\x2a\x00"
    258 # Should emit two error messages
    259 $QEMU_IO -c "discard 0 64k" -c "read 64k 64k" "$TEST_IMG" | _filter_qemu_io
    260 
    261 echo
    262 echo "=== Testing empty refcount table ==="
    263 echo
    264 _make_test_img 64M
    265 poke_file "$TEST_IMG" "$rt_offset"        "\x00\x00\x00\x00\x00\x00\x00\x00"
    266 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    267 # Repair the image
    268 _check_test_img -r all
    269 
    270 echo
    271 echo "=== Testing empty refcount table with valid L1 and L2 tables ==="
    272 echo
    273 _make_test_img 64M
    274 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    275 poke_file "$TEST_IMG" "$rt_offset"        "\x00\x00\x00\x00\x00\x00\x00\x00"
    276 # Since the first data cluster is already allocated this triggers an
    277 # allocation with an explicit offset (using qcow2_alloc_clusters_at())
    278 # causing a refcount block to be allocated at offset 0
    279 $QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
    280 # Repair the image
    281 _check_test_img -r all
    282 
    283 echo
    284 echo "=== Testing empty refcount block ==="
    285 echo
    286 _make_test_img 64M
    287 poke_file "$TEST_IMG" "$rb_offset"        "\x00\x00\x00\x00\x00\x00\x00\x00"
    288 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    289 # Repair the image
    290 _check_test_img -r all
    291 
    292 echo
    293 echo "=== Testing empty refcount block with compressed write ==="
    294 echo
    295 _make_test_img 64M
    296 $QEMU_IO -c "write 64k 64k" "$TEST_IMG" | _filter_qemu_io
    297 poke_file "$TEST_IMG" "$rb_offset"        "\x00\x00\x00\x00\x00\x00\x00\x00"
    298 # The previous write already allocated an L2 table, so now this new
    299 # write will try to allocate a compressed data cluster at offset 0.
    300 $QEMU_IO -c "write -c 0k 64k" "$TEST_IMG" | _filter_qemu_io
    301 # Repair the image
    302 _check_test_img -r all
    303 
    304 echo
    305 echo "=== Testing zero refcount table size ==="
    306 echo
    307 _make_test_img 64M
    308 poke_file "$TEST_IMG" "56"                "\x00\x00\x00\x00"
    309 $QEMU_IO -c "write 0 64k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
    310 # Repair the image
    311 _check_test_img -r all
    312 
    313 echo
    314 echo "=== Testing incorrect refcount table offset ==="
    315 echo
    316 _make_test_img 64M
    317 poke_file "$TEST_IMG" "48"                "\x00\x00\x00\x00\x00\x00\x00\x00"
    318 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    319 
    320 echo
    321 echo "=== Testing dirty corrupt image ==="
    322 echo
    323 
    324 _make_test_img 64M
    325 
    326 # Let the refblock appear unaligned
    327 poke_file "$TEST_IMG" "$rt_offset"        "\x00\x00\x00\x00\xff\xff\x2a\x00"
    328 # Mark the image dirty, thus forcing an automatic check when opening it
    329 $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 0
    330 # Open the image (qemu should refuse to do so)
    331 $QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
    332 
    333 echo '--- Repairing ---'
    334 
    335 # The actual repair should have happened (because of the dirty bit),
    336 # but some cleanup may have failed (like freeing the old reftable)
    337 # because the image was already marked corrupt by that point
    338 _check_test_img -r all
    339 
    340 echo
    341 echo "=== Writing to an unaligned preallocated zero cluster ==="
    342 echo
    343 
    344 _make_test_img 64M
    345 
    346 # Allocate the L2 table
    347 $QEMU_IO -c "write 0 64k" -c "discard 0 64k" "$TEST_IMG" | _filter_qemu_io
    348 # Pretend there is a preallocated zero cluster somewhere inside the
    349 # image header
    350 poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x00\x2a\x01"
    351 # Let's write to it!
    352 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
    353 
    354 echo '--- Repairing ---'
    355 _check_test_img -r all
    356 
    357 echo
    358 echo '=== Discarding with an unaligned refblock ==='
    359 echo
    360 
    361 _make_test_img 64M
    362 
    363 $QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
    364 # Make our refblock unaligned
    365 poke_file "$TEST_IMG" "$(($rt_offset))" "\x00\x00\x00\x00\x00\x00\x2a\x00"
    366 # Now try to discard something that will be submitted as two requests
    367 # (main part + tail)
    368 $QEMU_IO -c "discard 0 65537" "$TEST_IMG"
    369 
    370 echo '--- Repairing ---'
    371 # Fails the first repair because the corruption prevents the check
    372 # function from double-checking
    373 # (Using -q for the first invocation, because otherwise the
    374 #  double-check error message appears above the summary for some
    375 #  reason -- so let's just hide the summary)
    376 _check_test_img -q -r all
    377 _check_test_img -r all
    378 
    379 echo
    380 echo "=== Discarding an out-of-bounds refblock ==="
    381 echo
    382 
    383 _make_test_img 64M
    384 
    385 # Pretend there's a refblock really up high
    386 poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\xff\xff\xff\x00\x00\x00\x00"
    387 # Let's try to shrink the qcow2 image so that the block driver tries
    388 # to discard that refblock (and see what happens!)
    389 $QEMU_IMG resize --shrink "$TEST_IMG" 32M
    390 
    391 echo '--- Checking and retrying ---'
    392 # Image should not be resized
    393 _img_info | grep 'virtual size'
    394 # But it should pass this check, because the "partial" resize has
    395 # already overwritten refblocks past the end
    396 _check_test_img -r all
    397 # So let's try again
    398 $QEMU_IMG resize --shrink "$TEST_IMG" 32M
    399 _img_info | grep 'virtual size'
    400 
    401 echo
    402 echo "=== Discarding a non-covered in-bounds refblock ==="
    403 echo
    404 
    405 _make_test_img -o 'refcount_bits=1' 64M
    406 
    407 # Pretend there's a refblock somewhere where there is no refblock to
    408 # cover it (but the covering refblock has a valid index in the
    409 # reftable)
    410 # Every refblock covers 65536 * 8 * 65536 = 32 GB, so we have to point
    411 # to 0x10_0000_0000 (64G) to point to the third refblock
    412 poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
    413 $QEMU_IMG resize --shrink "$TEST_IMG" 32M
    414 
    415 echo '--- Checking and retrying ---'
    416 # Image should not be resized
    417 _img_info | grep 'virtual size'
    418 # But it should pass this check, because the "partial" resize has
    419 # already overwritten refblocks past the end
    420 _check_test_img -r all
    421 # So let's try again
    422 $QEMU_IMG resize --shrink "$TEST_IMG" 32M
    423 _img_info | grep 'virtual size'
    424 
    425 echo
    426 echo "=== Discarding a refblock covered by an unaligned refblock ==="
    427 echo
    428 
    429 _make_test_img -o 'refcount_bits=1' 64M
    430 
    431 # Same as above
    432 poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
    433 # But now we actually "create" an unaligned third refblock
    434 poke_file "$TEST_IMG" "$(($rt_offset+16))" "\x00\x00\x00\x00\x00\x00\x02\x00"
    435 $QEMU_IMG resize --shrink "$TEST_IMG" 32M
    436 
    437 echo '--- Repairing ---'
    438 # Fails the first repair because the corruption prevents the check
    439 # function from double-checking
    440 # (Using -q for the first invocation, because otherwise the
    441 #  double-check error message appears above the summary for some
    442 #  reason -- so let's just hide the summary)
    443 _check_test_img -q -r all
    444 _check_test_img -r all
    445 
    446 echo
    447 echo "=== Testing the QEMU shutdown with a corrupted image ==="
    448 echo
    449 _make_test_img 64M
    450 poke_file "$TEST_IMG" "$rt_offset"        "\x00\x00\x00\x00\x00\x00\x00\x00"
    451 echo "{'execute': 'qmp_capabilities'}
    452       {'execute': 'human-monitor-command',
    453        'arguments': {'command-line': 'qemu-io drive \"write 0 512\"'}}
    454       {'execute': 'quit'}" \
    455     | $QEMU -qmp stdio -nographic -nodefaults \
    456             -drive if=none,node-name=drive,file="$TEST_IMG",driver=qcow2 \
    457     | _filter_qmp | _filter_qemu_io
    458 
    459 echo
    460 echo "=== Testing incoming inactive corrupted image ==="
    461 echo
    462 
    463 _make_test_img 64M
    464 # Create an unaligned L1 entry, so qemu will signal a corruption when
    465 # reading from the covered area
    466 poke_file "$TEST_IMG" "$l1_offset" "\x00\x00\x00\x00\x2a\x2a\x2a\x2a"
    467 
    468 # Inactive images are effectively read-only images, so this should be a
    469 # non-fatal corruption (which does not modify the image)
    470 echo "{'execute': 'qmp_capabilities'}
    471       {'execute': 'human-monitor-command',
    472        'arguments': {'command-line': 'qemu-io drive \"read 0 512\"'}}
    473       {'execute': 'quit'}" \
    474     | $QEMU -qmp stdio -nographic -nodefaults \
    475             -blockdev "{'node-name': 'drive',
    476                         'driver': 'qcow2',
    477                         'file': {
    478                             'driver': 'file',
    479                             'filename': '$TEST_IMG'
    480                         }}" \
    481             -incoming exec:'cat /dev/null' \
    482             2>&1 \
    483     | _filter_qmp | _filter_qemu_io | _filter_io_error
    484 
    485 echo
    486 # Image should not have been marked corrupt
    487 _img_info --format-specific | grep 'corrupt:'
    488 
    489 # success, all done
    490 echo "*** done"
    491 rm -f $seq.full
    492 status=0