From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LJeGN-0003o9-UA for qemu-devel@nongnu.org; Sun, 04 Jan 2009 20:28:15 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LJeGK-0003nx-Sf for qemu-devel@nongnu.org; Sun, 04 Jan 2009 20:28:15 -0500 Received: from [199.232.76.173] (port=58309 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LJeGK-0003nu-PE for qemu-devel@nongnu.org; Sun, 04 Jan 2009 20:28:12 -0500 Received: from mx2.redhat.com ([66.187.237.31]:52022) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LJeGJ-0006h7-V4 for qemu-devel@nongnu.org; Sun, 04 Jan 2009 20:28:12 -0500 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n051SCPK002879 for ; Sun, 4 Jan 2009 20:28:12 -0500 Message-ID: <49616228.4030608@redhat.com> Date: Mon, 05 Jan 2009 03:28:08 +0200 From: Uri Lublin MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------060409010009020207040002" Subject: [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Shahar Frank , Uri Lublin This is a multi-part message in MIME format. --------------060409010009020207040002 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hello, This patch below can be considered as a version 2 of Shahar's "Qemu image over raw devices" patch http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html I think we've fixed the security flaw (that was discovered but not introduced by Shahar's patch). Also I'm attaching an examples file with some debugging messages. Thanks, Uri. ---------- From: Uri Lublin The purpose of this prefix is to 1. Provide a way to know the backing file format without probing it (setting the format upon creation time). 2. Enable using qcow2 format (and others) over host block devices. (only if the user specifically asks for it). If no fmt:FMT: is provided we go back to probing. Based on a similar patch from Shahar Frank ("Qemu image over raw devices"). http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html Also fixes a security flaw found by Daniel P. Berrange on the above thread which summarizes: "Autoprobing: just say no." Examples: backing file format is qcow2 (even though it's on a host block device) $ qemu-img create -b fmt:qcow2:/dev/loop0 -f qcow2 /tmp/uuu.qcow2 force backing file format to raw (no probing) $ qemu-img create -f raw /tmp/image1.raw 10G $ qemu-img create -b fmt:raw:/tmp/image1.raw -f qcow2 /tmp/image1.qcow2 Use together with other protocols, e.g. nbd $ qemu-nbd -v -n --snapshot -t -k /tmp/uuu.socket fmt:qcow2:/tmp/images/uuu.qcow2 & $ qemu-img info nbd:unix:/tmp/uuu.socket $ qemu-system-x86_64 -snapshot -hda nbd:unix:/tmp/uuu.socket Or fat $ qemu-system-x86_64 -hda fmt:qcow2:/tmp/uuu.qcow2 -hdb fat:floppy:/tmp/images Signed-off-by: Uri Lublin --- qemu/block.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 60 insertions(+), 12 deletions(-) diff --git a/qemu/block.c b/qemu/block.c index dc744dd..5b4c517 100644 --- a/qemu/block.c +++ b/qemu/block.c @@ -72,7 +72,7 @@ int path_is_absolute(const char *path) if (*path == '/' || *path == '\\') return 1; #endif - p = strchr(path, ':'); + p = strrchr(path, ':'); if (p) p++; else @@ -96,10 +96,23 @@ void path_combine(char *dest, int dest_size, if (dest_size <= 0) return; + + /* copy "fmt:" prefix of filename if exists */ + p = strrchr(filename, ':'); + if (p) { + len = p - filename + 1; + if (dest_size <= len) + return; + strncpy(dest, filename, len); + filename += len; + dest += len; + dest_size -= len; + } + if (path_is_absolute(filename)) { pstrcpy(dest, dest_size, filename); } else { - p = strchr(base_path, ':'); + p = strrchr(base_path, ':'); if (p) p++; else @@ -227,30 +240,51 @@ static int is_windows_drive(const char *filename) } #endif +static const char *raw_filename(const char *filename) +{ + char *_filename; + + _filename = strrchr(filename, ':'); + if (_filename) + return _filename + 1; + else + return filename; +} + static BlockDriver *find_protocol(const char *filename) { BlockDriver *drv1; char protocol[128]; - int len; + int len, is_fmt = 0; const char *p; + if (!strncmp(filename, "fmt:", 4)) { + filename += 4; + is_fmt = 1; + } + #ifdef _WIN32 if (is_windows_drive(filename) || is_windows_drive_prefix(filename)) - return &bdrv_raw; + return NULL; #endif p = strchr(filename, ':'); if (!p) - return &bdrv_raw; + return NULL; len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; memcpy(protocol, filename, len); protocol[len] = '\0'; for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { - if (drv1->protocol_name && - !strcmp(drv1->protocol_name, protocol)) - return drv1; + if (is_fmt) { + if (!strcmp(drv1->format_name, protocol)) + return drv1; + } else { + if (drv1->protocol_name && + !strcmp(drv1->protocol_name, protocol)) + return drv1; + } } return NULL; } @@ -268,6 +302,14 @@ static BlockDriver *find_image_format(const char *filename) recognized as a host CDROM */ if (strstart(filename, "/dev/cdrom", NULL)) return &bdrv_host_device; + + drv = find_protocol(filename); + if ((drv != NULL) && (drv->protocol_name == NULL)) + return drv; + + if (drv == NULL) + filename = raw_filename(filename); + #ifdef _WIN32 if (is_windows_drive(filename)) return &bdrv_host_device; @@ -281,7 +323,6 @@ static BlockDriver *find_image_format(const char *filename) } #endif - drv = find_protocol(filename); /* no need to test disk image formats for vvfat */ if (drv == &bdrv_vvfat) return drv; @@ -371,8 +412,11 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (is_protocol) snprintf(backing_filename, sizeof(backing_filename), "%s", filename); - else - realpath(filename, backing_filename); + else { + const char *p; + p = realpath(raw_filename(filename), backing_filename); + path_combine(backing_filename, sizeof(backing_filename), p, filename); + } if (bdrv_create(&bdrv_qcow2, tmp_filename, total_size, backing_filename, 0) < 0) { @@ -386,7 +430,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (flags & BDRV_O_FILE) { drv = find_protocol(filename); if (!drv) - return -ENOENT; + drv = &bdrv_raw; } else { if (!drv) { drv = find_image_format(filename); @@ -404,6 +448,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK); else open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); + + if (drv && !drv->protocol_name) + filename = raw_filename(filename); + ret = drv->bdrv_open(bs, filename, open_flags); if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) { ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR); -- 1.6.0.6 --------------060409010009020207040002 Content-Type: text/plain; name="EXAMPLES" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="EXAMPLES" ### FIND_IMAGE_FORMAT and FIND_PROTOCOL lines are just debugging messages ### which do not appear in the patch. ### created loop block devices using dd (of exising images) and losetup ### /dev/loop0 is of format qcow2 ### /dev/loop2 is of format raw ### qcow2 format over block devices ### qemu-img with -f $ qemu-img info -f qcow2 /dev/loop0 image: /dev/loop0 file format: qcow2 virtual size: 20G (21474836480 bytes) disk size: 0 cluster_size: 4096 ### using the new fmt "protocol" $ qemu-img info fmt:qcow2:/dev/loop0 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 image: fmt:qcow2:/dev/loop0 file format: qcow2 virtual size: 20G (21474836480 bytes) disk size: unavailable cluster_size: 4096 ### no format -- does not probe -- set to host_device ### -- will fail to boot $ qemu-img info /dev/loop0 FIND_IMAGE_FORMAT filename=/dev/loop0 FIND_IMAGE_FORMAT filename=/dev/loop0 is a host_device image: /dev/loop0 file format: host_device virtual size: 4.0G (4347179008 bytes) disk size: 0 ### creating a qcow image using new fmt "protocol" $ qemu-img create -b fmt:qcow2:/dev/loop0 -f qcow2 /tmp/uuu.qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 Formatting '/tmp/uuu.qcow2', fmt=qcow2, backing_file=fmt:qcow2:/dev/loop0, size=20971520 kB $ qemu-img info -f qcow2 /tmp/uuu.qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 image: /tmp/uuu.qcow2 file format: qcow2 virtual size: 20G (21474836480 bytes) disk size: 96K cluster_size: 4096 backing file: fmt:qcow2:/dev/loop0 (actual path: fmt:qcow2:/dev/loop0) ### creating an image with a relative backing file $ pushd /tmp/images/ > /dev/null $ qemu-img create -b fmt:qcow2:../uuu.qcow2 -f qcow2 ./uuu.qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:../uuu.qcow2 FIND_PROTOCOL filename=qcow2:../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 Formatting './uuu.qcow2', fmt=qcow2, backing_file=fmt:qcow2:../uuu.qcow2, size=20971520 kB $ popd > /dev/null $ qemu-img info -f qcow2 /tmp/images/uuu.qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 image: /tmp/images/uuu.qcow2 file format: qcow2 virtual size: 20G (21474836480 bytes) disk size: 96K cluster_size: 4096 backing file: fmt:qcow2:../uuu.qcow2 (actual path: fmt:qcow2:/tmp/images/../uuu.qcow2) ### probing leaf image $ qemu-img info /tmp/images/uuu.qcow2 FIND_IMAGE_FORMAT filename=/tmp/images/uuu.qcow2 FIND_IMAGE_FORMAT filename=/tmp/images/uuu.qcow2 PROBING FIND_IMAGE_FORMAT filename=/tmp/images/uuu.qcow2 PROBING found qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 image: /tmp/images/uuu.qcow2 file format: qcow2 virtual size: 20G (21474836480 bytes) disk size: 96K cluster_size: 4096 backing file: fmt:qcow2:../uuu.qcow2 (actual path: fmt:qcow2:/tmp/images/../uuu.qcow2) ### raw format over file $ qemu-img create -f raw /tmp/image1.raw 10G Formatting '/tmp/image1.raw', fmt=raw, size=10485760 kB ### using new "fmt" "protocol" -- no probing $ qemu-img create -b fmt:raw:/tmp/image1.raw -f qcow2 /tmp/image1.qcow2 FIND_IMAGE_FORMAT filename=fmt:raw:/tmp/image1.raw FIND_PROTOCOL filename=raw:/tmp/image1.raw found format raw FIND_IMAGE_FORMAT filename=fmt:raw:/tmp/image1.raw found format raw Formatting '/tmp/image1.qcow2', fmt=qcow2, backing_file=fmt:raw:/tmp/image1.raw, size=10485760 kB ### probing only qcow image (not raw backing file) $ qemu-img info /tmp/image1.qcow2 FIND_IMAGE_FORMAT filename=/tmp/image1.qcow2 FIND_IMAGE_FORMAT filename=/tmp/image1.qcow2 PROBING FIND_IMAGE_FORMAT filename=/tmp/image1.qcow2 PROBING found qcow2 FIND_IMAGE_FORMAT filename=fmt:raw:/tmp/image1.raw FIND_PROTOCOL filename=raw:/tmp/image1.raw found format raw FIND_IMAGE_FORMAT filename=fmt:raw:/tmp/image1.raw found format raw image: /tmp/image1.qcow2 file format: qcow2 virtual size: 10G (10737418240 bytes) disk size: 56K cluster_size: 4096 backing file: fmt:raw:/tmp/image1.raw (actual path: fmt:raw:/tmp/image1.raw) ### raw format over host device $ qemu-img info /dev/loop2 FIND_IMAGE_FORMAT filename=/dev/loop2 FIND_IMAGE_FORMAT filename=/dev/loop2 is a host_device image: /dev/loop2 file format: host_device virtual size: 300M (314572800 bytes) disk size: 0 ### use new "fmt" "protocol" -- no real need as qemu sets host_device anyways $ qemu-img create -b fmt:host_device:/dev/loop2 -f qcow2 /tmp/mydsl.qcow2 Formatting '/tmp/mydsl.qcow2', fmt=qcow2, backing_file=fmt:host_device:/dev/loop2, size=307200 kB $ qemu-img info -f qcow2 /tmp/mydsl.qcow2 image: /tmp/mydsl.qcow2 file format: qcow2 virtual size: 300M (314572800 bytes) disk size: 16K cluster_size: 4096 backing file: fmt:host_device:/dev/loop2 (actual path: fmt:host_device:/dev/loop2)\ ### run with probing (only upmost image) $ qemu-system-x86_64 -hda /tmp/mydsl.qcow2 FIND_IMAGE_FORMAT filename=/tmp/mydsl.qcow2 FIND_IMAGE_FORMAT filename=/tmp/mydsl.qcow2 PROBING FIND_IMAGE_FORMAT filename=/tmp/mydsl.qcow2 PROBING found qcow2 FIND_IMAGE_FORMAT filename=fmt:host_device:/dev/loop2 FIND_PROTOCOL filename=host_device:/dev/loop2 found format host_device FIND_IMAGE_FORMAT filename=fmt:host_device:/dev/loop2 found format host_device ### run with no probing (using -drive format) $ qemu-system-x86_64 -drive file=/tmp/mydsl.qcow2,format=qcow2 FIND_IMAGE_FORMAT filename=fmt:host_device:/dev/loop2 FIND_PROTOCOL filename=host_device:/dev/loop2 found format host_device FIND_IMAGE_FORMAT filename=fmt:host_device:/dev/loop2 found format host_device ### mydsl2 with no fmt, set host_device format for /dev/loop2 (no probing for host devices) $ qemu-img create -b /dev/loop2 -f qcow2 /tmp/mydsl2.qcow2 FIND_IMAGE_FORMAT filename=/dev/loop2 FIND_IMAGE_FORMAT filename=/dev/loop2 is a host_device Formatting '/tmp/mydsl2.qcow2', fmt=qcow2, backing_file=/dev/loop2, size=307200 kB $ qemu-img info -f qcow2 /tmp/mydsl2.qcow2 FIND_IMAGE_FORMAT filename=/dev/loop2 FIND_IMAGE_FORMAT filename=/dev/loop2 is a host_device image: /tmp/mydsl2.qcow2 file format: qcow2 virtual size: 300M (314572800 bytes) disk size: 16K cluster_size: 4096 backing file: /dev/loop2 (actual path: /dev/loop2) #### testing nbd together with "fmt" $ qemu-nbd -v -n --snapshot -t -k /tmp/uuu.socket fmt:qcow2:/tmp/images/uuu.qcow2 & [1] 31292 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=/tmp/vl.uXmIKt FIND_IMAGE_FORMAT filename=/tmp/vl.uXmIKt PROBING FIND_IMAGE_FORMAT filename=/tmp/vl.uXmIKt PROBING found qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 FIND_PROTOCOL filename=qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/tmp/images/../uuu.qcow2 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 ### info works $ qemu-img info nbd:unix:/tmp/uuu.socket FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING found nbd image: nbd:unix:/tmp/uuu.socket file format: nbd virtual size: 20G (21474836480 bytes) disk size: unavailable $ qemu-system-x86_64 -snapshot -hda nbd:unix:/tmp/uuu.socket FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING found nbd FIND_IMAGE_FORMAT filename=/tmp/vl.C1NTVv FIND_IMAGE_FORMAT filename=/tmp/vl.C1NTVv PROBING FIND_IMAGE_FORMAT filename=/tmp/vl.C1NTVv PROBING found qcow2 FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING FIND_PROTOCOL filename=nbd:unix:/tmp/uuu.socket: found protocol nbd FIND_IMAGE_FORMAT filename=nbd:unix:/tmp/uuu.socket PROBING found nbd ### $ kill %1 $ /bin/rm -f /tmp/uuu.socket ### checking vvfat: $ qemu-system-x86_64 -hda /tmp/uuu.qcow2 -hdb fat:floppy:/tmp/images FIND_IMAGE_FORMAT filename=/tmp/uuu.qcow2 FIND_IMAGE_FORMAT filename=/tmp/uuu.qcow2 PROBING FIND_IMAGE_FORMAT filename=/tmp/uuu.qcow2 PROBING found qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 FIND_PROTOCOL filename=qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fmt:qcow2:/dev/loop0 found format qcow2 FIND_IMAGE_FORMAT filename=fat:floppy:/tmp/images FIND_PROTOCOL filename=fat:floppy:/tmp/images: found protocol fat ### --------------060409010009020207040002--