]> xenbits.xensource.com Git - people/royger/linux-2.6.18-xen.git/commitdiff
xen/privcmd: fix for proper operation in compat mode
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 6 Jan 2010 08:38:09 +0000 (08:38 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 6 Jan 2010 08:38:09 +0000 (08:38 +0000)
- sizeof(struct privcmd_mmapbatch_32) was wrong
- MFN array must be translated for IOCTL_PRIVCMD_MMAPBATCH

Also, the error indicator of IOCTL_PRIVCMD_MMAPBATCH should be in the
top nibble (it is documented that way in include/xen/public/privcmd.h
and include/xen/compat_ioctl.h), but since that is an incompatible
change it is not being done here (instead, a new ioctl with proper
behavior will need to be added).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
drivers/xen/privcmd/compat_privcmd.c
include/xen/compat_ioctl.h

index ba6bf84e8eb0ac9159fa92cc4fef2889be763f70..c6e9df4eb16eb4d8bd3ca24a683a7f4ea0953812 100644 (file)
@@ -52,17 +52,49 @@ int privcmd_ioctl_32(int fd, unsigned int cmd, unsigned long arg)
                struct privcmd_mmapbatch *p;
                struct privcmd_mmapbatch_32 *p32;
                struct privcmd_mmapbatch_32 n32;
+#ifdef xen_pfn32_t
+               xen_pfn_t *__user arr;
+               xen_pfn32_t *__user arr32;
+               unsigned int i;
+#endif
 
                p32 = compat_ptr(arg);
                p = compat_alloc_user_space(sizeof(*p));
                if (copy_from_user(&n32, p32, sizeof(n32)) ||
                    put_user(n32.num, &p->num) ||
                    put_user(n32.dom, &p->dom) ||
-                   put_user(n32.addr, &p->addr) ||
-                   put_user(compat_ptr(n32.arr), &p->arr))
+                   put_user(n32.addr, &p->addr))
                        return -EFAULT;
+#ifdef xen_pfn32_t
+               arr = compat_alloc_user_space(n32.num * sizeof(*arr)
+                                             + sizeof(*p));
+               arr32 = compat_ptr(n32.arr);
+               for (i = 0; i < n32.num; ++i) {
+                       xen_pfn32_t mfn;
+
+                       if (get_user(mfn, arr32 + i) || put_user(mfn, arr + i))
+                               return -EFAULT;
+               }
+
+               if (put_user(arr, &p->arr))
+                       return -EFAULT;
+#else
+               if (put_user(compat_ptr(n32.arr), &p->arr))
+                       return -EFAULT;
+#endif
                
                ret = sys_ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, (unsigned long)p);
+
+#ifdef xen_pfn32_t
+               for (i = 0; !ret && i < n32.num; ++i) {
+                       xen_pfn_t mfn;
+
+                       if (get_user(mfn, arr + i) || put_user(mfn, arr32 + i))
+                               ret = -EFAULT;
+                       else if (mfn != (xen_pfn32_t)mfn)
+                               ret = -ERANGE;
+               }
+#endif
        }
                break;
        default:
index 0393ebf15f19ae8eb76eb5532dc3de41174ca736..16f6d93cc13192d82657bbf8842479308c878166 100644 (file)
 #define __LINUX_XEN_COMPAT_H__ 
 
 #include <linux/compat.h>
+#include <linux/compiler.h>
+
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+#define xen_pfn32_t __u32
+#endif
 
 extern int privcmd_ioctl_32(int fd, unsigned int cmd, unsigned long arg);
 struct privcmd_mmap_32 {
@@ -34,7 +39,14 @@ struct privcmd_mmap_32 {
 struct privcmd_mmapbatch_32 {
        int num;     /* number of pages to populate */
        domid_t dom; /* target domain */
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+       union {      /* virtual address */
+               __u64 addr __packed;
+               __u32 va; /* ensures union is 4-byte aligned */
+       };
+#else
        __u64 addr;  /* virtual address */
+#endif
        compat_uptr_t arr; /* array of mfns - top nibble set on err */
 };
 #define IOCTL_PRIVCMD_MMAP_32                   \