WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 01 of 25] libxc: infrastructure for hypercall safe da

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 01 of 25] libxc: infrastructure for hypercall safe data buffers
From: Ian Campbell <ian.campbell@xxxxxxxxxx>
Date: Fri, 22 Oct 2010 15:15:43 +0100
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
Delivery-date: Fri, 22 Oct 2010 07:27:37 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1287756942@xxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxx>
# Date 1287742257 -3600
# Node ID 38e25ffde90ec62f659f08996a828ef24f0ee8fb
# Parent  1f5676c9f1266d49a5fd1d8fdd84e60d7fe357a6
libxc: infrastructure for hypercall safe data buffers.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

diff -r 1f5676c9f126 -r 38e25ffde90e tools/libxc/Makefile
--- a/tools/libxc/Makefile      Fri Oct 22 10:27:31 2010 +0100
+++ b/tools/libxc/Makefile      Fri Oct 22 11:10:57 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 1f5676c9f126 -r 38e25ffde90e tools/libxc/xc_hcall_buf.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_hcall_buf.c        Fri Oct 22 11:10:57 2010 +0100
@@ -0,0 +1,160 @@
+/*
+ * 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 <inttypes.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 1f5676c9f126 -r 38e25ffde90e tools/libxc/xc_private.h
--- a/tools/libxc/xc_private.h  Fri Oct 22 10:27:31 2010 +0100
+++ b/tools/libxc/xc_private.h  Fri Oct 22 11:10:57 2010 +0100
@@ -105,6 +105,64 @@ void unlock_pages(xc_interface *xch, voi
 
 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);
 
diff -r 1f5676c9f126 -r 38e25ffde90e tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Fri Oct 22 10:27:31 2010 +0100
+++ b/tools/libxc/xenctrl.h     Fri Oct 22 11:10:57 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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>