]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/xen.git/commitdiff
tools/libs/*: Introduce APIs to restrict handles to a specific domain.
authorIan Campbell <ian.campbell@citrix.com>
Wed, 16 Dec 2015 16:49:17 +0000 (16:49 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 10 Feb 2016 12:45:24 +0000 (12:45 +0000)
These are intended to allow user space processes (in particular QEMU)
to lock down all the handles at start of day and then drop the
privileges which would allow them to open any new unrestricted handles
(e.g. setuid or similar). This will reduce the privileges which taking
over such a process would gain an attacker wrt other domains in the
system.

These are currently unimplemented on all platforms, however the API
semantics are defined as the basis for discussion, and so that
consumers can rely on this interface always having been present rather
than requiring compile time API checks.

It is expected that these will be implemented by adding new ioctl
calls on the underlying driver and that the restrictions will be
enforced at the kernel interface layer (most likely by the kernel
itself).

For evtchn, foreignmemory, gnttab and gntshr this is hopefully
reasonably straightforward.

For call it is not so clear cut. Clearly the kernel cannot enforce
these restrictions for hypercalls which are not stable (domctl et al)
so they can never be on the whitelist. It may also be that potential
users would like to restrict the handle further than just a given
target domain, i.e. to a specific set of functionality (e.g. "things a
device model might reasonably do"). I think we will also need some way
to discover whether a given set of interfaces is available to a
restricted handle, in order to support the addition of new
functionality.

Notes:

- On many (all?) platforms libxencall and libxenforeignmemory are
  implemented by the same underlying privcmd driver. The platform
  level ioctl interface should support restricting the handle to only
  one or the other.
- On platforms with multiple privilege mapping ioctl variants should
  consider only allowing the newest/currently preferred one on a
  restricted handle. e.g. on Linux this would allow
  IOCTL_PRIVCMD_MMAPBATCH_V2 but not IOCTL_PRIVCMD_MMAPBATCH. (Of
  course any subsequently introduced _V3 would be subject to
  compatibility concerns)

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
---
v8: New

This applies on top of the Xen portion of "Begin to disentangle
libxenctrl and provide some stable libraries", v7, plus a couple of
minor fixes which will be in v8. All of this can be found in the
"vwip" branch of the tree referenced by that series at
git://xenbits.xen.org/people/ianc/libxenctrl-split/xen.git.

13 files changed:
tools/libs/call/core.c
tools/libs/call/include/xencall.h
tools/libs/call/libxencall.map
tools/libs/evtchn/core.c
tools/libs/evtchn/include/xenevtchn.h
tools/libs/evtchn/libxenevtchn.map
tools/libs/foreignmemory/core.c
tools/libs/foreignmemory/include/xenforeignmemory.h
tools/libs/foreignmemory/libxenforeignmemory.map
tools/libs/gnttab/gntshr_core.c
tools/libs/gnttab/gnttab_core.c
tools/libs/gnttab/include/xengnttab.h
tools/libs/gnttab/libxengnttab.map

index 5ca037237f0d571f13c1523a53cd85a715faa517..00abac6c91b7ef847ae6095d6a80fe07453a8692 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -72,6 +73,12 @@ int xencall_close(xencall_handle *xcall)
     return rc;
 }
 
+int xencall_restrict_target(xencall_handle *xcall, uint32_t domid)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 int xencall0(xencall_handle *xcall, unsigned int op)
 {
     privcmd_hypercall_t call = {
index bafacdd2baeefdca2c79a6e26c91966f44515c4b..db849ef176f879e87439c71bba0f1c2eb9effde3 100644 (file)
@@ -73,6 +73,40 @@ xencall_handle *xencall_open(struct xentoollog_logger *logger,
  */
 int xencall_close(xencall_handle *xcall);
 
+/*
+ * Attempt to restrict the given xcall handle to only be able to
+ * target the given domain.
+ *
+ * On success returns 0, after which only hypercalls which are on a
+ * platform specific whitelist can be called and the arguments will be
+ * audited by the platform to ensure that the target domain is
+ * domid.
+ *
+ * Subsequent attempts to call any hypercall not on the platform
+ * specific whitelist will return -1 setting errno to ENOSYS.
+ *
+ * Subsequent attempts to call any hypercall on the platform specific
+ * whitelist with any other target domain return -1 setting errno to
+ * EPERM.
+ *
+ * These restrictions will be implemented by the platform in a way
+ * which cannot be circumvented by a userspace process. Further
+ * privilege drops (such as using setuid(2) etc) may also be required
+ * to prevent a compromised process from simply opening a second
+ * handle
+ *
+ * XXX which hypercalls are restricted, per platform list, do we need
+ * a way to probe? Do we want to be able to restrict to particular
+ * subsets of whitelisted hypercalls?
+ *
+ * On failure returns -1 and sets errno:
+ *   ENOSYS: The platform is not able to support restricting the
+ *           target domain.
+ *   Other: The platform should be able to support restricting the
+ *          target domain, but was unable to do so.
+ */
+int xencall_restrict_target(xencall_handle *xcall, uint32_t domid);
+
 /*
  * Call hypercalls with varying numbers of arguments.
  *
index 2f96144f40dcdbe8fe130227ac225f3b3fcd050b..d39f88e0b7972172bf752f82476c2d7075abab88 100644 (file)
@@ -3,6 +3,8 @@ VERS_1.0 {
                xencall_open;
                xencall_close;
 
+               xencall_restrict_target;
+
                xencall0;
                xencall1;
                xencall2;
index c31e08ce3d81eb3239c4fcf4f03b01f63935c2de..5f68f52c65ed240ad2a1c5434a80a0d2ac660dc4 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <unistd.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -61,6 +62,12 @@ int xenevtchn_close(xenevtchn_handle *xce)
     return rc;
 }
 
+int xenevtchn_restrict_target(xenevtchn_handle *xce, uint32_t domid)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 /*
  * Local variables:
  * mode: C
index 93b80cb1199eae52454d260c34cf5da7ae5c7b64..82d1ba10d82683a5c984f9376757caa4ec8fa52c 100644 (file)
@@ -74,6 +74,42 @@ xenevtchn_handle *xenevtchn_open(struct xentoollog_logger *logger,
  */
 int xenevtchn_close(xenevtchn_handle *xce);
 
+/*
+ * Attempt to restrict the given evtchn handle to only operate on the
+ * given domain.
+ *
+ * On success returns 0, after which:
+ *
+ * - Any operations which take a peer domain as an argument can only
+ *   be called with the specified target domain. Subsequent attempts
+ *   to call any such interface with another domain will return -1
+ *   setting errno to EPERM.
+ *
+ * - Any operations which take an evtchn_port_t are not restricted
+ *   other than by the requirement to have previously bound that
+ *   evtchn to the handle. Therefore users of the restrict interface
+ *   should take care not to bind any event channels relating to other
+ *   domains prior to enforcing the restriction. The restrictions on
+ *   xenevtchn_bind_*() (which take a domain id, see previous point)
+ *   suffice to prevent any new such bindings being created.
+ *
+ * - xenevtchn_bind_virq is not permitted and will return -1 setting
+ *   errno to EPERM.
+ *
+ * These restrictions will be implemented by the platform in a way
+ * which cannot be circumvented by a userspace process. Further
+ * privilege drops (such as using setuid(2) etc) may also be required
+ * to prevent a compromised process from simply opening a second
+ * handle
+ *
+ * On failure returns -1 and sets errno:
+ *   ENOSYS: The platform is not able to support restricting the
+ *           target domain.
+ *   Other: The platform should be able to support restricting the
+ *          target domain, but was unable to do so.
+ */
+int xenevtchn_restrict_target(xenevtchn_handle *xce, uint32_t domid);
+
 /*
  * Return an fd that can be select()ed on.
  *
index 625a1e2b827fa523aa3a49ae2f70f9f8c002e4bd..08e9dd51e10e8534b78e9a36639b7ec12816b180 100644 (file)
@@ -3,6 +3,8 @@ VERS_1.0 {
                xenevtchn_open;
                xenevtchn_close;
 
+               xenevtchn_restrict_target;
+
                xenevtchn_fd;
 
                xenevtchn_bind_unbound_port;
index a872b9555d8f98aceda96ce307df7c5765778e70..657034b99d8e42be64d1a1b34f56b00da152cecf 100644 (file)
@@ -63,6 +63,13 @@ int xenforeignmemory_close(xenforeignmemory_handle *fmem)
     return rc;
 }
 
+int xenforeignmemory_restrict_target(xenforeignmemory_handle *fmem,
+                                     uint32_t domid)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 void *xenforeignmemory_map(xenforeignmemory_handle *fmem,
                            uint32_t dom, int prot,
                            size_t num,
index 92b9277b75ed23e633d7628323a0e3caad0e81b6..ad6463eae56ee0821e825c391d1d0e5c6fb0c41e 100644 (file)
@@ -73,6 +73,28 @@ xenforeignmemory_handle *xenforeignmemory_open(struct xentoollog_logger *logger,
  */
 int xenforeignmemory_close(xenforeignmemory_handle *fmem);
 
+/*
+ * Attempt to restrict the given handle to only target the given
+ * domain.
+ *
+ * On success returns 0, after which calls to xenforeignmemory_map
+ * which pass a domain other than the given domain will return -1
+ * setting errno to EPERM.
+ *
+ * This restriction will be implemented by the platform in a way which
+ * cannot be circumvented by a userspace process. Further privilege
+ * drops (such as using setuid(2) etc) may also be required to prevent
+ * a compromised process from simply opening a second handle
+ *
+ * On failure returns -1 and sets errno:
+ *   ENOSYS: The platform is not able to support restricting the
+ *           target domain.
+ *   Other: The platform should be able to support restricting the
+ *          target domain, but was unable to do so.
+ */
+int xenforeignmemory_restrict_target(xenforeignmemory_handle *fmem,
+                                     uint32_t domid);
+
 /*
  * Maps a range within one domain to a local address range.  Mappings
  * must be unmapped with xenforeignmemory_unmap and should follow the
index df206b3cfbcf63a1ac75709b09ee7dd53fc3acdc..dc1e0a1aff04043aa66b469c14494de4c3758aea 100644 (file)
@@ -2,6 +2,9 @@ VERS_1.0 {
        global:
                xenforeignmemory_open;
                xenforeignmemory_close;
+
+               xenforeignmemory_restrict_target;
+
                xenforeignmemory_map;
                xenforeignmemory_unmap;
        local: *; /* Do not expose anything by default */
index 7f6bf9de6a7d1275631ef8b8cc6e24c8ba22c83e..0347a165f1bbf0b3a571c3d6b25cf63ff08b6ac9 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -64,6 +65,13 @@ int xengntshr_close(xengntshr_handle *xgs)
     free(xgs);
     return rc;
 }
+
+int xengntshr_restrict_target(xengntshr_handle *xgs, uint32_t domid)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 void *xengntshr_share_pages(xengntshr_handle *xcg, uint32_t domid,
                             int count, uint32_t *refs, int writable)
 {
index 5d0474ddf9e0c295a8d8eb5223fff80444062b64..77ce167056bdf6389de25bb0acb8ee467edb0145 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <stdlib.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -65,6 +66,12 @@ int xengnttab_close(xengnttab_handle *xgt)
     return rc;
 }
 
+int xengnttab_restrict_target(xengnttab_handle *xgt, uint32_t domid)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 int xengnttab_set_max_grants(xengnttab_handle *xgt, uint32_t count)
 {
     return osdep_gnttab_set_max_grants(xgt, count);
index 0431dcf45dddc56902ad0eaf2b31f07323193846..0d3fedfc36ea23ebc22be58a26a14de4837b7568 100644 (file)
@@ -149,6 +149,33 @@ xengnttab_handle *xengnttab_open(struct xentoollog_logger *logger,
  */
 int xengnttab_close(xengnttab_handle *xgt);
 
+/*
+ * Attempt to restrict the given handle to only target the given
+ * domain.
+ *
+ * On success returns 0, after which:
+ *
+ * - Calls to xengnttab_map_*() which are passed a domain other than
+ *   the given domain (either as an argument or as any member of a
+ *   domid array argument, regardless of the validity of other members
+ *   of the array) will return -1 setting errno to EPERM.
+ *
+ * - Calls to xengnttab_set_max_grants() will return -1 having set
+ *   errno to EPERM.
+ *
+ * This restriction will be implemented by the platform in a way which
+ * cannot be circumvented by a userspace process. Further privilege
+ * drops (such as using setuid(2) etc) may also be required to prevent
+ * a compromised process from simply opening a second handle
+ *
+ * On failure returns -1 and sets errno:
+ *   ENOSYS: The platform is not able to support restricting the
+ *           target domain.
+ *   Other: The platform should be able to support restricting the
+ *          target domain, but was unable to do so.
+ */
+int xengnttab_restrict_target(xengnttab_handle *xgt, uint32_t domid);
+
 /**
  * Memory maps a grant reference from one domain to a local address range.
  * Mappings should be unmapped with xengnttab_unmap.  Logs errors.
@@ -306,6 +333,31 @@ xengntshr_handle *xengntshr_open(struct xentoollog_logger *logger,
  */
 int xengntshr_close(xengntshr_handle *xgs);
 
+/*
+ * Attempt to restrict the given handle to only target the given
+ * domain.
+ *
+ * On success returns 0, after which:
+ *
+ * - Calls to xengntshr_share_*() which are passed a domain other than
+ *   the given domain will return -1 setting errno to EPERM.
+ *
+ * - Calls to xengnttab_set_max_grants() will return -1 having set
+ *   errno to EPERM.
+ *
+ * This restriction will be implemented by the platform in a way which
+ * cannot be circumvented by a userspace process. Further privilege
+ * drops (such as using setuid(2) etc) may also be required to prevent
+ * a compromised process from simply opening a second handle
+ *
+ * On failure returns -1 and sets errno:
+ *   ENOSYS: The platform is not able to support restricting the
+ *           target domain.
+ *   Other: The platform should be able to support restricting the
+ *          target domain, but was unable to do so.
+ */
+int xengntshr_restrict_target(xengntshr_handle *xgs, uint32_t domid);
+
 /**
  * Allocates and shares pages with another domain.
  *
index dc737acc0c2f09759cdea48b5dcacf0a535544eb..8421723cd6c1cbc6d7b804c4f0471e6b4eb18128 100644 (file)
@@ -3,6 +3,8 @@ VERS_1.0 {
                xengnttab_open;
                xengnttab_close;
 
+               xengnttab_restrict_target;
+
                xengnttab_set_max_grants;
 
                xengnttab_map_domain_grant_refs;
@@ -15,6 +17,8 @@ VERS_1.0 {
                xengntshr_open;
                xengntshr_close;
 
+               xengntshr_restrict_target;
+
                xengntshr_share_page_notify;
                xengntshr_share_pages;