Jan Beulich
2010-Jan-05 12:52 UTC
[Xen-devel] [PATCH] linux/privcmd: fix for proper operation in compat mode
- 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). As usual, written against 2.6.32.2 and made apply to the 2.6.18 tree without further testing. Signed-off-by: Jan Beulich <jbeulich@novell.com> --- head-2010-01-04.orig/drivers/xen/privcmd/compat_privcmd.c 2009-11-06 10:45:48.000000000 +0100 +++ head-2010-01-04/drivers/xen/privcmd/compat_privcmd.c 2010-01-04 13:50:00.000000000 +0100 @@ -51,17 +51,49 @@ int privcmd_ioctl_32(int fd, unsigned in 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: --- head-2010-01-04.orig/include/xen/compat_ioctl.h 2007-07-10 09:42:30.000000000 +0200 +++ head-2010-01-04/include/xen/compat_ioctl.h 2009-12-17 15:40:40.000000000 +0100 @@ -23,6 +23,11 @@ #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; + }; +#else __u64 addr; /* virtual address */ +#endif compat_uptr_t arr; /* array of mfns - top nibble set on err */ }; #define IOCTL_PRIVCMD_MMAP_32 \ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Simon Horman
2010-Jan-06 02:27 UTC
Re: [Xen-devel] [PATCH] linux/privcmd: fix for proper operation in compat mode
On Tue, Jan 05, 2010 at 12:52:04PM +0000, Jan Beulich wrote:> - 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). > > As usual, written against 2.6.32.2 and made apply to the 2.6.18 > tree without further testing. > > Signed-off-by: Jan Beulich <jbeulich@novell.com> > > --- head-2010-01-04.orig/drivers/xen/privcmd/compat_privcmd.c 2009-11-06 10:45:48.000000000 +0100 > +++ head-2010-01-04/drivers/xen/privcmd/compat_privcmd.c 2010-01-04 13:50:00.000000000 +0100 > @@ -51,17 +51,49 @@ int privcmd_ioctl_32(int fd, unsigned in > 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:Perhaps this could be refactored to reduce or remove the #ifdefs ?> --- head-2010-01-04.orig/include/xen/compat_ioctl.h 2007-07-10 09:42:30.000000000 +0200 > +++ head-2010-01-04/include/xen/compat_ioctl.h 2009-12-17 15:40:40.000000000 +0100 > @@ -23,6 +23,11 @@ > #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 > +#endifIs it usual in xen for a type to be a #define in xen? Ito my mind it would make things a lot clearer to use a #define called SOME_FEATURE and then either use __u32 directly for the type or typedef __u32 xen_pfn32_t.> > 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; > + }; > +#else > __u64 addr; /* virtual address */ > +#endif > compat_uptr_t arr; /* array of mfns - top nibble set on err */ > }; > #define IOCTL_PRIVCMD_MMAP_32 \Its unclear to me why va is necessary. It doesn''t seem to be used anywhere in the patch. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jan Beulich
2010-Jan-06 08:19 UTC
Re: [Xen-devel] [PATCH] linux/privcmd: fix for proper operation in compat mode
>>> Simon Horman <horms@verge.net.au> 06.01.10 03:27 >>> >On Tue, Jan 05, 2010 at 12:52:04PM +0000, Jan Beulich wrote: >... >> +#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: > >Perhaps this could be refactored to reduce or remove the #ifdefs ?I couldn''t think of a clean way.>> --- head-2010-01-04.orig/include/xen/compat_ioctl.h 2007-07-10 09:42:30.000000000 +0200 >> +++ head-2010-01-04/include/xen/compat_ioctl.h 2009-12-17 15:40:40.000000000 +0100 >> @@ -23,6 +23,11 @@ >> #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 > >Is it usual in xen for a type to be a #define in xen? > >Ito my mind it would make things a lot clearer to use a #define called >SOME_FEATURE and then either use __u32 directly for the type or >typedef __u32 xen_pfn32_t.This would be an alternative, but I don''t think the code would look much better afterwards.>> @@ -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; >> + }; >> +#else >> __u64 addr; /* virtual address */ >> +#endif >> compat_uptr_t arr; /* array of mfns - top nibble set on err */ >> }; >> #define IOCTL_PRIVCMD_MMAP_32 \ > >Its unclear to me why va is necessary. >It doesn''t seem to be used anywhere in the patch.With the addr field being __packed, the va field ensures the union is 4-byte aligned (as it is in the native 32-bit type). Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel