diff options
Diffstat (limited to 'main/xen/xsa57-4.1.patch')
-rw-r--r-- | main/xen/xsa57-4.1.patch | 363 |
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, ...) + { |