[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 1/8] public / x86: Introduce __HYPERCALL_dm_op...
On Tue, Jan 17, 2017 at 05:29:49PM +0000, Paul Durrant wrote: > ...as a set of hypercalls to be used by a device model. > > As stated in the new docs/designs/dm_op.markdown: > > "The aim of DMOP is to prevent a compromised device model from > compromising domains other then the one it is associated with. (And is > therefore likely already compromised)." > > See that file for further information. > > This patch simply adds the boilerplate for the hypercall. > > Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> > Suggested-by: Ian Jackson <ian.jackson@xxxxxxxxxx> > Suggested-by: Jennifer Herbert <jennifer.herbert@xxxxxxxxxx> > --- > Cc: Ian Jackson <ian.jackson@xxxxxxxxxx> > Cc: Jennifer Herbert <jennifer.herbert@xxxxxxxxxx> > Cc: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> > Cc: Wei Liu <wei.liu2@xxxxxxxxxx> > Cc: Jan Beulich <jbeulich@xxxxxxxx> > Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > > v4: > - Change XEN_GUEST_HANDLE_64 to XEN_GUEST_HANDLE in struct xen_dm_op_buf > and add the necessary compat code. Drop Jan's R-b since the patch has > been fundamentally modified. > > v3: > - Re-written large portions of dmop.markdown to remove references to > previous proposals and make it a standalone design doc. > > v2: > - Addressed several comments from Jan. > - Removed modification of __XEN_LATEST_INTERFACE_VERSION__ as it is not > needed in this patch. > --- > docs/designs/dmop.markdown | 165 > ++++++++++++++++++++++++++++++++++++++ > tools/flask/policy/modules/xen.if | 2 +- > tools/libxc/include/xenctrl.h | 1 + > tools/libxc/xc_private.c | 70 ++++++++++++++++ > tools/libxc/xc_private.h | 2 + > xen/arch/x86/hvm/Makefile | 1 + > xen/arch/x86/hvm/dm.c | 149 ++++++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/hvm.c | 1 + > xen/arch/x86/hypercall.c | 2 + > xen/include/Makefile | 1 + > xen/include/public/hvm/dm_op.h | 71 ++++++++++++++++ > xen/include/public/xen.h | 1 + > xen/include/xen/hypercall.h | 15 ++++ > xen/include/xlat.lst | 1 + > xen/include/xsm/dummy.h | 6 ++ > xen/include/xsm/xsm.h | 6 ++ > xen/xsm/flask/hooks.c | 7 ++ > 17 files changed, 500 insertions(+), 1 deletion(-) > create mode 100644 docs/designs/dmop.markdown > create mode 100644 xen/arch/x86/hvm/dm.c > create mode 100644 xen/include/public/hvm/dm_op.h > > diff --git a/docs/designs/dmop.markdown b/docs/designs/dmop.markdown > new file mode 100644 > index 0000000..9f2f0d4 > --- /dev/null > +++ b/docs/designs/dmop.markdown > @@ -0,0 +1,165 @@ > +DMOP > +==== > + > +Introduction > +------------ > + > +The aim of DMOP is to prevent a compromised device model from compromising > +domains other then the one it is associated with. (And is therefore likely > +already compromised). > + > +The problem occurs when you a device model issues an hypercall that > +includes references to user memory other than the operation structure > +itself, such as with Track dirty VRAM (as used in VGA emulation). > +Is this case, the address of this other user memory needs to be vetted, > +to ensure it is not within restricted address ranges, such as kernel > +memory. The real problem comes down to how you would vet this address - > +the idea place to do this is within the privcmd driver, without privcmd > +having to have specific knowledge of the hypercall's semantics. > + > +The Design > +---------- > + > +The privcmd driver implements a new restriction ioctl, which takes a domid > +parameter. After that restriction ioctl is issued, the privcmd driver will > +permit only DMOP hypercalls, and only with the specified target domid. > + > +A DMOP hypercall consists of an array of buffers and lengths, with the > +first one containing the specific DMOP parameters. These can then reference > +further buffers from within in the array. Since the only user buffers > +passed are that found with that array, they can all can be audited by > +privcmd. > + > +The following code illustrates this idea: > + > +struct xen_dm_op { > + uint32_t op; > +}; > + > +struct xen_dm_op_buf { > + XEN_GUEST_HANDLE(void) h; > + unsigned long size; > +}; > +typedef struct xen_dm_op_buf xen_dm_op_buf_t; > + > +enum neg_errnoval > +HYPERVISOR_dm_op(domid_t domid, > + xen_dm_op_buf_t bufs[], > + unsigned int nr_bufs) > + > +@domid is the domain the hypercall operates on. > +@bufs points to an array of buffers where @bufs[0] contains a struct > +dm_op, describing the specific device model operation and its parameters. > +@bufs[1..] may be referenced in the parameters for the purposes of > +passing extra information to or from the domain. > +@nr_bufs is the number of buffers in the @bufs array. > + > +It is forbidden for the above struct (xen_dm_op) to contain any guest > +handles. If they are needed, they should instead be in > +HYPERVISOR_dm_op->bufs. > + > +Validation by privcmd driver > +---------------------------- > + > +If the privcmd driver has been restricted to specific domain (using a > + new ioctl), when it received an op, it will: > + > +1. Check hypercall is DMOP. > + > +2. Check domid == restricted domid. > + > +3. For each @nr_bufs in @bufs: Check @h and @size give a buffer > + wholly in the user space part of the virtual address space. (e.g. > + Linux will use access_ok()). > + > + > +Xen Implementation > +------------------ > + > +Since a DMOP buffers need to be copied from or to the guest, functions for > +doing this would be written as below. Note that care is taken to prevent > +damage from buffer under- or over-run situations. If the DMOP is called > +with incorrectly sized buffers, zeros will be read, while extra is ignored. > + > +static bool copy_buf_from_guest(xen_dm_op_buf_t bufs[], > + unsigned int nr_bufs, void *dst, > + unsigned int idx, size_t dst_size) > +{ > + size_t size = min_t(size_t, dst_size, bufs[idx].size); > + > + return !copy_from_guest(dst, bufs[idx].h, size); > +} > + > +static bool copy_buf_to_guest(xen_dm_op_buf_t bufs[], > + unsigned int nr_bufs, unsigned int idx, > + void *src, size_t src_size) > +{ > + size_t size = min_t(size_t, bufs[idx].size, src_size); > + > + return !copy_to_guest(bufs[idx].h, src, size); > +} > + > +This leaves do_dm_op easy to implement as below: > + > +static int dm_op(domid_t domid, > + unsigned int nr_bufs, > + xen_dm_op_buf_t bufs[]) > +{ > + struct domain *d; > + struct xen_dm_op op; > + long rc; > + > + rc = rcu_lock_remote_domain_by_id(domid, &d); > + if ( rc ) > + return rc; > + > + if ( !has_hvm_container_domain(d) ) > + goto out; > + > + rc = xsm_dm_op(XSM_DM_PRIV, d); > + if ( rc ) > + goto out; > + > + if ( !copy_buf_from_guest(bufs, nr_bufs, &op, 0, sizeof(op)) ) > + { > + rc = -EFAULT; > + goto out; > + } > + > + switch ( op.op ) > + { > + default: > + rc = -EOPNOTSUPP; > + break; > + } > + > + if ( !rc && > + !copy_buf_to_guest(bufs, nr_bufs, 0, &op, sizeof(op)) ) > + rc = -EFAULT; > + > + out: > + rcu_unlock_domain(d); > + > + return rc; > +} > + > +long do_dm_op(domid_t domid, > + unsigned int nr_bufs, > + XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs) > +{ > + struct xen_dm_op_buf *nat; > + int rc; > + > + nat = xzalloc_array(struct xen_dm_op_buf, nr_bufs); > + if ( !nat ) > + return -ENOMEM; > + > + if ( !copy_from_guest_offset(nat, bufs, 0, nr_bufs) ) > + return -EFAULT; > + > + rc = dm_op(domid, nr_bufs, nat); > + > + xfree(nat); > + > + return rc; > +} > diff --git a/tools/flask/policy/modules/xen.if > b/tools/flask/policy/modules/xen.if > index 1aca75d..f9254c2 100644 > --- a/tools/flask/policy/modules/xen.if > +++ b/tools/flask/policy/modules/xen.if > @@ -151,7 +151,7 @@ define(`device_model', ` > > allow $1 $2_target:domain { getdomaininfo shutdown }; > allow $1 $2_target:mmu { map_read map_write adjust physmap target_hack > }; > - allow $1 $2_target:hvm { getparam setparam trackdirtyvram hvmctl > irqlevel pciroute pcilevel cacheattr send_irq }; > + allow $1 $2_target:hvm { getparam setparam trackdirtyvram hvmctl > irqlevel pciroute pcilevel cacheattr send_irq dm }; > ') > > # make_device_model(priv, dm_dom, hvm_dom) > diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h > index 4ab0f57..2ba46d7 100644 > --- a/tools/libxc/include/xenctrl.h > +++ b/tools/libxc/include/xenctrl.h > @@ -41,6 +41,7 @@ > #include <xen/sched.h> > #include <xen/memory.h> > #include <xen/grant_table.h> > +#include <xen/hvm/dm_op.h> > #include <xen/hvm/params.h> > #include <xen/xsm/flask_op.h> > #include <xen/tmem.h> > diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c > index d57c39a..8e49635 100644 > --- a/tools/libxc/xc_private.c > +++ b/tools/libxc/xc_private.c > @@ -776,6 +776,76 @@ int xc_ffs64(uint64_t x) > return l ? xc_ffs32(l) : h ? xc_ffs32(h) + 32 : 0; > } > > +int do_dm_op(xc_interface *xch, domid_t domid, unsigned int nr_bufs, ...) > +{ > + int ret = -1; > + struct { > + void *u; > + void *h; > + } *bounce; > + DECLARE_HYPERCALL_BUFFER(xen_dm_op_buf_t, bufs); > + va_list args; > + unsigned int idx; > + > + bounce = calloc(nr_bufs, sizeof(*bounce)); > + if ( bounce == NULL ) > + goto fail1; > + > + bufs = xc_hypercall_buffer_alloc(xch, bufs, sizeof(*bufs) * nr_bufs); > + if ( bufs == NULL ) > + goto fail2; > + > + va_start(args, nr_bufs); > + for (idx = 0; idx < nr_bufs; idx++) Coding style. > + > +int compat_dm_op(domid_t domid, > + unsigned int nr_bufs, > + COMPAT_HANDLE_PARAM(compat_dm_op_buf_t) bufs) > +{ > + struct xen_dm_op_buf *nat; > + unsigned int i; > + int rc = -EFAULT; > + > + nat = xzalloc_array(struct xen_dm_op_buf, nr_bufs); > + if ( !nat ) > + return -ENOMEM; > + > + for ( i = 0; i < nr_bufs; i++ ) > + { > + struct compat_dm_op_buf cmp; > + > + if ( copy_from_compat_offset(&cmp, bufs, i, 1) ) > + goto out; > + > +#define XLAT_dm_op_buf_HNDL_h(_d_, _s_) \ > + guest_from_compat_handle((_d_)->h, (_s_)->h) > + > + XLAT_dm_op_buf(&nat[i], &cmp); > + > +#undef XLAT_dm_op_buf_HNDL_h > + } > + > + rc = dm_op(domid, nr_bufs, nat); > + Need to copy back to the original places with copy_to_compat? Wei. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |