[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.