X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fxen%2Fprivcmd%2Fprivcmd.c;h=0f328eada70c5d92f310423d9c8e81f526962060;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=501aa5fe3e73a0f116f9d5d6dc127443aeba6728;hpb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;p=linux-2.6.git diff --git a/drivers/xen/privcmd/privcmd.c b/drivers/xen/privcmd/privcmd.c index 501aa5fe3..0f328eada 100644 --- a/drivers/xen/privcmd/privcmd.c +++ b/drivers/xen/privcmd/privcmd.c @@ -34,6 +34,10 @@ static struct proc_dir_entry *privcmd_intf; static struct proc_dir_entry *capabilities_intf; +#ifndef HAVE_ARCH_PRIVCMD_MMAP +static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); +#endif + static int privcmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { @@ -48,6 +52,8 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, return -EFAULT; #if defined(__i386__) + if (hypercall.op >= (PAGE_SIZE >> 5)) + break; __asm__ __volatile__ ( "pushl %%ebx; pushl %%ecx; pushl %%edx; " "pushl %%esi; pushl %%edi; " @@ -64,21 +70,21 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, "popl %%ecx; popl %%ebx" : "=a" (ret) : "0" (&hypercall) : "memory" ); #elif defined (__x86_64__) - { + if (hypercall.op < (PAGE_SIZE >> 5)) { long ign1, ign2, ign3; __asm__ __volatile__ ( "movq %8,%%r10; movq %9,%%r8;" - "shlq $5,%%rax ;" + "shll $5,%%eax ;" "addq $hypercall_page,%%rax ;" "call *%%rax" : "=a" (ret), "=D" (ign1), "=S" (ign2), "=d" (ign3) - : "0" ((unsigned long)hypercall.op), - "1" ((unsigned long)hypercall.arg[0]), - "2" ((unsigned long)hypercall.arg[1]), - "3" ((unsigned long)hypercall.arg[2]), - "g" ((unsigned long)hypercall.arg[3]), - "g" ((unsigned long)hypercall.arg[4]) + : "0" ((unsigned int)hypercall.op), + "1" (hypercall.arg[0]), + "2" (hypercall.arg[1]), + "3" (hypercall.arg[2]), + "g" (hypercall.arg[3]), + "g" (hypercall.arg[4]) : "r8", "r10", "memory" ); } #elif defined (__ia64__) @@ -121,12 +127,10 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, vma = find_vma(mm, msg.va); rc = -EINVAL; - if (!vma || (msg.va != vma->vm_start) || vma->vm_private_data) + if (!vma || (msg.va != vma->vm_start) || + !privcmd_enforce_singleshot_mapping(vma)) goto mmap_out; - /* Mapping is a one-shot operation per vma. */ - vma->vm_private_data = (void *)1; - va = vma->vm_start; for (i = 0; i < mmapcmd.num; i++) { @@ -136,7 +140,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, /* Do not allow range to wrap the address space. */ rc = -EINVAL; - if ((msg.npages > (INT_MAX >> PAGE_SHIFT)) || + if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) || ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va)) goto mmap_out; @@ -180,7 +184,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&m, udata, sizeof(m))) return -EFAULT; - if ((m.num <= 0) || (m.num > (INT_MAX >> PAGE_SHIFT))) + if ((m.num <= 0) || (m.num > (LONG_MAX >> PAGE_SHIFT))) return -EINVAL; down_read(&mm->mmap_sem); @@ -188,15 +192,13 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, vma = find_vma(mm, m.addr); if (!vma || (m.addr != vma->vm_start) || - ((m.addr + (m.num<vm_end) || - vma->vm_private_data) { + ((m.addr + ((unsigned long)m.num<vm_end) || + !privcmd_enforce_singleshot_mapping(vma)) { up_read(&mm->mmap_sem); return -EINVAL; } - /* Mapping is a one-shot operation per vma. */ - vma->vm_private_data = (void *)1; - p = m.arr; addr = m.addr; for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) { @@ -250,6 +252,11 @@ static int privcmd_mmap(struct file * file, struct vm_area_struct * vma) return 0; } + +static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) +{ + return (xchg(&vma->vm_private_data, (void *)1) == NULL); +} #endif static struct file_operations privcmd_file_ops = {