aboutsummaryrefslogtreecommitdiffstats
path: root/main/xen/xsa57-4.1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/xen/xsa57-4.1.patch')
-rw-r--r--main/xen/xsa57-4.1.patch363
1 files changed, 363 insertions, 0 deletions
diff --git a/main/xen/xsa57-4.1.patch b/main/xen/xsa57-4.1.patch
new file mode 100644
index 0000000000..b9df838b72
--- /dev/null
+++ b/main/xen/xsa57-4.1.patch
@@ -0,0 +1,363 @@
+libxl: Restrict permissions on PV console device xenstore nodes
+
+Matthew Daley has observed that the PV console protocol places sensitive host
+state into a guest writeable xenstore locations, this includes:
+
+ - The pty used to communicate between the console backend daemon and its
+ client, allowing the guest administrator to read and write arbitrary host
+ files.
+ - The output file, allowing the guest administrator to write arbitrary host
+ files or to target arbitrary qemu chardevs which include sockets, udp, ptr,
+ pipes etc (see -chardev in qemu(1) for a more complete list).
+ - The maximum buffer size, allowing the guest administrator to consume more
+ resources than the host administrator has configured.
+ - The backend to use (qemu vs xenconsoled), potentially allowing the guest
+ administrator to confuse host software.
+
+So we arrange to make the sensitive keys in the xenstore frontend directory
+read only for the guest. This is safe since the xenstore permissions model,
+unlike POSIX directory permissions, does not allow the guest to remove and
+recreate a node if it has write access to the containing directory.
+
+There are a few associated wrinkles:
+
+ - The primary PV console is "special". It's xenstore node is not under the
+ usual /devices/ subtree and it does not use the customary xenstore state
+ machine protocol. Unfortunately its directory is used for other things,
+ including the vnc-port node, which we do not want the guest to be able to
+ write to. Rather than trying to track down all the possible secondary uses
+ of this directory just make it r/o to the guest. All newly created
+ subdirectories inherit these permissions and so are now safe by default.
+
+ - The other serial consoles do use the customary xenstore state machine and
+ therefore need write access to at least the "protocol" and "state" nodes,
+ however they may also want to use arbitrary "feature-foo" nodes (although
+ I'm not aware of any) and therefore we cannot simply lock down the entire
+ frontend directory. Instead we add support to libxl__device_generic_add for
+ frontend keys which are explicitly read only and use that to lock down the
+ sensitive keys.
+
+ - Minios' console frontend wants to write the "type" node, which it has no
+ business doing since this is a host/toolstack level decision. This fails
+ now that the node has become read only to the PV guest. Since the toolstack
+ already writes this node just remove the attempt to set it.
+
+This is CVE-XXXX-XXX / XSA-57
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+
+Conflicts (4.2 backport):
+ tools/libxl/libxl.c (no vtpm, free front_ro on error in
+ libxl__device_console_add)
+
+Conflicts (4.1 backport):
+ extras/mini-os/console/xenbus.c
+ tools/libxl/libxl.c
+ tools/libxl/libxl_device.c
+ tools/libxl/libxl_internal.h
+ tools/libxl/libxl_pci.c
+ tools/libxl/libxl_xshelp.c
+
+ - minios code was in xencons_ring.c
+ - many places need &gc not just gc
+ - libxl__xs_writev path is not const
+ - varios minor context fixups
+
+diff --git a/extras/mini-os/console/xencons_ring.c b/extras/mini-os/console/xencons_ring.c
+index 9ed3756..286c650 100644
+--- a/extras/mini-os/console/xencons_ring.c
++++ b/extras/mini-os/console/xencons_ring.c
+@@ -291,12 +291,6 @@ again:
+ goto abort_transaction;
+ }
+
+- err = xenbus_printf(xbt, nodename, "type", "%s", "ioemu");
+- if (err) {
+- message = "writing type";
+- goto abort_transaction;
+- }
+-
+ snprintf(path, sizeof(path), "%s/state", nodename);
+ err = xenbus_switch_state(xbt, path, XenbusStateConnected);
+ if (err) {
+diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
+index 3c2e1b2..54f440c 100644
+--- a/tools/libxl/libxl.c
++++ b/tools/libxl/libxl.c
+@@ -1036,8 +1036,9 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ rc = 0;
+
+@@ -1266,8 +1267,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ /* FIXME: wait for plug */
+ rc = 0;
+@@ -1478,8 +1480,9 @@ int libxl_device_net2_add(libxl_ctx *ctx, uint32_t domid, libxl_device_net2 *net
+ flexarray_append(front, "1");
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ /* FIXME: wait for plug */
+ rc = 0;
+@@ -1571,7 +1574,7 @@ int libxl_device_net2_del(libxl_ctx *ctx, libxl_device_net2 *net2, int wait)
+ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
+ {
+ libxl__gc gc = LIBXL_INIT_GC(ctx);
+- flexarray_t *front;
++ flexarray_t *front, *ro_front;
+ flexarray_t *back;
+ libxl__device device;
+ int rc;
+@@ -1581,6 +1584,11 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+ rc = ERROR_NOMEM;
+ goto out;
+ }
++ ro_front = flexarray_make(16, 1);
++ if (!ro_front) {
++ rc = ERROR_NOMEM;
++ goto out;
++ }
+ back = flexarray_make(16, 1);
+ if (!back) {
+ rc = ERROR_NOMEM;
+@@ -1607,25 +1615,27 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+
+ flexarray_append(front, "backend-id");
+ flexarray_append(front, libxl__sprintf(&gc, "%d", console->backend_domid));
+- flexarray_append(front, "limit");
+- flexarray_append(front, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
+- flexarray_append(front, "type");
++ flexarray_append(ro_front, "limit");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
++ flexarray_append(ro_front, "type");
+ if (console->consback == LIBXL_CONSBACK_XENCONSOLED)
+- flexarray_append(front, "xenconsoled");
++ flexarray_append(ro_front, "xenconsoled");
+ else
+- flexarray_append(front, "ioemu");
+- flexarray_append(front, "output");
+- flexarray_append(front, console->output);
++ flexarray_append(ro_front, "ioemu");
++ flexarray_append(ro_front, "output");
++ flexarray_append(ro_front, console->output);
++ flexarray_append(ro_front, "tty");
++ flexarray_append(ro_front, "");
+
+ if (device.devid == 0) {
+ if (console->build_state == NULL) {
+ rc = ERROR_INVAL;
+ goto out_free;
+ }
+- flexarray_append(front, "port");
+- flexarray_append(front, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
+- flexarray_append(front, "ring-ref");
+- flexarray_append(front, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
++ flexarray_append(ro_front, "port");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
++ flexarray_append(ro_front, "ring-ref");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
+ } else {
+ flexarray_append(front, "state");
+ flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
+@@ -1634,11 +1644,13 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ libxl__xs_kvs_of_flexarray(&gc, ro_front, ro_front->count));
+ rc = 0;
+ out_free:
+ flexarray_free(back);
++ flexarray_free(ro_front);
+ flexarray_free(front);
+ out:
+ libxl__free_all(&gc);
+@@ -1693,8 +1705,9 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
+ flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+ rc = 0;
+ out_free:
+ flexarray_free(back);
+@@ -1921,8 +1934,9 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
+ flexarray_append_pair(front, "state", libxl__sprintf(&gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+ rc = 0;
+ out_free:
+ flexarray_free(front);
+diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
+index 7e8fcef..0628840 100644
+--- a/tools/libxl/libxl_device.c
++++ b/tools/libxl/libxl_device.c
+@@ -62,12 +62,13 @@ char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device)
+ }
+
+ int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+- char **bents, char **fents)
++ char **bents, char **fents, char **ro_fents)
+ {
+ libxl__gc gc = LIBXL_INIT_GC(ctx);
+ char *frontend_path, *backend_path;
+ xs_transaction_t t;
+ struct xs_permissions frontend_perms[2];
++ struct xs_permissions ro_frontend_perms[2];
+ struct xs_permissions backend_perms[2];
+ int rc;
+
+@@ -84,21 +85,36 @@ int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+ frontend_perms[1].id = device->backend_domid;
+ frontend_perms[1].perms = XS_PERM_READ;
+
+- backend_perms[0].id = device->backend_domid;
+- backend_perms[0].perms = XS_PERM_NONE;
+- backend_perms[1].id = device->domid;
+- backend_perms[1].perms = XS_PERM_READ;
++ ro_frontend_perms[0].id = backend_perms[0].id = device->backend_domid;
++ ro_frontend_perms[0].perms = backend_perms[0].perms = XS_PERM_NONE;
++ ro_frontend_perms[1].id = backend_perms[1].id = device->domid;
++ ro_frontend_perms[1].perms = backend_perms[1].perms = XS_PERM_READ;
+
+ retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ /* FIXME: read frontend_path and check state before removing stuff */
+
+- if (fents) {
++ if (fents || ro_fents) {
+ xs_rm(ctx->xsh, t, frontend_path);
+ xs_mkdir(ctx->xsh, t, frontend_path);
+- xs_set_permissions(ctx->xsh, t, frontend_path, frontend_perms, ARRAY_SIZE(frontend_perms));
++ /* Console 0 is a special case. It doesn't use the regular PV
++ * state machine but also the frontend directory has
++ * historically contained other information, such as the
++ * vnc-port, which we don't want the guest fiddling with.
++ */
++ if (device->kind == DEVICE_CONSOLE && device->devid == 0)
++ xs_set_permissions(ctx->xsh, t, frontend_path,
++ ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
++ else
++ xs_set_permissions(ctx->xsh, t, frontend_path,
++ frontend_perms, ARRAY_SIZE(frontend_perms));
+ xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/backend", frontend_path), backend_path, strlen(backend_path));
+- libxl__xs_writev(&gc, t, frontend_path, fents);
++ if (fents)
++ libxl__xs_writev_perms(&gc, t, frontend_path, fents,
++ frontend_perms, ARRAY_SIZE(frontend_perms));
++ if (ro_fents)
++ libxl__xs_writev_perms(&gc, t, frontend_path, ro_fents,
++ ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
+ }
+
+ if (bents) {
+diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
+index 9cf503f..5ddd27b 100644
+--- a/tools/libxl/libxl_internal.h
++++ b/tools/libxl/libxl_internal.h
+@@ -143,6 +143,11 @@ _hidden char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int
+
+ _hidden int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+ char *dir, char **kvs);
++/* as writev but also sets the permissions on each path */
++_hidden int libxl__xs_writev_perms(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[],
++ struct xs_permissions *perms,
++ unsigned int num_perms);
+ _hidden int libxl__xs_write(libxl__gc *gc, xs_transaction_t t,
+ char *path, char *fmt, ...) PRINTF_ATTRIBUTE(4, 5);
+ /* Each fn returns 0 on success.
+@@ -185,7 +190,7 @@ _hidden int libxl__device_physdisk_major_minor(const char *physpath, int *major,
+ _hidden int libxl__device_disk_dev_number(const char *virtpath);
+
+ _hidden int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+- char **bents, char **fents);
++ char **bents, char **fents, char **ro_fents);
+ _hidden char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device);
+ _hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device);
+ _hidden int libxl__device_del(libxl_ctx *ctx, libxl__device *dev, int wait);
+diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c
+index b1d05d9..9c76bce 100644
+--- a/tools/libxl/libxl_pci.c
++++ b/tools/libxl/libxl_pci.c
+@@ -274,8 +274,9 @@ static int libxl_create_pci_backend(libxl__gc *gc, uint32_t domid, libxl_device_
+ flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(gc, front, front->count),
++ NULL);
+
+ out:
+ if (back)
+diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
+index 3dc9239..06b95e0 100644
+--- a/tools/libxl/libxl_xshelp.c
++++ b/tools/libxl/libxl_xshelp.c
+@@ -48,8 +48,10 @@ char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int length)
+ return kvs;
+ }
+
+-int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+- char *dir, char *kvs[])
++int libxl__xs_writev_perms(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[],
++ struct xs_permissions *perms,
++ unsigned int num_perms)
+ {
+ libxl_ctx *ctx = libxl__gc_owner(gc);
+ char *path;
+@@ -63,11 +65,19 @@ int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+ if (path && kvs[i + 1]) {
+ int length = strlen(kvs[i + 1]);
+ xs_write(ctx->xsh, t, path, kvs[i + 1], length);
++ if (perms)
++ xs_set_permissions(ctx->xsh, t, path, perms, num_perms);
+ }
+ }
+ return 0;
+ }
+
++int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[])
++{
++ return libxl__xs_writev_perms(gc, t, dir, kvs, NULL, 0);
++}
++
+ int libxl__xs_write(libxl__gc *gc, xs_transaction_t t,
+ char *path, char *fmt, ...)
+ {