It is possible for a guest with a raw formatted disk image to write a header to that disk image describing another format (such as qcow). Stopping and subsequent restart of the guest will cause QEMU to detect that format, and could allow the guest to read any host file. The patch extends the backend device description in xenstore by an optional format node. It makes xend force the raw format there, unless enable-image-format-probing is true in its configuration. This protects everybody from the vulnerability by default, but breaks images with formats other than raw. None of our tools creates such images. People who somehow created them themselves can choose to switch back to format auto-detection, relinquishing protection. diff -rup --exclude '*~' a/tools/examples/xend-config.sxp b/tools/examples/xend-config.sxp --- a/tools/examples/xend-config.sxp 2008-04-22 18:53:55.000000000 +0200 +++ b/tools/examples/xend-config.sxp 2008-05-05 14:19:07.000000000 +0200 @@ -240,3 +240,8 @@ # Script to run when the label of a resource has changed. #(resource-label-change-script '') + +# Allow probing of disk image file format. This is insecure! It lets +# a malicious domU read any file in dom0. Applies only to fully +# virtual domUs. Required for using formats other than raw. +#(enable-image-format-probing no) diff -rup --exclude '*~' a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c 2008-01-16 19:34:59.000000000 +0100 +++ b/tools/ioemu/xenstore.c 2008-05-05 14:28:34.000000000 +0200 @@ -83,8 +83,10 @@ void xenstore_parse_domain_config(int do char *buf = NULL, *path; char *fpath = NULL, *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL, *drv = NULL; + char *format = NULL; int i, is_scsi, is_hdN = 0; unsigned int len, num, hd_index; + BlockDriver *bdrv; for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) media_filename[i] = NULL; @@ -185,6 +187,19 @@ void xenstore_parse_domain_config(int do fprintf(logfile, "Strip off blktap sub-type prefix to %s\n", params); } + if (pasprintf(&buf, "%s/format", bpath) == -1) + continue; + free(format); + format = xs_read(xsh, XBT_NULL, buf, &len); + if (format) { + bdrv = bdrv_find_format(format); + if (!bdrv) { + fprintf(logfile, "invalid format '%s' for %s\n", format, bpath); + continue; + } + } else + bdrv = NULL; + /* * check if device has a phantom vbd; the phantom is hooked * to the frontend device (for ease of cleanup), so lookup @@ -218,8 +233,8 @@ void xenstore_parse_domain_config(int do } /* open device now if media present */ if (params[0]) { - if (bdrv_open(bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)], - params, 0 /* snapshot */) < 0) + if (bdrv_open2(bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)], + params, 0 /* snapshot */, drv) < 0) fprintf(stderr, "qemu: could not open hard disk image '%s'\n", params); } @@ -242,6 +257,7 @@ void xenstore_parse_domain_config(int do out: free(type); free(params); + free(format); free(dev); free(bpath); free(buf); diff -rup --exclude '*~' a/tools/python/xen/xend/XendOptions.py b/tools/python/xen/xend/XendOptions.py --- a/tools/python/xen/xend/XendOptions.py 2008-01-16 19:34:59.000000000 +0100 +++ b/tools/python/xen/xend/XendOptions.py 2008-05-05 14:36:23.000000000 +0200 @@ -314,6 +314,9 @@ class XendOptions: def get_vnc_x509_verify(self): return self.get_config_string('vnc-x509-verify', self.xend_vnc_x509_verify) + def get_enable_image_format_probing(self): + return self.get_config_bool('enable-image-format-probing', 'no') + class XendOptionsFile(XendOptions): diff -rup --exclude '*~' a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py --- a/tools/python/xen/xend/server/blkif.py 2008-01-16 19:34:59.000000000 +0100 +++ b/tools/python/xen/xend/server/blkif.py 2008-05-05 14:36:22.000000000 +0200 @@ -21,6 +21,7 @@ import string from xen.util import blkif import xen.util.xsm.xsm as security +from xen.xend import XendOptions from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -75,6 +76,10 @@ class BlkifController(DevController): if security.on(): self.do_access_control(config, uname) + xoptions = XendOptions.instance() + if not xoptions.get_enable_image_format_probing(): + back.update({'format' : 'raw'}) + devid = blkif.blkdev_name_to_number(dev) if devid is None: raise VmError('Unable to find number for device (%s)' % (dev))