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 10 of 24] libxc: infrastructure for hypercall safe da

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 10 of 24] libxc: infrastructure for hypercall safe data buffers
From: Ian Campbell <ian.campbell@xxxxxxxxxx>
Date: Mon, 06 Sep 2010 14:38:30 +0100
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
Delivery-date: Mon, 06 Sep 2010 06:53:26 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1283780300@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 1283779691 -3600
# Node ID bf7fb64762eb7decea9a6804460f0f966496ba07
# Parent  7b45202f78cd82d320fb32fea67c0a618697baec
libxc: infrastructure for hypercall safe data buffers.

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

diff -r 7b45202f78cd -r bf7fb64762eb tools/libxc/Makefile
--- a/tools/libxc/Makefile      Mon Sep 06 14:28:11 2010 +0100
+++ b/tools/libxc/Makefile      Mon Sep 06 14:28:11 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 7b45202f78cd -r bf7fb64762eb tools/libxc/xc_hcall_buf.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_hcall_buf.c        Mon Sep 06 14:28:11 2010 +0100
@@ -0,0 +1,147 @@
+/*
+ * 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"
+
+DECLARE_NAMED_HYPERCALL_BUFFER(HYPERCALL_BUFFER_NULL);
+
+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();
+
+    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 7b45202f78cd -r bf7fb64762eb tools/libxc/xc_private.h
--- a/tools/libxc/xc_private.h  Mon Sep 06 14:28:11 2010 +0100
+++ b/tools/libxc/xc_private.h  Mon Sep 06 14:28:11 2010 +0100
@@ -105,6 +105,62 @@ 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.
+ *
+ * See the definition DECLARE_NAMED_HYPERCALL_BUFFER for details of
+ * when it is acceptable to use this declaration rather than
+ * DECLARE_HYPERCALL_BOUNCE.
+ */
+#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 7b45202f78cd -r bf7fb64762eb tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Mon Sep 06 14:28:11 2010 +0100
+++ b/tools/libxc/xenctrl.h     Mon Sep 06 14:28:11 2010 +0100
@@ -147,6 +147,149 @@ 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 named hypercall buffer.
+ *
+ * Normally you should use DECLARE_HYPERCALL_BUFFER (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_BUFFER(_name)                  \
+    xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(_name) = { \
+        .hbuf = NULL,                                          \
+        .param_shadow = NULL,                                  \
+        HYPERCALL_BUFFER_INIT_NO_BOUNCE                        \
+    }
+
+/*
+ * 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;                       \
+    DECLARE_NAMED_HYPERCALL_BUFFER(_name)
+
+/*
+ * 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>