[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] libxc: infrastructure for hypercall safe data buffers.
# HG changeset patch # User Ian Campbell <ian.campbell@xxxxxxxxxx> # Date 1288091497 -3600 # Node ID 6f904c99db56b341a285134c6d00f0b21ce86e9c # Parent 4f9922cff3ab488b4958fb67094eec3706a217ea libxc: infrastructure for hypercall safe data buffers. (Modified version of this patch, with updated #includes in xc_hcall_buf.c to fix stubdomain build.) Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> --- tools/libxc/Makefile | 1 tools/libxc/xc_hcall_buf.c | 162 +++++++++++++++++++++++++++++++++++++++++++++ tools/libxc/xc_private.c | 2 tools/libxc/xc_private.h | 58 ++++++++++++++++ tools/libxc/xenctrl.h | 131 ++++++++++++++++++++++++++++++++++++ 5 files changed, 352 insertions(+), 2 deletions(-) diff -r 4f9922cff3ab -r 6f904c99db56 tools/libxc/Makefile --- a/tools/libxc/Makefile Tue Oct 26 12:08:10 2010 +0100 +++ b/tools/libxc/Makefile Tue Oct 26 12:11:37 2010 +0100 @@ -27,6 +27,7 @@ CTRL_SRCS-y += xc_mem_event.c CTRL_SRCS-y += xc_mem_event.c CTRL_SRCS-y += xc_mem_paging.c CTRL_SRCS-y += xc_memshr.c +CTRL_SRCS-y += xc_hcall_buf.c CTRL_SRCS-y += xtl_core.c CTRL_SRCS-y += xtl_logger_stdio.c CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c diff -r 4f9922cff3ab -r 6f904c99db56 tools/libxc/xc_hcall_buf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_hcall_buf.c Tue Oct 26 12:11:37 2010 +0100 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2010, Citrix Systems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdlib.h> +#include <malloc.h> + +#include "xc_private.h" +#include "xg_private.h" + +xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL) = { + .hbuf = NULL, + .param_shadow = NULL, + HYPERCALL_BUFFER_INIT_NO_BOUNCE +}; + +void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages) +{ + size_t size = nr_pages * PAGE_SIZE; + void *p; +#if defined(_POSIX_C_SOURCE) && !defined(__sun__) + int ret; + ret = posix_memalign(&p, PAGE_SIZE, size); + if (ret != 0) + return NULL; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + p = valloc(size); +#else + p = memalign(PAGE_SIZE, size); +#endif + + if (!p) + return NULL; + +#ifndef __sun__ + if ( mlock(p, size) < 0 ) + { + free(p); + return NULL; + } +#endif + + b->hbuf = p; + + memset(p, 0, size); + return b->hbuf; +} + +void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages) +{ + if ( b->hbuf == NULL ) + return; + +#ifndef __sun__ + (void) munlock(b->hbuf, nr_pages * PAGE_SIZE); +#endif + + free(b->hbuf); +} + +struct allocation_header { + int nr_pages; +}; + +void *xc__hypercall_buffer_alloc(xc_interface *xch, xc_hypercall_buffer_t *b, size_t size) +{ + size_t actual_size = ROUNDUP(size + sizeof(struct allocation_header), PAGE_SHIFT); + int nr_pages = actual_size >> PAGE_SHIFT; + struct allocation_header *hdr; + + hdr = xc__hypercall_buffer_alloc_pages(xch, b, nr_pages); + if ( hdr == NULL ) + return NULL; + + b->hbuf = (void *)(hdr+1); + + hdr->nr_pages = nr_pages; + return b->hbuf; +} + +void xc__hypercall_buffer_free(xc_interface *xch, xc_hypercall_buffer_t *b) +{ + struct allocation_header *hdr; + + if (b->hbuf == NULL) + return; + + hdr = b->hbuf; + b->hbuf = --hdr; + + xc__hypercall_buffer_free_pages(xch, b, hdr->nr_pages); +} + +int xc__hypercall_bounce_pre(xc_interface *xch, xc_hypercall_buffer_t *b) +{ + void *p; + + /* + * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE. + */ + if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE ) + abort(); + + /* + * Do need to bounce a NULL buffer. + */ + if ( b->ubuf == NULL ) + { + b->hbuf = NULL; + return 0; + } + + p = xc__hypercall_buffer_alloc(xch, b, b->sz); + if ( p == NULL ) + return -1; + + if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_IN || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH ) + memcpy(b->hbuf, b->ubuf, b->sz); + + return 0; +} + +void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *b) +{ + /* + * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE. + */ + if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE ) + abort(); + + if ( b->hbuf == NULL ) + return; + + if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_OUT || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH ) + memcpy(b->ubuf, b->hbuf, b->sz); + + xc__hypercall_buffer_free(xch, b); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 4f9922cff3ab -r 6f904c99db56 tools/libxc/xc_private.c --- a/tools/libxc/xc_private.c Tue Oct 26 12:08:10 2010 +0100 +++ b/tools/libxc/xc_private.c Tue Oct 26 12:11:37 2010 +0100 @@ -18,13 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <inttypes.h> #include "xc_private.h" #include "xg_private.h" #include "xc_dom.h" #include <stdarg.h> #include <stdlib.h> -#include <malloc.h> #include <unistd.h> #include <pthread.h> #include <assert.h> diff -r 4f9922cff3ab -r 6f904c99db56 tools/libxc/xc_private.h --- a/tools/libxc/xc_private.h Tue Oct 26 12:08:10 2010 +0100 +++ b/tools/libxc/xc_private.h Tue Oct 26 12:11:37 2010 +0100 @@ -106,6 +106,64 @@ int hcall_buf_prep(xc_interface *xch, vo int hcall_buf_prep(xc_interface *xch, void **addr, size_t len); void hcall_buf_release(xc_interface *xch, void **addr, size_t len); +/* + * HYPERCALL ARGUMENT BUFFERS + * + * Augment the public hypercall buffer interface with the ability to + * bounce between user provided buffers and hypercall safe memory. + * + * Use xc_hypercall_bounce_pre/post instead of + * xc_hypercall_buffer_alloc/free(_pages). The specified user + * supplied buffer is automatically copied in/out of the hypercall + * safe memory. + */ +enum { + XC_HYPERCALL_BUFFER_BOUNCE_NONE = 0, + XC_HYPERCALL_BUFFER_BOUNCE_IN = 1, + XC_HYPERCALL_BUFFER_BOUNCE_OUT = 2, + XC_HYPERCALL_BUFFER_BOUNCE_BOTH = 3 +}; + +/* + * Declare a named bounce buffer. + * + * Normally you should use DECLARE_HYPERCALL_BOUNCE (see below). + * + * This declaration should only be used when the user pointer is + * non-trivial, e.g. when it is contained within an existing data + * structure. + */ +#define DECLARE_NAMED_HYPERCALL_BOUNCE(_name, _ubuf, _sz, _dir) \ + xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(_name) = { \ + .hbuf = NULL, \ + .param_shadow = NULL, \ + .sz = _sz, .dir = _dir, .ubuf = _ubuf, \ + } + +/* + * Declare a bounce buffer shadowing the named user data pointer. + */ +#define DECLARE_HYPERCALL_BOUNCE(_ubuf, _sz, _dir) DECLARE_NAMED_HYPERCALL_BOUNCE(_ubuf, _ubuf, _sz, _dir) + +/* + * Set the size of data to bounce. Useful when the size is not known + * when the bounce buffer is declared. + */ +#define HYPERCALL_BOUNCE_SET_SIZE(_buf, _sz) do { (HYPERCALL_BUFFER(_buf))->sz = _sz; } while (0) + +/* + * Initialise and free hypercall safe memory. Takes care of any required + * copying. + */ +int xc__hypercall_bounce_pre(xc_interface *xch, xc_hypercall_buffer_t *bounce); +#define xc_hypercall_bounce_pre(_xch, _name) xc__hypercall_bounce_pre(_xch, HYPERCALL_BUFFER(_name)) +void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *bounce); +#define xc_hypercall_bounce_post(_xch, _name) xc__hypercall_bounce_post(_xch, HYPERCALL_BUFFER(_name)) + +/* + * Hypercall interfaces. + */ + int do_xen_hypercall(xc_interface *xch, privcmd_hypercall_t *hypercall); static inline int do_xen_version(xc_interface *xch, int cmd, void *dest) diff -r 4f9922cff3ab -r 6f904c99db56 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Tue Oct 26 12:08:10 2010 +0100 +++ b/tools/libxc/xenctrl.h Tue Oct 26 12:11:37 2010 +0100 @@ -147,6 +147,137 @@ enum xc_open_flags { * @return 0 on success, -1 otherwise. */ int xc_interface_close(xc_interface *xch); + +/* + * HYPERCALL SAFE MEMORY BUFFER + * + * Ensure that memory which is passed to a hypercall has been + * specially allocated in order to be safe to access from the + * hypervisor. + * + * Each user data pointer is shadowed by an xc_hypercall_buffer data + * structure. You should never define an xc_hypercall_buffer type + * directly, instead use the DECLARE_HYPERCALL_BUFFER* macros below. + * + * The strucuture should be considered opaque and all access should be + * via the macros and helper functions defined below. + * + * Once the buffer is declared the user is responsible for explicitly + * allocating and releasing the memory using + * xc_hypercall_buffer_alloc(_pages) and + * xc_hypercall_buffer_free(_pages). + * + * Once the buffer has been allocated the user can initialise the data + * via the normal pointer. The xc_hypercall_buffer structure is + * transparently referenced by the helper macros (such as + * xen_set_guest_handle) in order to check at compile time that the + * correct type of memory is being used. + */ +struct xc_hypercall_buffer { + /* Hypercall safe memory buffer. */ + void *hbuf; + + /* + * Reference to xc_hypercall_buffer passed as argument to the + * current function. + */ + struct xc_hypercall_buffer *param_shadow; + + /* + * Direction of copy for bounce buffering. + */ + int dir; + + /* Used iff dir != 0. */ + void *ubuf; + size_t sz; +}; +typedef struct xc_hypercall_buffer xc_hypercall_buffer_t; + +/* + * Construct the name of the hypercall buffer for a given variable. + * For internal use only + */ +#define XC__HYPERCALL_BUFFER_NAME(_name) xc__hypercall_buffer_##_name + +/* + * Returns the hypercall_buffer associated with a variable. + */ +#define HYPERCALL_BUFFER(_name) \ + ({ xc_hypercall_buffer_t _val1; \ + typeof(XC__HYPERCALL_BUFFER_NAME(_name)) *_val2 = &XC__HYPERCALL_BUFFER_NAME(_name); \ + (void)(&_val1 == _val2); \ + (_val2)->param_shadow ? (_val2)->param_shadow : (_val2); \ + }) + +#define HYPERCALL_BUFFER_INIT_NO_BOUNCE .dir = 0, .sz = 0, .ubuf = (void *)-1 + +/* + * Defines a hypercall buffer and user pointer with _name of _type. + * + * The user accesses the data as normal via _name which will be + * transparently converted to the hypercall buffer as necessary. + */ +#define DECLARE_HYPERCALL_BUFFER(_type, _name) \ + _type *_name = NULL; \ + xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(_name) = { \ + .hbuf = NULL, \ + .param_shadow = NULL, \ + HYPERCALL_BUFFER_INIT_NO_BOUNCE \ + } + +/* + * Declare the necessary data structure to allow a hypercall buffer + * passed as an argument to a function to be used in the normal way. + */ +#define DECLARE_HYPERCALL_BUFFER_ARGUMENT(_name) \ + xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(_name) = { \ + .hbuf = (void *)-1, \ + .param_shadow = _name, \ + HYPERCALL_BUFFER_INIT_NO_BOUNCE \ + } + +/* + * Get the hypercall buffer data pointer in a form suitable for use + * directly as a hypercall argument. + */ +#define HYPERCALL_BUFFER_AS_ARG(_name) \ + ({ xc_hypercall_buffer_t _val1; \ + typeof(XC__HYPERCALL_BUFFER_NAME(_name)) *_val2 = HYPERCALL_BUFFER(_name); \ + (void)(&_val1 == _val2); \ + (unsigned long)(_val2)->hbuf; \ + }) + +/* + * Set a xen_guest_handle in a type safe manner, ensuring that the + * data pointer has been correctly allocated. + */ +#define xc_set_xen_guest_handle(_hnd, _val) \ + do { \ + xc_hypercall_buffer_t _val1; \ + typeof(XC__HYPERCALL_BUFFER_NAME(_val)) *_val2 = HYPERCALL_BUFFER(_val); \ + (void) (&_val1 == _val2); \ + set_xen_guest_handle_raw(_hnd, (_val2)->hbuf); \ + } while (0) + +/* Use with xc_set_xen_guest_handle in place of NULL */ +extern xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL); + +/* + * Allocate and free hypercall buffers with byte granularity. + */ +void *xc__hypercall_buffer_alloc(xc_interface *xch, xc_hypercall_buffer_t *b, size_t size); +#define xc_hypercall_buffer_alloc(_xch, _name, _size) xc__hypercall_buffer_alloc(_xch, HYPERCALL_BUFFER(_name), _size) +void xc__hypercall_buffer_free(xc_interface *xch, xc_hypercall_buffer_t *b); +#define xc_hypercall_buffer_free(_xch, _name) xc__hypercall_buffer_free(_xch, HYPERCALL_BUFFER(_name)) + +/* + * Allocate and free hypercall buffers with page alignment. + */ +void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages); +#define xc_hypercall_buffer_alloc_pages(_xch, _name, _nr) xc__hypercall_buffer_alloc_pages(_xch, HYPERCALL_BUFFER(_name), _nr) +void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages); +#define xc_hypercall_buffer_free_pages(_xch, _name, _nr) xc__hypercall_buffer_free_pages(_xch, HYPERCALL_BUFFER(_name), _nr) /* * DOMAIN DEBUGGING FUNCTIONS _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |