qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames
@ 2009-01-05  1:28 Uri Lublin
  2009-01-07 16:55 ` Anthony Liguori
  0 siblings, 1 reply; 3+ messages in thread
From: Uri Lublin @ 2009-01-05  1:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Shahar Frank, Uri Lublin

[-- Attachment #1: Type: text/plain, Size: 6460 bytes --]

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 <uril@redhat.com>

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 <uril@redhat.com>
---
  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


[-- Attachment #2: EXAMPLES --]
[-- Type: text/plain, Size: 10707 bytes --]

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


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2009-01-07 17:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-05  1:28 [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames Uri Lublin
2009-01-07 16:55 ` Anthony Liguori
2009-01-07 17:56   ` Uri Lublin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).