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)
{
return -EFAULT;
#if defined(__i386__)
+ if (hypercall.op >= (PAGE_SIZE >> 5))
+ break;
__asm__ __volatile__ (
"pushl %%ebx; pushl %%ecx; pushl %%edx; "
"pushl %%esi; pushl %%edi; "
"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__)
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++) {
/* 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;
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);
vma = find_vma(mm, m.addr);
if (!vma ||
(m.addr != vma->vm_start) ||
- ((m.addr + (m.num<<PAGE_SHIFT)) != vma->vm_end) ||
- vma->vm_private_data) {
+ ((m.addr + ((unsigned long)m.num<<PAGE_SHIFT)) !=
+ vma->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++) {
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 = {