9ae3a8
From 38b7ffbe3a1fa62f4d5177a3a572aa1c9abb1963 Mon Sep 17 00:00:00 2001
9ae3a8
From: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Date: Tue, 25 Mar 2014 14:23:33 +0100
9ae3a8
Subject: [PATCH 26/49] qcow2: Fix backing file name length check
9ae3a8
9ae3a8
RH-Author: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Message-id: <1395753835-7591-27-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: n/a
9ae3a8
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 26/48] qcow2: Fix backing file name length check
9ae3a8
Bugzilla: 1066691
9ae3a8
RH-Acked-by: Jeff Cody <jcody@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
9ae3a8
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1066691
9ae3a8
Upstream status: Series embargoed
9ae3a8
9ae3a8
len could become negative and would pass the check then. Nothing bad
9ae3a8
happened because bdrv_pread() happens to return an error for negative
9ae3a8
length values, but make variables for sizes unsigned anyway.
9ae3a8
9ae3a8
This patch also changes the behaviour to error out on invalid lengths
9ae3a8
instead of silently truncating it to 1023.
9ae3a8
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow2.c              |    9 ++++++---
9ae3a8
 tests/qemu-iotests/080     |    8 ++++++++
9ae3a8
 tests/qemu-iotests/080.out |    5 +++++
9ae3a8
 3 files changed, 19 insertions(+), 3 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/qcow2.c b/block/qcow2.c
9ae3a8
index 8be82f0..a8ad9e1 100644
9ae3a8
--- a/block/qcow2.c
9ae3a8
+++ b/block/qcow2.c
9ae3a8
@@ -445,7 +445,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
                       Error **errp)
9ae3a8
 {
9ae3a8
     BDRVQcowState *s = bs->opaque;
9ae3a8
-    int len, i, ret = 0;
9ae3a8
+    unsigned int len, i;
9ae3a8
+    int ret = 0;
9ae3a8
     QCowHeader header;
9ae3a8
     QemuOpts *opts;
9ae3a8
     Error *local_err = NULL;
9ae3a8
@@ -720,8 +721,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
     /* read the backing file name */
9ae3a8
     if (header.backing_file_offset != 0) {
9ae3a8
         len = header.backing_file_size;
9ae3a8
-        if (len > 1023) {
9ae3a8
-            len = 1023;
9ae3a8
+        if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) {
9ae3a8
+            error_setg(errp, "Backing file name too long");
9ae3a8
+            ret = -EINVAL;
9ae3a8
+            goto fail;
9ae3a8
         }
9ae3a8
         ret = bdrv_pread(bs->file, header.backing_file_offset,
9ae3a8
                          bs->backing_file, len);
9ae3a8
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
9ae3a8
index 7255b6c..f3091a9 100755
9ae3a8
--- a/tests/qemu-iotests/080
9ae3a8
+++ b/tests/qemu-iotests/080
9ae3a8
@@ -45,6 +45,7 @@ _supported_os Linux
9ae3a8
 header_size=104
9ae3a8
 
9ae3a8
 offset_backing_file_offset=8
9ae3a8
+offset_backing_file_size=16
9ae3a8
 offset_l1_size=36
9ae3a8
 offset_l1_table_offset=40
9ae3a8
 offset_refcount_table_offset=48
9ae3a8
@@ -135,6 +136,13 @@ poke_file "$TEST_IMG" "$offset_l1_table_offset" "\x12\x34\x56\x78\x90\xab\xcd\xe
9ae3a8
 poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\x00\x01"
9ae3a8
 { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
 
9ae3a8
+echo
9ae3a8
+echo "== Invalid backing file size =="
9ae3a8
+_make_test_img 64M
9ae3a8
+poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x10\x00"
9ae3a8
+poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
9ae3a8
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
+
9ae3a8
 # success, all done
9ae3a8
 echo "*** done"
9ae3a8
 rm -f $seq.full
9ae3a8
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
9ae3a8
index 4ec2545..8103211 100644
9ae3a8
--- a/tests/qemu-iotests/080.out
9ae3a8
+++ b/tests/qemu-iotests/080.out
9ae3a8
@@ -58,4 +58,9 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
9ae3a8
 no file open, try 'help open'
9ae3a8
 qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
9ae3a8
 no file open, try 'help open'
9ae3a8
+
9ae3a8
+== Invalid backing file size ==
9ae3a8
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
9ae3a8
+qemu-io: can't open device TEST_DIR/t.qcow2: Backing file name too long
9ae3a8
+no file open, try 'help open'
9ae3a8
 *** done
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8