[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] The hypercall will fail and return EFAULT when the page becomes COW by forking process in linux



> From: Ian Campbell [mailto:Ian.Campbell@xxxxxxxxxx]
> 
> It would be good to write this in a comment next to each of the
> xc_{interface,evtchn,gnttab,gntshr}_open() prototypes in the header
> (assuming it applies to all of them, since they all make hypercalls I
> expect it does and in any case it is easy to relax this restriction in
> the future if not)
> 
> Otherwise:
> Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

I added a comment and your acked-by in patch 

The patch is

# HG changeset patch
# Parent a5dfd924fcdb173a154dad9f37073c1de1302065
libxc: Add VM_DONTCOPY flag of the VMA of the hypercall buffer, to avoid the 
hypercall buffer becoming COW on hypercall.

In multi-threads and multi-processes environment, e.g. the process has two 
threads, thread A 
may call hypercall, thread B may call fork() to create child process. After 
forking, all pages 
of the process including hypercall buffers are cow. The hypervisor calls 
copy_to_user in hypercall 
in thread A context, will cause a write protection and return EFAULT error.

Fix:
1. Before hypercall: use MADV_DONTFORK of madvise syscall to make the hypercall 
buffer 
   not to be copied to child process after fork. 
2. After hypercall: undo the effect of MADV_DONTFORK for the hypercall buffer 
by 
   using MADV_DOFORK of madvise syscall.
3. Use mmap/nunmap for memory alloc/free instead of malloc/free to bypass libc.

Note: 
Chlid process do not use xc interface handle which is opend by parent process, 
it should open 
a fresh handle if it wants to keep interacting with xc. Otherwise, it may cause 
segment fault 
to access hypercall buffer cache in the handle.

Signed-off-by: Zhenguo Wang <wangzhenguo@xxxxxxxxxx>
Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxxx>
Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

diff -r a5dfd924fcdb tools/libxc/xc_linux_osdep.c
--- a/tools/libxc/xc_linux_osdep.c      Tue Aug 07 13:52:10 2012 +0800
+++ b/tools/libxc/xc_linux_osdep.c      Wed Aug 08 19:31:53 2012 +0800
@@ -93,22 +93,20 @@ static void *linux_privcmd_alloc_hyperca
     size_t size = npages * XC_PAGE_SIZE;
     void *p;
 
-    p = xc_memalign(xch, XC_PAGE_SIZE, size);
-    if (!p)
-        return NULL;
+    /* Address returned by mmap is page aligned. */
+    p = mmap(NULL, size, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, -1, 0);
 
-    if ( mlock(p, size) < 0 )
-    {
-        free(p);
-        return NULL;
-    }
+    /* Do not copy the VMA to child process on fork. Avoid the page being COW 
on hypercall. */
+    madvise(ptr, npages * XC_PAGE_SIZE, MADV_DONTFORK);
     return p;
 }
 
 static void linux_privcmd_free_hypercall_buffer(xc_interface *xch, 
xc_osdep_handle h, void *ptr, int npages)
 {
-    munlock(ptr, npages * XC_PAGE_SIZE);
-    free(ptr);
+    /* Recover the VMA flags. Maybe it's not necessary */
+    madvise(ptr, npages * XC_PAGE_SIZE, MADV_DOFORK);
+    
+    munmap(ptr, npages * XC_PAGE_SIZE);
 }
 
 static int linux_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, 
privcmd_hypercall_t *hypercall)
diff -r a5dfd924fcdb tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Tue Aug 07 13:52:10 2012 +0800
+++ b/tools/libxc/xenctrl.h     Wed Aug 08 19:31:53 2012 +0800
@@ -131,8 +131,11 @@ typedef enum xc_error_code xc_error_code
 
 /**
  * This function opens a handle to the hypervisor interface.  This function can
- * be called multiple times within a single process.  Multiple processes can
- * have an open hypervisor interface at the same time.
+ * be called multiple times within a single process.  Multiple processes can 
not
+ * have an open hypervisor interface at the same time. Chlid process do not 
+ * use xc interface handle which is opend by parent process, it should open
+ * a fresh handle if it wants to keep interacting with xc. Otherwise, it may 
+ * cause segment fault to access hypercall buffer cache in the handle.
  *
  * Each call to this function should have a corresponding call to
  * xc_interface_close().
@@ -908,6 +911,11 @@ int xc_evtchn_status(xc_interface *xch, 
  * Return a handle to the event channel driver, or -1 on failure, in which case
  * errno will be set appropriately.
  *
+ * Note:
+ * Chlid process do not use xc evtchn handle which is opend by parent process, 
+ * it should open a fresh handle if it wants to keep interacting with xc. 
Otherwise, 
+ * it may cause segment fault to access hypercall buffer cache in the handle.
+ *
  * Before Xen pre-4.1 this function would sometimes report errors with perror.
  */
 xc_evtchn *xc_evtchn_open(xentoollog_logger *logger,
@@ -1339,9 +1347,12 @@ int xc_domain_subscribe_for_suspend(
 
 /*
  * These functions sometimes log messages as above, but not always.
- */
-
-/*
+ *
+ * Note:
+ * Chlid process do not use xc gnttab handle which is opend by parent process, 
+ * it should open a fresh handle if it wants to keep interacting with xc. 
Otherwise, 
+ * it may cause segment fault to access hypercall buffer cache in the handle.
+ *
  * Return an fd onto the grant table driver.  Logs errors.
  */
 xc_gnttab *xc_gnttab_open(xentoollog_logger *logger,
@@ -1458,6 +1469,12 @@ grant_entry_v2_t *xc_gnttab_map_table_v2
 
 /*
  * Return an fd onto the grant sharing driver.  Logs errors.
+ *
+ * Note:
+ * Chlid process do not use xc gntshr handle which is opend by parent process, 
+ * it should open a fresh handle if it wants to keep interacting with xc. 
Otherwise, 
+ * it may cause segment fault to access hypercall buffer cache in the handle.
+ *
  */
 xc_gntshr *xc_gntshr_open(xentoollog_logger *logger,
                          unsigned open_flags);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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