]> xenbits.xensource.com Git - qemu-xen-3.3-testing.git/commitdiff
Avoid trusting client-controlled areas of xenstore.
authorIan Jackson <ian.jackson@eu.citrix.com>
Thu, 12 Feb 2009 11:05:55 +0000 (11:05 +0000)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Thu, 12 Feb 2009 11:05:55 +0000 (11:05 +0000)
Various parts of xenstore, specifically /local/GUEST/devices, are
writeable by the guest.  Information from these areas must be used
with care, to avoid the guest tricking qemu-dm into improperly using
its privileged access to dom0 resources.

To this end:
 * Variables and functions referring to client-controlled data have
   had `danger' added to their names.
 * There is a new sanitisation/checking arrangement for getting
   backend paths and information about the configuration of device
   backends, given the frontend information.  This is so that when
   qemu is providing a data path which is parallel to the PV
   frontend/backend arrangements, it only uses the configuration from
   a genuine backend which is really configured to serve qemu's own
   guest.
 * For information which should be read from or written to the `vm'
   tree, we obtain the guest's uuid from the hypervisor (the `label'
   as the hypercall interface calls it) rather than reading it from
   the guest-controlled areas of xenstore.
 * The `phantom vbd' feature is disabled.  It relies on
   guest-controlled xenstore areas indicating device paths on the
   guest.  We do not believe this feature is currently very relevant.
 * We _do_ allow the guest of a stubdom qemu to mess up the
   correspondence between pv backends and emulated devices, in the
   sense that we don't mind if the guest directs qemu to use a `wrong'
   frontend.

(cherry picked from commit 5d9302d372cf0a2951e3e0c61a5e08496de8aa2b)
Conflicts:
qemu-xen.h

hw/pc.c
hw/tpm_tis.c
i386-dm/helper2.c
qemu-xen.h
xen-config-host.h
xenstore.c

diff --git a/hw/pc.c b/hw/pc.c
index c13e45375747c2591ca2eeaa8ddf935c12259107..656f755b1f7bcef772c7d6bf32e191b78ce6a855 100644 (file)
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1050,7 +1050,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     }
 
 #ifdef HAS_TPM
-    if (has_tpm_device())
+    if (has_tpm_device_danger())
         tpm_tis_init(&i8259[11]);
 #endif
 
index c02a6493ca8f5c9b258ad6b3d1e692bc7a4430ae..ceb0decacdbadea23cd6aba3be86c51d10a40441 100644 (file)
@@ -1052,12 +1052,12 @@ static int TPM_Receive(tpmState *s, tpmBuffer *buffer)
    Helper functions for reading data from the xenstore such as
    reading virtual TPM instance information
  ****************************************************************************/
-int has_tpm_device(void)
+int has_tpm_device_danger(void)
 {
     int ret = 0;
     struct xs_handle *handle = xs_daemon_open();
     if (handle) {
-        ret = xenstore_domain_has_devtype(handle, "vtpm");
+        ret = xenstore_domain_has_devtype_danger(handle, "vtpm");
         xs_daemon_close(handle);
     }
     return ret;
@@ -1083,10 +1083,11 @@ static uint32_t vtpm_instance_from_xenstore(void)
     FD_ZERO(&readfds);
 
     if (handle) {
-        char **e = xenstore_domain_get_devices(handle, "vtpm", &num);
+        char **e_danger =
+            xenstore_domain_get_devices_danger(handle, "vtpm", &num);
         int fd = xs_fileno(handle);
         FD_SET(fd, &readfds);
-        if (e) {
+        if (e_danger) {
             do {
                 struct timeval tv = {
                     .tv_sec  = 30,
@@ -1095,12 +1096,12 @@ static uint32_t vtpm_instance_from_xenstore(void)
                 /* need to make sure that the hotplug scripts have finished */
                 char *status = xenstore_read_hotplug_status(handle,
                                                             "vtpm",
-                                                            e[0]);
+                                                            e_danger[0]);
                 if (status) {
                     if (!strcmp(status, "connected")) {
                         char *inst = xenstore_backend_read_variable(handle,
                                                                     "vtpm",
-                                                                    e[0],
+                                                                    e_danger[0],
                                                                    "instance");
                         if (1 != (sscanf(inst,"%d",&number)))
                             number = VTPM_BAD_INSTANCE;
@@ -1121,7 +1122,7 @@ static uint32_t vtpm_instance_from_xenstore(void)
                     if (!subscribed) {
                         rc = xenstore_subscribe_to_hotplug_status(handle,
                                                                   "vtpm",
-                                                                  e[0],
+                                                                  e_danger[0],
                                                                   token);
                         if (rc != 0)
                             break;
@@ -1136,13 +1137,13 @@ static uint32_t vtpm_instance_from_xenstore(void)
                         end = 1;
                 }
             } while (end == 0);
-            free(e);
+            free(e_danger);
         }
         if (subscribed) {
             /* clean up */
             xenstore_unsubscribe_from_hotplug_status(handle,
                                                      "vtpm",
-                                                     e[0],
+                                                     e_danger[0],
                                                      token);
         }
         xs_daemon_close(handle);
index d630cb0bba688ce8146569600104fdf6705f5783..dee8efd360df49d8d2a0e106e3dd42cd04105b1a 100644 (file)
@@ -83,6 +83,14 @@ int xc_handle = -1;
 char domain_name[64] = "Xen-no-name";
 int domid;
 
+int domid_backend = 0;
+  /* 0 for now.  If we ever have non-dom0 backend domains, this
+   * will have to be the domid of the real backend domain.
+   * For stubdom, this is the domain of the _real_ backend
+   * not of the stubdom.  So still 0 unless we're in a driver
+   * domain case.
+   */
+
 long time_offset = 0;
 
 shared_iopage_t *shared_page = NULL;
index 06d8ec9f4c41695dba08cf8c68500878f0d051d5..d0e36f9205b723c6a69dfae86d81dbf26b547e9e 100644 (file)
@@ -48,14 +48,16 @@ void xenstore_write_vncport(int vnc_display);
 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen);
 void xenstore_write_vslots(char *vslots);
 
-int xenstore_domain_has_devtype(struct xs_handle *handle,
+int xenstore_domain_has_devtype_danger(struct xs_handle *handle,
                                 const char *devtype);
-char **xenstore_domain_get_devices(struct xs_handle *handle,
+char **xenstore_domain_get_devices_danger(struct xs_handle *handle,
                                    const char *devtype, unsigned int *num);
 char *xenstore_read_hotplug_status(struct xs_handle *handle,
-                                   const char *devtype, const char *inst);
+                                   const char *devtype,
+                                  const char *inst_danger);
 char *xenstore_backend_read_variable(struct xs_handle *,
-                                     const char *devtype, const char *inst,
+                                     const char *devtype,
+                                    const char *inst_danger,
                                      const char *var);
 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
                                          const char *devtype,
@@ -66,6 +68,18 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
                                              const char *inst,
                                              const char *token);
 
+ /* `danger' means that this parameter, variable or function refers to
+  * an area of xenstore which is writeable by the guest and thus must
+  * not be trusted by qemu code.  For variables containing xenstore
+  * paths, `danger' can mean that both the path refers to a
+  * guest-writeable area (so that data read from there is dangerous
+  * too) and that path's value was read from somewhere controlled by
+  * the guest (so writing to this path is not safe either).
+  */
+ /* When we're stubdom we don't mind doing as our domain tells us to,
+  * at least when it comes to running our own frontends
+  */
+
 int xenstore_vm_write(int domid, char *key, char *val);
 char *xenstore_vm_read(int domid, char *key, unsigned int *len);
 
index 6e84a98142a84d9932d089230a3a46ca27315d4d..c5e019b5747d69a98156c101939e09087c051758 100644 (file)
@@ -1,5 +1,5 @@
 extern char domain_name[64];
-extern int domid;
+extern int domid, domid_backend;
 
 #include <errno.h>
 
index dd487ddd08505b0327bec8fd788ddbd7dd25fdae..2a50584fd2c513e203f495dfbfad370bad166f19 100644 (file)
@@ -145,49 +145,179 @@ static int drive_name_to_index(const char *name) {
     return ret;
 }
 
+static void xenstore_get_backend_path(char **backend, const char *devtype,
+                                     const char *frontend_dompath,
+                                     int frontend_domid,
+                                     const char *inst_danger) {
+    /* On entry: *backend will be passed to free()
+     * On succcess: *backend will be from malloc
+     * On failure: *backend==0
+     */
+    char *bpath=0;
+    char *frontend_path=0;
+    char *backend_dompath=0;
+    char *expected_backend=0;
+    char *frontend_backend_path=0;
+    char *backend_frontend_path=0;
+    char *frontend_doublecheck=0;
+    int len;
+    const char *frontend_idpath_slash;
+
+    /* clear out return value for if we error out */
+    free(*backend);
+    *backend = 0;
+
+    if (strchr(inst_danger,'/')) {
+        fprintf(logfile, "xenstore_get_backend_path inst_danger has slash"
+                " which is forbidden (devtype %s)\n", devtype);
+       goto out;
+    }
+
+    if (pasprintf(&frontend_path, "%s/device/%s/%s",
+                  frontend_dompath, devtype, inst_danger)
+        == -1) goto out;
+
+    if (pasprintf(&frontend_backend_path, "%s/backend",
+                  frontend_path)
+        == -1) goto out;
+
+    bpath = xs_read(xsh, XBT_NULL, frontend_backend_path, &len);
+
+    /* now we must check that the backend is intended for use
+     * by this frontend, since the frontend's /backend xenstore node
+     * is writeable by the untrustworthy guest. */
+
+    backend_dompath = xs_get_domain_path(xsh, domid_backend);
+    if (!backend_dompath) goto out;
+    
+    if (pasprintf(&expected_backend, "%s/backend/%s/%lu/%s",
+                  backend_dompath, devtype, frontend_domid, inst_danger)
+        == -1) goto out;
+
+    if (strcmp(bpath, expected_backend)) {
+        fprintf(stderr, "frontend `%s' expected backend `%s' got `%s',"
+                " ignoring\n", frontend_path, expected_backend, bpath);
+        errno = EINVAL;
+        goto out;
+    }
+
+    if (pasprintf(&backend_frontend_path, "%s/frontend", bpath)
+        == -1) goto out;
+
+    frontend_doublecheck = xs_read(xsh, XBT_NULL, backend_frontend_path, &len);
+
+    if (strcmp(frontend_doublecheck, frontend_path)) {
+        fprintf(stderr, "frontend `%s' backend `%s' points to other frontend"
+                " `%s', ignoring\n", frontend_path, bpath, frontend_doublecheck);
+        errno = EINVAL;
+        goto out;
+    }
+
+    /* steal bpath */
+    *backend = bpath;
+    bpath = 0;
+
+ out:
+    free(bpath);
+    free(frontend_path);
+    free(backend_dompath);
+    free(expected_backend);
+    free(frontend_backend_path);
+    free(backend_frontend_path);
+    free(frontend_doublecheck);
+}
+
+const char *xenstore_get_guest_uuid(void) {
+#ifdef CONFIG_STUBDOM
+    return 0;
+#else
+
+    static char *already_computed;
+
+    xc_domaininfo_t info;
+    int xch = -1, r, i;
+    char *p;
+
+    if (already_computed)
+        return already_computed;
+
+    xch = xc_interface_open();
+    if (xch == -1) {
+        fprintf(logfile, "cannot get uuid - xc_interface_open() failed: %s\n",
+                strerror(errno));
+        goto out;
+    }
+    r = xc_domain_getinfolist(xch, domid, 1, &info);
+    if (r != 1) {
+        fprintf(logfile, "cannot get uuid - xc_domain_getinfolist() failed:"
+                " %s\n", strerror(errno));
+        goto out;
+    }
+    already_computed = malloc(37);
+    for (i = 0, p = already_computed; i < 16; i++, p += 2) {
+        if (i==4 || i==6 || i==8 || i==10)
+            *p++ = '-';
+        sprintf(p, "%02x", info.handle[i]);
+    }
+    close(xch);
+    return already_computed;
+
+ out:
+    if (xch != -1)
+        close(xch);
+    
+    return 0;
+#endif
+}
+
 #define DIRECT_PCI_STR_LEN 160
 char direct_pci_str[DIRECT_PCI_STR_LEN];
 void xenstore_parse_domain_config(int hvm_domid)
 {
-    char **e = NULL;
-    char *buf = NULL, *path;
+    char **e_danger = NULL;
+    char *buf = NULL;
     char *fpath = NULL, *bpath = NULL,
-        *dev = NULL, *params = NULL, *type = NULL, *drv = NULL;
+        *dev = NULL, *params = NULL, *drv = NULL;
     int i, any_hdN = 0, ret;
     unsigned int len, num, hd_index, pci_devid = 0;
     BlockDriverState *bs;
     BlockDriver *format;
 
+    /* paths controlled by untrustworthy guest, and values read from them */
+    char *danger_path;
+    char *danger_buf = NULL;
+    char *danger_type = NULL;
+
     for(i = 0; i < MAX_DRIVES + 1; i++)
         media_filename[i] = NULL;
 
+    xenstore_get_guest_uuid();
+
     xsh = xs_daemon_open();
     if (xsh == NULL) {
         fprintf(logfile, "Could not contact xenstore for domain config\n");
         return;
     }
 
-    path = xs_get_domain_path(xsh, hvm_domid);
-    if (path == NULL) {
+    danger_path = xs_get_domain_path(xsh, hvm_domid);
+    if (danger_path == NULL) {
         fprintf(logfile, "xs_get_domain_path() error\n");
         goto out;
     }
 
-    if (pasprintf(&buf, "%s/device/vbd", path) == -1)
+    if (pasprintf(&danger_buf, "%s/device/vbd", danger_path) == -1)
         goto out;
 
-    e = xs_directory(xsh, XBT_NULL, buf, &num);
-    if (e == NULL)
+    e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
+    if (e_danger == NULL)
         num = 0;
 
     for (i = 0; i < num; i++) {
         /* read the backend path */
-        if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
-            continue;
-        free(bpath);
-        bpath = xs_read(xsh, XBT_NULL, buf, &len);
+        xenstore_get_backend_path(&bpath, "vbd", danger_path, hvm_domid,
+                                 e_danger[i]);
         if (bpath == NULL)
-            continue;
+            continue;    
         /* read the name of the device */
         if (pasprintf(&buf, "%s/dev", bpath) == -1)
             continue;
@@ -203,12 +333,8 @@ void xenstore_parse_domain_config(int hvm_domid)
         
     for (i = 0; i < num; i++) {
        format = NULL; /* don't know what the format is yet */
-
         /* read the backend path */
-        if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
-            continue;
-        free(bpath);
-        bpath = xs_read(xsh, XBT_NULL, buf, &len);
+        xenstore_get_backend_path(&bpath, "vbd", danger_path, hvm_domid, e_danger[i]);
         if (bpath == NULL)
             continue;
         /* read the name of the device */
@@ -226,10 +352,11 @@ void xenstore_parse_domain_config(int hvm_domid)
        if (ret)
            continue;
         /* read the type of the device */
-        if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
+        if (pasprintf(&danger_buf, "%s/device/vbd/%s/device-type",
+                      danger_path, e_danger[i]) == -1)
             continue;
-        free(type);
-        type = xs_read(xsh, XBT_NULL, buf, &len);
+        free(danger_type);
+        danger_type = xs_read(xsh, XBT_NULL, danger_buf, &len);
         if (pasprintf(&buf, "%s/params", bpath) == -1)
             continue;
         free(params);
@@ -267,21 +394,29 @@ void xenstore_parse_domain_config(int hvm_domid)
            format = &bdrv_raw;
         }
 
+#if 0
+       /* Phantom VBDs are disabled because the use of paths
+        * from guest-controlled areas in xenstore is unsafe.
+        * Hopefully if they are really needed for something
+        * someone will shout and then we will find out what for.
+        */
         /* 
          * check if device has a phantom vbd; the phantom is hooked
          * to the frontend device (for ease of cleanup), so lookup 
          * the frontend device, and see if there is a phantom_vbd
          * if there is, we will use resolution as the filename
          */
-        if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
+        if (pasprintf(&danger_buf, "%s/device/vbd/%s/phantom_vbd", path, e_danger[i]) == -1)
             continue;
-        free(fpath);
-        fpath = xs_read(xsh, XBT_NULL, buf, &len);
-        if (fpath) {
-            if (pasprintf(&buf, "%s/dev", fpath) == -1)
+        free(danger_fpath);
+        danger_fpath = xs_read(xsh, XBT_NULL, danger_buf, &len);
+        if (danger_fpath) {
+            if (pasprintf(&danger_buf, "%s/dev", danger_fpath) == -1)
                 continue;
             free(params);
-            params = xs_read(xsh, XBT_NULL, buf , &len);
+           params_danger = xs_read(xsh, XBT_NULL, danger_buf , &len);
+            DANGER DANGER params is supposedly trustworthy but here
+                         we read it from untrusted part of xenstore
             if (params) {
                 /* 
                  * wait for device, on timeout silently fail because we will 
@@ -290,10 +425,11 @@ void xenstore_parse_domain_config(int hvm_domid)
                 waitForDevice(params);
             }
         }
+#endif
 
         bs = bdrv_new(dev);
         /* check if it is a cdrom */
-        if (type && !strcmp(type, "cdrom")) {
+        if (danger_type && !strcmp(danger_type, "cdrom")) {
             bdrv_set_type_hint(bs, BDRV_TYPE_CDROM);
             if (pasprintf(&buf, "%s/params", bpath) != -1)
                 xs_watch(xsh, buf, dev);
@@ -301,9 +437,9 @@ void xenstore_parse_domain_config(int hvm_domid)
 
         /* open device now if media present */
 #ifdef CONFIG_STUBDOM
-        if (pasprintf(&buf, "%s/device/vbd/%s", path, e[i]) == -1)
+        if (pasprintf(&danger_buf, "%s/device/vbd/%s", danger_path, e_danger[i]) == -1)
             continue;
-       if (bdrv_open2(bs, buf, 0 /* snapshot */, &bdrv_vbd) == 0) {
+       if (bdrv_open2(bs, danger_buf, 0 /* snapshot */, &bdrv_vbd) == 0) {
            pstrcpy(bs->filename, sizeof(bs->filename), params);
            continue;
        }
@@ -340,31 +476,31 @@ void xenstore_parse_domain_config(int hvm_domid)
     }
 
 #ifdef CONFIG_STUBDOM
-    if (pasprintf(&buf, "%s/device/vkbd", path) == -1)
+    if (pasprintf(&danger_buf, "%s/device/vkbd", danger_path) == -1)
         goto out;
 
-    free(e);
-    e = xs_directory(xsh, XBT_NULL, buf, &num);
+    free(e_danger);
+    e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
 
-    if (e) {
+    if (e_danger) {
         for (i = 0; i < num; i++) {
-            if (pasprintf(&buf, "%s/device/vkbd/%s", path, e[i]) == -1)
+            if (pasprintf(&danger_buf, "%s/device/vkbd/%s", danger_path, e_danger[i]) == -1)
                 continue;
-            xenfb_connect_vkbd(buf);
+            xenfb_connect_vkbd(danger_buf);
         }
     }
 
-    if (pasprintf(&buf, "%s/device/vfb", path) == -1)
+    if (pasprintf(&danger_buf, "%s/device/vfb", danger_path) == -1)
         goto out;
 
-    free(e);
-    e = xs_directory(xsh, XBT_NULL, buf, &num);
+    free(e_danger);
+    e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
 
-    if (e) {
+    if (e_danger) {
         for (i = 0; i < num; i++) {
-            if (pasprintf(&buf, "%s/device/vfb/%s", path, e[i]) == -1)
+            if (pasprintf(&danger_buf, "%s/device/vfb/%s", danger_path, e_danger[i]) == -1)
                 continue;
-            xenfb_connect_vfb(buf);
+            xenfb_connect_vfb(danger_buf);
         }
     }
 #endif
@@ -416,13 +552,14 @@ void xenstore_parse_domain_config(int hvm_domid)
     }
 
  out:
-    free(type);
+    free(danger_type);
     free(params);
     free(dev);
     free(bpath);
     free(buf);
-    free(path);
-    free(e);
+    free(danger_buf);
+    free(danger_path);
+    free(e_danger);
     free(drv);
     return;
 }
@@ -804,7 +941,7 @@ void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
 /*
  * get all device instances of a certain type
  */
-char **xenstore_domain_get_devices(struct xs_handle *handle,
+char **xenstore_domain_get_devices_danger(struct xs_handle *handle,
                                    const char *devtype, unsigned int *num)
 {
     char *path;
@@ -829,11 +966,12 @@ char **xenstore_domain_get_devices(struct xs_handle *handle,
 /*
  * Check whether a domain has devices of the given type
  */
-int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
+int xenstore_domain_has_devtype_danger(struct xs_handle *handle,
+                                    const char *devtype)
 {
     int rc = 0;
     unsigned int num;
-    char **e = xenstore_domain_get_devices(handle, devtype, &num);
+    char **e = xenstore_domain_get_devices_danger(handle, devtype, &num);
     if (e)
         rc = 1;
     free(e);
@@ -844,14 +982,22 @@ int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
  * Function that creates a path to a variable of an instance of a
  * certain device
  */
-static char *get_device_variable_path(const char *devtype, const char *inst,
+static char *get_device_variable_path(const char *devtype,
+                                      const char *inst_danger,
                                       const char *var)
 {
     char *buf = NULL;
-    if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
+    if (strchr(inst_danger,'/')) {
+        fprintf(logfile, "get_device_variable_path inst_danger has slash"
+                " which is forbidden (devtype %s)\n", devtype);
+        return NULL;
+    }
+
+    if (pasprintf(&buf, "/local/domain/%d/backend/%s/%d/%s/%s",
+                  domid_backend,
                   devtype,
                   domid,
-                  inst,
+                  inst_danger /* safe now */,
                   var) == -1) {
         free(buf);
         buf = NULL;
@@ -860,14 +1006,15 @@ static char *get_device_variable_path(const char *devtype, const char *inst,
 }
 
 char *xenstore_backend_read_variable(struct xs_handle *handle,
-                                     const char *devtype, const char *inst,
+                                     const char *devtype,
+                                     const char *inst_danger,
                                      const char *var)
 {
     char *value = NULL;
     char *buf = NULL;
     unsigned int len;
 
-    buf = get_device_variable_path(devtype, inst, var);
+    buf = get_device_variable_path(devtype, inst_danger, var);
     if (NULL == buf)
         goto out;
 
@@ -884,9 +1031,10 @@ char *xenstore_backend_read_variable(struct xs_handle *handle,
   of device and its instance.
 */
 char *xenstore_read_hotplug_status(struct xs_handle *handle,
-                                   const char *devtype, const char *inst)
+                                   const char *devtype,
+                                   const char *inst_danger)
 {
-    return xenstore_backend_read_variable(handle, devtype, inst,
+    return xenstore_backend_read_variable(handle, devtype, inst_danger,
                                           "hotplug-status");
 }
 
@@ -897,11 +1045,11 @@ char *xenstore_read_hotplug_status(struct xs_handle *handle,
  */
 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
                                          const char *devtype,
-                                         const char *inst,
+                                         const char *inst_danger,
                                          const char *token)
 {
     int rc = 0;
-    char *path = get_device_variable_path(devtype, inst, "hotplug-status");
+    char *path = get_device_variable_path(devtype, inst_danger, "hotplug-status");
 
     if (path == NULL)
         return -1;
@@ -920,12 +1068,12 @@ int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
  */
 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
                                              const char *devtype,
-                                             const char *inst,
+                                             const char *inst_danger,
                                              const char *token)
 {
     int rc = 0;
     char *path;
-    path = get_device_variable_path(devtype, inst, "hotplug-status");
+    path = get_device_variable_path(devtype, inst_danger, "hotplug-status");
     if (path == NULL)
         return -1;
 
@@ -937,72 +1085,53 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
     return rc;
 }
 
-char *xenstore_vm_read(int domid, char *key, unsigned int *len)
-{
-    char *buf = NULL, *path = NULL, *value = NULL;
-
+static char *xenstore_vm_key_path(int domid, char *key) {
+    const char *uuid;
+    char *buf = NULL;
+    
     if (xsh == NULL)
-        goto out;
+        return NULL;
 
-    path = xs_get_domain_path(xsh, domid);
-    if (path == NULL) {
-        fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
-        goto out;
-    }
+    uuid = xenstore_get_guest_uuid();
+    if (!uuid) return NULL;
 
-    pasprintf(&buf, "%s/vm", path);
-    free(path);
-    path = xs_read(xsh, XBT_NULL, buf, NULL);
-    if (path == NULL) {
-        fprintf(logfile, "xs_read(%s): read error\n", buf);
-        goto out;
-    }
+    if (pasprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+        return NULL;
+    return buf;
+}
+
+char *xenstore_vm_read(int domid, char *key, unsigned int *len)
+{
+    char *path = NULL, *value = NULL;
 
-    pasprintf(&buf, "%s/%s", path, key);
-    value = xs_read(xsh, XBT_NULL, buf, len);
+    path = xenstore_vm_key_path(domid, key);
+
+    value = xs_read(xsh, XBT_NULL, path, len);
     if (value == NULL) {
-        fprintf(logfile, "xs_read(%s): read error\n", buf);
+        fprintf(logfile, "xs_read(%s): read error\n", path);
         goto out;
     }
 
  out:
     free(path);
-    free(buf);
     return value;
 }
 
 int xenstore_vm_write(int domid, char *key, char *value)
 {
-    char *buf = NULL, *path = NULL;
+    char *path = NULL;
     int rc = -1;
 
-    if (xsh == NULL)
-        goto out;
+    path = xenstore_vm_key_path(domid, key);
 
-    path = xs_get_domain_path(xsh, domid);
-    if (path == NULL) {
-        fprintf(logfile, "xs_get_domain_path: error\n");
-        goto out;
-    }
-
-    pasprintf(&buf, "%s/vm", path);
-    free(path);
-    path = xs_read(xsh, XBT_NULL, buf, NULL);
-    if (path == NULL) {
-        fprintf(logfile, "xs_read(%s): read error\n", buf);
-        goto out;
-    }
-
-    pasprintf(&buf, "%s/%s", path, key);
-    rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
+    rc = xs_write(xsh, XBT_NULL, path, value, strlen(value));
     if (rc == 0) {
-        fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
+        fprintf(logfile, "xs_write(%s, %s): write error\n", path, key);
         goto out;
     }
 
  out:
     free(path);
-    free(buf);
     return rc;
 }