[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



Adding Ian J for his opinion.

I think this is a candidate for 4.2.0, although I would like to get rc2
under our belts first.

On Wed, 2012-08-08 at 04:44 +0100, Wangzhenguo wrote:
> > From: Ian Campbell [mailto:Ian.Campbell@xxxxxxxxxx]
> > 
> > I don't think we should expect it to be valid to keep an xc interface
> > handle open after a fork. The child should open a fresh handle if it
> > wants to keep interacting with xc.
> OK, I see xs, libxl and python open a fresh handle to interact with xc in 
> child process. 
> I modified the patch as follow:
> 
> # 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.

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>

> 
> Signed-off-by: Zhenguo Wang <wangzhenguo@xxxxxxxxxx>
> Signed-off-by: Xiaowei Yang <xiaowei.yang@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 11:33:38 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)
> 



_______________________________________________
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®.