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

* Re: [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames
  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
  0 siblings, 1 reply; 3+ messages in thread
From: Anthony Liguori @ 2009-01-07 16:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Shahar Frank, Uri Lublin

Uri Lublin wrote:
> 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).

Doesn't the fmt= option to the block drivers achieve the same thing 
(except for not probing the backend formats)?

Regards,

Anthony Liguori

> 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);

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

* Re: [Qemu-devel] [PATCH] qemu: block.c: introducing "fmt:FMT:" prefix to image-filenames
  2009-01-07 16:55 ` Anthony Liguori
@ 2009-01-07 17:56   ` Uri Lublin
  0 siblings, 0 replies; 3+ messages in thread
From: Uri Lublin @ 2009-01-07 17:56 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Shahar Frank, Uri Lublin, qemu-devel

Anthony Liguori wrote:
> Uri Lublin wrote:
>> 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).
> 
> Doesn't the fmt= option to the block drivers achieve the same thing 
> (except for not probing the backend formats)?

It does only for the leaf image (the writeable one).
While all backing files would be probed.
For example if we have a raw format image A (the base image), and the guest 
writes a fake qcow2 header into the beginning of the disk, and then the VM owner 
asks to create a new qcow2 image B with A as its backing file. In this scenario 
qemu opens A as a qcow2 image. This scenario is a security breach (mentioned by 
Daniel P. Berrange) as the fake qcow2 header may point to any host file.

I need to send a second version (-cdrom is broken). Comments about the concept 
would be appreciated.

Thanks for looking at it,
     Uri.

^ permalink raw reply	[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).