qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to ima


From: Uri Lublin
Subject: [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames
Date: Mon, 05 Jan 2009 03:28:08 +0200
User-agent: Thunderbird 2.0.0.18 (X11/20081119)

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 <address@hidden>

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 <address@hidden>
---
 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

### 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
### <running>

$ 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
### <running>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]