* =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??=
@ 2004-05-20 21:06 Arnd Bergmann
2004-06-05 0:16 ` =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arun Sharma
0 siblings, 1 reply; 14+ messages in thread
From: Arnd Bergmann @ 2004-05-20 21:06 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Arun Sharma, linux-arch
[-- Attachment #1: Type: text/plain, Size: 243 bytes --]
Arnd Bergmann <arnd@arndb.de> schrieb am 20.05.2004, 22:54:01:
>
> The attachment has an older (but so far untested) patch of mine
> to consolidate the syscalls from fs/readdir.c.
Ok, so here goes the attachment (I hope). Stupid webmail...
[-- Attachment #2: compat_readdir.diff --]
[-- Type: text/plain, Size: 6293 bytes --]
===== fs/compat.c 1.24 vs edited =====
--- 1.24/fs/compat.c Wed May 19 09:12:47 2004
+++ edited/fs/compat.c Thu May 20 22:39:43 2004
@@ -1632,3 +1632,246 @@
return sys_ni_syscall();
}
#endif
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & ~(sizeof(compat_long_t)-1))
+
+struct compat_old_linux_dirent {
+ compat_ulong_t d_ino;
+ compat_ulong_t d_offset;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct compat_readdir_callback {
+ struct compat_old_linux_dirent __user * dirent;
+ int result;
+};
+
+static int compat_fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type)
+{
+ struct compat_readdir_callback * buf = __buf;
+ struct compat_old_linux_dirent __user * dirent;
+
+ if (buf->result)
+ return -EINVAL;
+ buf->result++;
+ dirent = buf->dirent;
+ if (!access_ok(VERIFY_WRITE, (unsigned long)dirent,
+ (unsigned long)(dirent->d_name + namlen + 1) -
+ (unsigned long)dirent))
+ goto efault;
+ if ( __put_user(ino, &dirent->d_ino) ||
+ __put_user(offset, &dirent->d_offset) ||
+ __put_user(namlen, &dirent->d_namlen) ||
+ __copy_to_user(dirent->d_name, name, namlen) ||
+ __put_user(0, dirent->d_name + namlen))
+ goto efault;
+ return 0;
+efault:
+ buf->result = -EFAULT;
+ return -EFAULT;
+}
+
+asmlinkage long compat_old_readdir(unsigned int fd,
+ struct compat_old_linux_dirent __user * dirent, unsigned int count)
+{
+ int error;
+ struct file * file;
+ struct compat_readdir_callback buf;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.result = 0;
+ buf.dirent = dirent;
+
+ error = vfs_readdir(file, compat_fillonedir, &buf);
+ if (error >= 0)
+ error = buf.result;
+
+ fput(file);
+out:
+ return error;
+}
+
+struct compat_linux_dirent {
+ compat_ulong_t d_ino;
+ compat_ulong_t d_off;
+ unsigned short d_reclen;
+ char d_name[1];
+};
+
+struct compat_getdents_callback {
+ struct compat_linux_dirent __user * current_dir;
+ struct compat_linux_dirent __user * previous;
+ int count;
+ int error;
+};
+
+static int compat_filldir(void * __buf, const char * name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type)
+{
+ struct compat_linux_dirent __user * dirent;
+ struct compat_getdents_callback * buf = (struct compat_getdents_callback *) __buf;
+ int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+ if (__put_user(ino, &dirent->d_ino))
+ goto efault;
+ if (__put_user(reclen, &dirent->d_reclen))
+ goto efault;
+ if (copy_to_user(dirent->d_name, name, namlen))
+ goto efault;
+ if (__put_user(0, dirent->d_name + namlen))
+ goto efault;
+ if (__put_user(d_type, (char *) dirent + reclen - 1))
+ goto efault;
+ buf->previous = dirent;
+ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+efault:
+ buf->error = -EFAULT;
+ return -EFAULT;
+}
+
+asmlinkage long compat_sys_getdents(unsigned int fd, struct compat_linux_dirent __user * dirent, unsigned int count)
+{
+ struct file * file;
+ struct compat_linux_dirent __user * lastdirent;
+ struct compat_getdents_callback buf;
+ int error;
+
+ error = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, dirent, count))
+ goto out;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdir(file, compat_filldir, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.error;
+ lastdirent = buf.previous;
+ if (lastdirent) {
+ if (put_user(file->f_pos, &lastdirent->d_off))
+ error = -EFAULT;
+ else
+ error = count - buf.count;
+ }
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+
+#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
+#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+struct compat_getdents_callback64 {
+ struct linux_dirent64 __user * current_dir;
+ struct linux_dirent64 __user * previous;
+ int count;
+ int error;
+};
+
+static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
+ ino_t ino, unsigned int d_type)
+{
+ struct linux_dirent64 __user *dirent;
+ struct compat_getdents_callback64 * buf = (struct compat_getdents_callback64 *) __buf;
+ int reclen = COMPAT_ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
+ u64 off;
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent) {
+ if (__put_user(offset, &dirent->d_off))
+ goto efault;
+ }
+ dirent = buf->current_dir;
+ if (__copy_to_user(&dirent->d_ino, &ino, sizeof(ino)))
+ goto efault;
+ off = 0;
+ if (__copy_to_user(&dirent->d_off, &off, sizeof(off)))
+ goto efault;
+ if (__put_user(reclen, &dirent->d_reclen))
+ goto efault;
+ if (__put_user(d_type, &dirent->d_type))
+ goto efault;
+ if (copy_to_user(dirent->d_name, name, namlen))
+ goto efault;
+ if (__put_user(0, dirent->d_name + namlen))
+ goto efault;
+ buf->previous = dirent;
+ dirent = (void __user *)dirent + reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+efault:
+ buf->error = -EFAULT;
+ return -EFAULT;
+}
+
+asmlinkage long compat_sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent64 __user * lastdirent;
+ struct compat_getdents_callback64 buf;
+ int error;
+
+ error = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, dirent, count))
+ goto out;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdir(file, compat_filldir64, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.error;
+ lastdirent = buf.previous;
+ if (lastdirent) {
+ typeof(lastdirent->d_off) d_off = file->f_pos;
+ __put_user(d_off, &lastdirent->d_off);
+ error = count - buf.count;
+ }
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= 2004-05-20 21:06 =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arnd Bergmann @ 2004-06-05 0:16 ` Arun Sharma 2004-06-05 0:28 ` sys getdents64 needs compat wrapper ? David S. Miller 0 siblings, 1 reply; 14+ messages in thread From: Arun Sharma @ 2004-06-05 0:16 UTC (permalink / raw) To: Arnd Bergmann; +Cc: linux-arch [-- Attachment #1: Type: text/plain, Size: 614 bytes --] On 5/20/2004 2:06 PM, Arnd Bergmann wrote: > Arnd Bergmann <arnd@arndb.de> schrieb am 20.05.2004, 22:54:01: > >>The attachment has an older (but so far untested) patch of mine >>to consolidate the syscalls from fs/readdir.c. > Thanks for the patch. We made a few changes to the patch: - use put_user instead of copy_to_user for simple data types. - Couple of more instances where a 64 bit copy needs to be split into two compat_filldir64(): __put_user(offset, &dirent->d_off) compat_sys_getdents64(): __put_user(d_off, &lastdirent->d_off) With these changes, we don't see unaligned faults anymore. -Arun [-- Attachment #2: readdir_ive.1.diff --] [-- Type: text/plain, Size: 7576 bytes --] diff -Nurap a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S 2004-05-10 10:32:38.000000000 +0800 +++ b/arch/ia64/ia32/ia32_entry.S 2004-06-01 16:08:09.268146780 +0800 @@ -349,7 +349,7 @@ ia32_syscall_table: data8 sys_setfsuid /* 16-bit version */ data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ - data8 sys32_getdents + data8 compat_sys_getdents data8 sys32_select data8 sys_flock data8 sys32_msync @@ -428,7 +428,7 @@ ia32_syscall_table: data8 sys_pivot_root data8 sys_mincore data8 sys_madvise - data8 sys_getdents64 /* 220 */ + data8 compat_sys_getdents64 /* 220 */ data8 compat_sys_fcntl64 data8 sys_ni_syscall /* reserved for TUX */ data8 sys_ni_syscall /* reserved for Security */ diff -Nurap a/fs/compat.c b/fs/compat.c --- a/fs/compat.c 2004-05-10 10:32:29.000000000 +0800 +++ b/fs/compat.c 2004-06-01 16:08:38.474201110 +0800 @@ -34,6 +34,7 @@ #include <linux/syscalls.h> #include <linux/ctype.h> #include <linux/module.h> +#include <linux/dirent.h> #include <net/sock.h> /* siocdevprivate_ioctl */ #include <asm/uaccess.h> @@ -794,3 +795,252 @@ asmlinkage int compat_sys_mount(char __u return retval; } +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & ~(sizeof(compat_long_t)-1)) + +struct compat_old_linux_dirent { + compat_ulong_t d_ino; + compat_ulong_t d_offset; + unsigned short d_namlen; + char d_name[1]; +}; + +struct compat_readdir_callback { + struct compat_old_linux_dirent __user * dirent; + int result; +}; + +static int compat_fillonedir(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct compat_readdir_callback * buf = __buf; + struct compat_old_linux_dirent __user * dirent; + + if (buf->result) + return -EINVAL; + buf->result++; + dirent = buf->dirent; + if (!access_ok(VERIFY_WRITE, (unsigned long)dirent, + (unsigned long)(dirent->d_name + namlen + 1) - + (unsigned long)dirent)) + goto efault; + if ( __put_user(ino, &dirent->d_ino) || + __put_user(offset, &dirent->d_offset) || + __put_user(namlen, &dirent->d_namlen) || + __copy_to_user(dirent->d_name, name, namlen) || + __put_user(0, dirent->d_name + namlen)) + goto efault; + return 0; +efault: + buf->result = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_old_readdir(unsigned int fd, + struct compat_old_linux_dirent __user * dirent, unsigned int count) +{ + int error; + struct file * file; + struct compat_readdir_callback buf; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.result = 0; + buf.dirent = dirent; + + error = vfs_readdir(file, compat_fillonedir, &buf); + if (error >= 0) + error = buf.result; + + fput(file); +out: + return error; +} + +struct compat_linux_dirent { + compat_ulong_t d_ino; + compat_ulong_t d_off; + unsigned short d_reclen; + char d_name[1]; +}; + +struct compat_getdents_callback { + struct compat_linux_dirent __user * current_dir; + struct compat_linux_dirent __user * previous; + int count; + int error; +}; + +static int compat_filldir(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct compat_linux_dirent __user * dirent; + struct compat_getdents_callback * buf = (struct compat_getdents_callback *) __buf; + int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) { + if (__put_user(offset, &dirent->d_off)) + goto efault; + } + dirent = buf->current_dir; + if (__put_user(ino, &dirent->d_ino)) + goto efault; + if (__put_user(reclen, &dirent->d_reclen)) + goto efault; + if (copy_to_user(dirent->d_name, name, namlen)) + goto efault; + if (__put_user(0, dirent->d_name + namlen)) + goto efault; + if (__put_user(d_type, (char *) dirent + reclen - 1)) + goto efault; + buf->previous = dirent; + dirent = (void __user *)dirent + reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +efault: + buf->error = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_sys_getdents(unsigned int fd, struct compat_linux_dirent __user * dirent, unsigned int count) +{ + struct file * file; + struct compat_linux_dirent __user * lastdirent; + struct compat_getdents_callback buf; + int error; + + error = -EFAULT; + if (!access_ok(VERIFY_WRITE, dirent, count)) + goto out; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, compat_filldir, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + if (put_user(file->f_pos, &lastdirent->d_off)) + error = -EFAULT; + else + error = count - buf.count; + } + +out_putf: + fput(file); +out: + return error; +} + +#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64 +#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) + +struct compat_getdents_callback64 { + struct linux_dirent64 __user * current_dir; + struct linux_dirent64 __user * previous; + int count; + int error; +}; + +static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct linux_dirent64 __user *dirent; + struct compat_getdents_callback64 * buf = (struct compat_getdents_callback64 *) __buf; + int jj = NAME_OFFSET(dirent); + int reclen = COMPAT_ROUND_UP64(jj + namlen + 1); + u64 off; + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + + if (dirent) { + if ((__put_user(offset, (u32 *)&dirent->d_off)) + || (__put_user(offset >> 32, ((u32 *)&dirent->d_off) + 1))) + goto efault; + } + dirent = buf->current_dir; + if ((__put_user(ino, (u32 *)&dirent->d_ino)) + || (__put_user(ino >> 32, ((u32 *)&dirent->d_ino) + 1))) + goto efault; + off = 0; + if ((__put_user(off, (u32 *)&dirent->d_off)) + || (__put_user(off >> 32, ((u32 *)&dirent->d_off) + 1))) + goto efault; + if (__put_user(reclen, &dirent->d_reclen)) + goto efault; + if (__put_user(d_type, &dirent->d_type)) + goto efault; + if (copy_to_user(dirent->d_name, name, namlen)) + goto efault; + if (__put_user(0, dirent->d_name + namlen)) + goto efault; + buf->previous = dirent; + dirent = (void __user *)dirent + reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +efault: + buf->error = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count) +{ + struct file * file; + struct linux_dirent64 __user * lastdirent; + struct compat_getdents_callback64 buf; + int error; + + error = -EFAULT; + if (!access_ok(VERIFY_WRITE, dirent, count)) + goto out; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, compat_filldir64, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + typeof(lastdirent->d_off) d_off = file->f_pos; + __put_user(d_off, (u32 *)&lastdirent->d_off); + __put_user(d_off >> 32, ((u32 *)&lastdirent->d_off) + 1); + error = count - buf.count; + } + +out_putf: + fput(file); +out: + return error; +} +#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ + ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-05 0:16 ` =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arun Sharma @ 2004-06-05 0:28 ` David S. Miller 2004-06-07 21:13 ` Arun Sharma 0 siblings, 1 reply; 14+ messages in thread From: David S. Miller @ 2004-06-05 0:28 UTC (permalink / raw) To: Arun Sharma; +Cc: arnd, linux-arch Some bug fixes needed: +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) Cast must be "(char __user *)" to avoid sparse warnings. + if (__put_user(d_type, (char *) dirent + reclen - 1)) Again need "(char __user *)" for sparse. + if ((__put_user(offset, (u32 *)&dirent->d_off)) + || (__put_user(offset >> 32, ((u32 *)&dirent->d_off) + 1))) Again, need "(u32 __user *)" || (__put_user(ino >> 32, ((u32 *)&dirent->d_ino) + 1))) Another "(u32 __user *)" + || (__put_user(off >> 32, ((u32 *)&dirent->d_off) + 1))) Another "(u32 __user *)" + __put_user(d_off, (u32 *)&lastdirent->d_off); + __put_user(d_off >> 32, ((u32 *)&lastdirent->d_off) + 1); Two more "(u32 __user *)" People really need to get into the habit of running sparse on their changes to the compat code now that we've annotated most of it. :-) ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-05 0:28 ` sys getdents64 needs compat wrapper ? David S. Miller @ 2004-06-07 21:13 ` Arun Sharma 2004-06-07 21:58 ` David S. Miller 2004-06-11 15:09 ` Arnd Bergmann 0 siblings, 2 replies; 14+ messages in thread From: Arun Sharma @ 2004-06-07 21:13 UTC (permalink / raw) To: David S. Miller; +Cc: arnd, linux-arch [-- Attachment #1: Type: text/plain, Size: 554 bytes --] On 6/4/2004 5:28 PM, David S. Miller wrote: > Some bug fixes needed: > > +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) > > Cast must be "(char __user *)" to avoid sparse warnings. This updated patch takes care of the __user problems that Dave pointed out. Regarding __put_user vs __copy_to_user, __put_user is more optimal on ia64 like Andrew already noted. I realize it's not optimal on all platforms. So I suggest that we apply the patch for now and try to build something that's optimal for all platforms in the future. -Arun [-- Attachment #2: readdir_ive.3.patch --] [-- Type: text/plain, Size: 7933 bytes --] Running /emul/ia32-linux/bin/ls on 2.6.6 produces kernel mode unaligned faults. Analysis shows it's caused by getdents64 system call. Signed-off-by: Arun Sharma <arun.sharma@intel.com> Signed-off-by: Gordon Jin <gordon.jin@intel.com> Original patch by: Arnd Bergmann <arnd@arndb.de> diff -Nurap a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S 2004-05-10 10:32:38.000000000 +0800 +++ b/arch/ia64/ia32/ia32_entry.S 2004-06-07 17:42:56.151928752 +0800 @@ -349,7 +349,7 @@ ia32_syscall_table: data8 sys_setfsuid /* 16-bit version */ data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ - data8 sys32_getdents + data8 compat_sys_getdents data8 sys32_select data8 sys_flock data8 sys32_msync @@ -428,7 +428,7 @@ ia32_syscall_table: data8 sys_pivot_root data8 sys_mincore data8 sys_madvise - data8 sys_getdents64 /* 220 */ + data8 compat_sys_getdents64 /* 220 */ data8 compat_sys_fcntl64 data8 sys_ni_syscall /* reserved for TUX */ data8 sys_ni_syscall /* reserved for Security */ diff -Nurap a/fs/compat.c b/fs/compat.c --- a/fs/compat.c 2004-05-10 10:32:29.000000000 +0800 +++ b/fs/compat.c 2004-06-07 17:43:23.478100292 +0800 @@ -34,6 +34,7 @@ #include <linux/syscalls.h> #include <linux/ctype.h> #include <linux/module.h> +#include <linux/dirent.h> #include <net/sock.h> /* siocdevprivate_ioctl */ #include <asm/uaccess.h> @@ -794,3 +795,252 @@ asmlinkage int compat_sys_mount(char __u return retval; } +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) +#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & ~(sizeof(compat_long_t)-1)) + +struct compat_old_linux_dirent { + compat_ulong_t d_ino; + compat_ulong_t d_offset; + unsigned short d_namlen; + char d_name[1]; +}; + +struct compat_readdir_callback { + struct compat_old_linux_dirent __user * dirent; + int result; +}; + +static int compat_fillonedir(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct compat_readdir_callback * buf = __buf; + struct compat_old_linux_dirent __user * dirent; + + if (buf->result) + return -EINVAL; + buf->result++; + dirent = buf->dirent; + if (!access_ok(VERIFY_WRITE, (unsigned long)dirent, + (unsigned long)(dirent->d_name + namlen + 1) - + (unsigned long)dirent)) + goto efault; + if ( __put_user(ino, &dirent->d_ino) || + __put_user(offset, &dirent->d_offset) || + __put_user(namlen, &dirent->d_namlen) || + __copy_to_user(dirent->d_name, name, namlen) || + __put_user(0, dirent->d_name + namlen)) + goto efault; + return 0; +efault: + buf->result = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_old_readdir(unsigned int fd, + struct compat_old_linux_dirent __user * dirent, unsigned int count) +{ + int error; + struct file * file; + struct compat_readdir_callback buf; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.result = 0; + buf.dirent = dirent; + + error = vfs_readdir(file, compat_fillonedir, &buf); + if (error >= 0) + error = buf.result; + + fput(file); +out: + return error; +} + +struct compat_linux_dirent { + compat_ulong_t d_ino; + compat_ulong_t d_off; + unsigned short d_reclen; + char d_name[1]; +}; + +struct compat_getdents_callback { + struct compat_linux_dirent __user * current_dir; + struct compat_linux_dirent __user * previous; + int count; + int error; +}; + +static int compat_filldir(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct compat_linux_dirent __user * dirent; + struct compat_getdents_callback * buf = (struct compat_getdents_callback *) __buf; + int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) { + if (__put_user(offset, &dirent->d_off)) + goto efault; + } + dirent = buf->current_dir; + if (__put_user(ino, &dirent->d_ino)) + goto efault; + if (__put_user(reclen, &dirent->d_reclen)) + goto efault; + if (copy_to_user(dirent->d_name, name, namlen)) + goto efault; + if (__put_user(0, dirent->d_name + namlen)) + goto efault; + if (__put_user(d_type, (char __user *) dirent + reclen - 1)) + goto efault; + buf->previous = dirent; + dirent = (void __user *)dirent + reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +efault: + buf->error = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_sys_getdents(unsigned int fd, struct compat_linux_dirent __user * dirent, unsigned int count) +{ + struct file * file; + struct compat_linux_dirent __user * lastdirent; + struct compat_getdents_callback buf; + int error; + + error = -EFAULT; + if (!access_ok(VERIFY_WRITE, dirent, count)) + goto out; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, compat_filldir, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + if (put_user(file->f_pos, &lastdirent->d_off)) + error = -EFAULT; + else + error = count - buf.count; + } + +out_putf: + fput(file); +out: + return error; +} + +#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64 +#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) + +struct compat_getdents_callback64 { + struct linux_dirent64 __user * current_dir; + struct linux_dirent64 __user * previous; + int count; + int error; +}; + +static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct linux_dirent64 __user *dirent; + struct compat_getdents_callback64 * buf = (struct compat_getdents_callback64 *) __buf; + int jj = NAME_OFFSET(dirent); + int reclen = COMPAT_ROUND_UP64(jj + namlen + 1); + u64 off; + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + + if (dirent) { + if ((__put_user(offset, (u32 __user *)&dirent->d_off)) + || (__put_user(offset >> 32, ((u32 __user *)&dirent->d_off) + 1))) + goto efault; + } + dirent = buf->current_dir; + if ((__put_user(ino, (u32 __user *)&dirent->d_ino)) + || (__put_user(ino >> 32, ((u32 __user *)&dirent->d_ino) + 1))) + goto efault; + off = 0; + if ((__put_user(off, (u32 __user *)&dirent->d_off)) + || (__put_user(off >> 32, ((u32 __user *)&dirent->d_off) + 1))) + goto efault; + if (__put_user(reclen, &dirent->d_reclen)) + goto efault; + if (__put_user(d_type, &dirent->d_type)) + goto efault; + if (copy_to_user(dirent->d_name, name, namlen)) + goto efault; + if (__put_user(0, dirent->d_name + namlen)) + goto efault; + buf->previous = dirent; + dirent = (void __user *)dirent + reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +efault: + buf->error = -EFAULT; + return -EFAULT; +} + +asmlinkage long compat_sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count) +{ + struct file * file; + struct linux_dirent64 __user * lastdirent; + struct compat_getdents_callback64 buf; + int error; + + error = -EFAULT; + if (!access_ok(VERIFY_WRITE, dirent, count)) + goto out; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, compat_filldir64, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + typeof(lastdirent->d_off) d_off = file->f_pos; + __put_user(d_off, (u32 __user *)&lastdirent->d_off); + __put_user(d_off >> 32, ((u32 __user *)&lastdirent->d_off) + 1); + error = count - buf.count; + } + +out_putf: + fput(file); +out: + return error; +} +#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ + ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-07 21:13 ` Arun Sharma @ 2004-06-07 21:58 ` David S. Miller 2004-06-11 15:09 ` Arnd Bergmann 1 sibling, 0 replies; 14+ messages in thread From: David S. Miller @ 2004-06-07 21:58 UTC (permalink / raw) To: Arun Sharma; +Cc: arnd, linux-arch On Mon, 07 Jun 2004 14:13:02 -0700 Arun Sharma <arun.sharma@intel.com> wrote: > This updated patch takes care of the __user problems that Dave pointed > out. Regarding __put_user vs __copy_to_user, __put_user is more > optimal on ia64 like Andrew already noted. I realize it's not optimal > on all platforms. So I suggest that we apply the patch for now and try > to build something that's optimal for all platforms in the future. I agree. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-07 21:13 ` Arun Sharma 2004-06-07 21:58 ` David S. Miller @ 2004-06-11 15:09 ` Arnd Bergmann 2004-06-14 18:15 ` Arun Sharma 1 sibling, 1 reply; 14+ messages in thread From: Arnd Bergmann @ 2004-06-11 15:09 UTC (permalink / raw) To: Arun Sharma; +Cc: David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 1217 bytes --] On maanantai 07 kesäkuu 2004 23:13, Arun Sharma wrote: > This updated patch takes care of the __user problems that Dave > pointed out. Regarding __put_user vs __copy_to_user, __put_user > is more optimal on ia64 like Andrew already noted. I realize it's > not optimal on all platforms. So I suggest that we apply the > patch for now and try to build something that's optimal for all > platforms in the future. > + if (dirent) { > + if ((__put_user(offset, (u32 __user *)&dirent->d_off)) > + || (__put_user(offset >> 32, ((u32 __user *)&dirent->d_off) + 1))) > + goto efault; > + } I just realized your code is broken on big-endian architectures, so we should either get back to __copy_to_user or find the optimal solution now. How about a {__,}{get,put}_user_unaligned() that gets defined per architecture in one of these two ways: /* put_user doesn't care about alignment */ #define put_user_unaligned(x,ptr) put_user(x,ptr) /* put_user only works on aligned data */ #define put_user_unaligned(x,ptr) ({ \ __typeof__(*(ptr)) __x = (x); \ copy_to_user(ptr, &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ }) Arnd <>< [-- Attachment #2: signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-11 15:09 ` Arnd Bergmann @ 2004-06-14 18:15 ` Arun Sharma 2004-06-17 22:28 ` Arun Sharma 0 siblings, 1 reply; 14+ messages in thread From: Arun Sharma @ 2004-06-14 18:15 UTC (permalink / raw) To: Arnd Bergmann; +Cc: David S. Miller, linux-arch On 6/11/2004 8:09 AM, Arnd Bergmann wrote: > >>+ if (dirent) { >>+ if ((__put_user(offset, (u32 __user *)&dirent->d_off)) >>+ || (__put_user(offset >> 32, ((u32 __user *)&dirent->d_off) + 1))) >>+ goto efault; >>+ } > > > I just realized your code is broken on big-endian architectures, so > we should either get back to __copy_to_user or find the optimal solution > now. > > How about a {__,}{get,put}_user_unaligned() that gets defined per > architecture in one of these two ways: We'll go for the optimal solution now. We'll provide an <asm-generic/uaccess.h> that does __copy_to_user and a <asm-ia64/uaccess.h> that's optimized for ia64. Archs which don't care about alignment can override appropriately. Should have the patch tested by tomorrow. -Arun ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-14 18:15 ` Arun Sharma @ 2004-06-17 22:28 ` Arun Sharma 2004-06-17 23:36 ` Arnd Bergmann 0 siblings, 1 reply; 14+ messages in thread From: Arun Sharma @ 2004-06-17 22:28 UTC (permalink / raw) To: Andrew Morton; +Cc: Arnd Bergmann, David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 813 bytes --] On 6/14/2004 11:15 AM, Arun Sharma wrote: >> I just realized your code is broken on big-endian architectures, so >> we should either get back to __copy_to_user or find the optimal solution >> now. >> >> How about a {__,}{get,put}_user_unaligned() that gets defined per >> architecture in one of these two ways: > > > We'll go for the optimal solution now. We'll provide an > <asm-generic/uaccess.h> that does __copy_to_user and a > <asm-ia64/uaccess.h> that's optimized for ia64. Archs which don't care > about alignment can override appropriately. > > Should have the patch tested by tomorrow. It took us a bit longer :) But here's the promised patch. Using __put_user_unaligned() on ia64 may still cause unaligned faults, but we chose to optimize for the common case, where it's 4 byte aligned. -Arun [-- Attachment #2: __get_put_user_unaligned.patch --] [-- Type: text/plain, Size: 8037 bytes --] (1) Fix compat_filldir64() which is broken on big-endian machines. (2) Introduce new APIs __{get,put}_user_unaligned. (3) Optimize __{get,put}_user_unaligned for ia64. Signed-off-by: Gordon Jin <gordon.jin@intel.com> Signed-off-by: Arun Sharma <arun.sharma@intel.com> --- fs/compat.c | 14 ++++---------- include/asm-generic/uaccess.h | 25 +++++++++++++++++++++++++ include/asm-ia64/uaccess.h | 36 ++++++++++++++++++++++++++++++++++++ include/asm-mips/uaccess.h | 1 + include/asm-ppc64/uaccess.h | 1 + include/asm-s390/uaccess.h | 1 + include/asm-sparc64/uaccess.h | 1 + include/asm-x86_64/uaccess.h | 1 + 8 files changed, 70 insertions(+), 10 deletions(-) diff -purN -X dontdiff linux-2.6.7-rc3-getdents/fs/compat.c linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c --- linux-2.6.7-rc3-getdents/fs/compat.c 2004-06-16 22:13:46.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c 2004-06-17 14:51:42.019623885 +0800 @@ -979,19 +979,14 @@ static int compat_filldir64(void * __buf dirent = buf->previous; if (dirent) { - if (__put_user(offset, (u32 __user *)&dirent->d_off)) - goto efault; - if (__put_user(offset >> 32, - ((u32 __user *)&dirent->d_off) + 1)) + if (__put_user_unaligned(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if ((__put_user(ino, (u32 __user *)&dirent->d_ino)) - || (__put_user(ino >> 32, ((u32 __user *)&dirent->d_ino) + 1))) + if (__put_user_unaligned(ino, &dirent->d_ino)) goto efault; off = 0; - if ((__put_user(off, (u32 __user *)&dirent->d_off)) - || (__put_user(off >> 32, ((u32 __user *)&dirent->d_off) + 1))) + if (__put_user_unaligned(off, &dirent->d_off)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -1040,8 +1035,7 @@ asmlinkage long compat_sys_getdents64(un lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; - __put_user(d_off, (u32 __user *)&lastdirent->d_off); - __put_user(d_off >> 32, ((u32 __user *)&lastdirent->d_off) + 1); + __put_user_unaligned(d_off, &lastdirent->d_off); error = count - buf.count; } diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h 2004-06-17 15:06:28.391683339 +0800 @@ -0,0 +1,25 @@ +#ifndef _ASM_GENERIC_UACCESS_H_ +#define _ASM_GENERIC_UACCESS_H_ + +/* + * This macro should be used instead of __get_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __get_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x = (x); \ + copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ +}) + + +/* + * This macro should be used instead of __put_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __put_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x = (x); \ + copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ +}) + +#endif /* _ASM_GENERIC_UACCESS_H */ diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h 2004-06-16 22:13:46.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h 2004-06-17 15:13:34.646560930 +0800 @@ -91,6 +91,42 @@ verify_area (int type, const void *addr, #define __put_user(x, ptr) __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr))) #define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) +extern long __put_user_unaligned_unknown (void); + +#define __put_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __put_user((x), (ptr)); break; \ + case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \ + || (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \ + || (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \ + || (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __put_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + +extern long __get_user_unaligned_unknown (void); + +#define __get_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __get_user((x), (ptr)); break; \ + case 2: __ret = (__get_user((x), (u8 __user *)(ptr))) \ + || (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__get_user((x), (u16 __user *)(ptr))) \ + || (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__get_user((x), (u32 __user *)(ptr))) \ + || (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __get_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + #ifdef ASM_SUPPORTED struct __large_struct { unsigned long buf[100]; }; # define __m(x) (*(struct __large_struct *)(x)) diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h 2004-06-15 13:41:35.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h 2004-06-17 14:51:42.020600447 +0800 @@ -13,6 +13,7 @@ #include <linux/compiler.h> #include <linux/errno.h> #include <linux/thread_info.h> +#include <asm-generic/uaccess.h> /* * The fs value determines whether argument validity checking should be diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h 2004-06-15 13:41:35.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h 2004-06-17 14:51:42.020600447 +0800 @@ -12,6 +12,7 @@ #include <linux/sched.h> #include <linux/errno.h> #include <asm/processor.h> +#include <asm-generic/uaccess.h> #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h 2004-06-15 13:41:39.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h 2004-06-17 14:51:42.021577010 +0800 @@ -16,6 +16,7 @@ */ #include <linux/sched.h> #include <linux/errno.h> +#include <asm-generic/uaccess.h> #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h 2004-06-15 13:41:39.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h 2004-06-17 14:51:42.021577010 +0800 @@ -14,6 +14,7 @@ #include <asm/asi.h> #include <asm/system.h> #include <asm/spitfire.h> +#include <asm-generic/uaccess.h> #endif #ifndef __ASSEMBLY__ diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h 2004-06-15 13:41:34.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h 2004-06-17 14:51:42.022553572 +0800 @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/prefetch.h> #include <asm/page.h> +#include <asm-generic/uaccess.h> #define VERIFY_READ 0 #define VERIFY_WRITE 1 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-17 22:28 ` Arun Sharma @ 2004-06-17 23:36 ` Arnd Bergmann 2004-06-18 0:56 ` Arun Sharma 0 siblings, 1 reply; 14+ messages in thread From: Arnd Bergmann @ 2004-06-17 23:36 UTC (permalink / raw) To: Arun Sharma; +Cc: Andrew Morton, David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 5306 bytes --] On Freitag, 18. Juni 2004 00:28, Arun Sharma wrote: > It took us a bit longer :) But here's the promised patch. Using > __put_user_unaligned() on ia64 may still cause unaligned faults, > but we chose to optimize for the common case, where it's 4 byte > aligned. Isn't it legal for i386 code to pass syscall arguments with an arbitrary alignment? I guess gcc normally aligns everything to 32 bit unless you force it not to but you might still return error for syscalls that work fine on a native i386 system. > + */ > +#define __get_user_unaligned(x, ptr) \ > +({ \ > + __typeof__ (*(ptr)) __x = (x); \ > + copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ > +}) This should be __copy_from_user instead of copy_from_user, right? > + > + > +/* > + * This macro should be used instead of __put_user() when accessing > + * values at locations that are unknown to be aligned. > + */ > +#define __put_user_unaligned(x, ptr) \ > +({ \ > + __typeof__ (*(ptr)) __x = (x); \ > + copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ > +}) same here. > +extern long __put_user_unaligned_unknown (void); > + > +#define __put_user_unaligned(x, ptr) \ > +({ \ > + long __ret; \ > + switch (sizeof(*(ptr))) { \ > + case 1: __ret = __put_user((x), (ptr)); break; \ > + case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \ > + || (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ > + case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \ > + || (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ > + case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \ > + || (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ > + default: __ret = __put_user_unaligned_unknown(); \ > + } \ > + __ret; \ > +}) Under what circumstances would you need to break down a 4 byte alignment into 2 bytes? I can understand that you want to optimize the unaligned-64 bit case because i386-gcc aligns them only to 32 bit in user space, but the other special cases are bogus. Why not just do: #define __put_user_unaligned(x, ptr) \ ( \ (sizeof(*(ptr)) == 8) ? \ ((__put_user((x), (u32 __user *)(ptr))) \ | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1)))) \ : __put_user(x,ptr) \ ) Note also the use of | instead of || to get the correct value on error (-EFAULT, not 1). > diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h > --- linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h 2004-06-15 13:41:35.000000000 +0800 > +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h 2004-06-17 14:51:42.020600447 +0800 > @@ -12,6 +12,7 @@ > #include <linux/sched.h> > #include <linux/errno.h> > #include <asm/processor.h> > +#include <asm-generic/uaccess.h> > > #define VERIFY_READ 0 > #define VERIFY_WRITE 1 > diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h > --- linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h 2004-06-15 13:41:39.000000000 +0800 > +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h 2004-06-17 14:51:42.021577010 +0800 > @@ -16,6 +16,7 @@ > */ > #include <linux/sched.h> > #include <linux/errno.h> > +#include <asm-generic/uaccess.h> > > #define VERIFY_READ 0 > #define VERIFY_WRITE 1 ppc64 and s390 both don't care about alignment, so simply using #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user would make more sense here. See include/asm-*/unaligned.h > diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h > --- linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h 2004-06-15 13:41:34.000000000 +0800 > +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h 2004-06-17 14:51:42.022553572 +0800 > @@ -10,6 +10,7 @@ > #include <linux/sched.h> > #include <linux/prefetch.h> > #include <asm/page.h> > +#include <asm-generic/uaccess.h> > > #define VERIFY_READ 0 > #define VERIFY_WRITE 1 Same on x86_64. Arnd <>< [-- Attachment #2: signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-17 23:36 ` Arnd Bergmann @ 2004-06-18 0:56 ` Arun Sharma 2004-06-18 17:05 ` Arun Sharma 0 siblings, 1 reply; 14+ messages in thread From: Arun Sharma @ 2004-06-18 0:56 UTC (permalink / raw) To: Arnd Bergmann; +Cc: Andrew Morton, David S. Miller, linux-arch On 6/17/2004 4:36 PM, Arnd Bergmann wrote: > On Freitag, 18. Juni 2004 00:28, Arun Sharma wrote: > >>It took us a bit longer :) But here's the promised patch. Using >>__put_user_unaligned() on ia64 may still cause unaligned faults, >>but we chose to optimize for the common case, where it's 4 byte >>aligned. > > > Isn't it legal for i386 code to pass syscall arguments with > an arbitrary alignment? I guess gcc normally aligns everything > to 32 bit unless you force it not to but you might still return > error for syscalls that work fine on a native i386 system. > We don't return error, we just take an unaligned fault for this case. > >>+ */ >>+#define __get_user_unaligned(x, ptr) \ >>+({ \ >>+ __typeof__ (*(ptr)) __x = (x); \ >>+ copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ >>+}) > > > This should be __copy_from_user instead of copy_from_user, right? > Yes, will fix. > Under what circumstances would you need to break down a 4 byte > alignment into 2 bytes? I can understand that you want to optimize > the unaligned-64 bit case because i386-gcc aligns them only to 32 bit > in user space, but the other special cases are bogus. Why not > just do: I agree that it's unlikely to be used, but I put it in there for completeness. For eg: <asm-ia64/unaligned.h> is doing this too. > > ppc64 and s390 both don't care about alignment, so simply using > > #define __get_user_unaligned __get_user > #define __put_user_unaligned __put_user > > would make more sense here. See include/asm-*/unaligned.h > > >>diff -purN -X dontdiff linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h >>--- linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h 2004-06-15 13:41:34.000000000 +0800 >>+++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h 2004-06-17 14:51:42.022553572 +0800 >>@@ -10,6 +10,7 @@ >> #include <linux/sched.h> >> #include <linux/prefetch.h> >> #include <asm/page.h> >>+#include <asm-generic/uaccess.h> >> >> #define VERIFY_READ 0 >> #define VERIFY_WRITE 1 > > > Same on x86_64. Will update the patch for other archs as well. -Arun ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-18 0:56 ` Arun Sharma @ 2004-06-18 17:05 ` Arun Sharma 2004-06-20 21:50 ` Arnd Bergmann 0 siblings, 1 reply; 14+ messages in thread From: Arun Sharma @ 2004-06-18 17:05 UTC (permalink / raw) To: Arnd Bergmann; +Cc: Andrew Morton, David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 171 bytes --] On 6/17/2004 5:56 PM, Arun Sharma wrote: >> >> This should be __copy_from_user instead of copy_from_user, right? >> > > Yes, will fix. Updated patch attached. -Arun [-- Attachment #2: __get_put_user_unaligned.2.patch --] [-- Type: text/plain, Size: 7919 bytes --] (1) Fix compat_filldir64() which is broken on big-endian machines. (2) Introduce new APIs __{get,put}_user_unaligned. (3) Optimize __{get,put}_user_unaligned for ia64, x86-64, s390, ppc64. Thanks to Arnd Bergmann <arnd@arndb.de> for his help. Signed-off-by: Gordon Jin <gordon.jin@intel.com> Signed-off-by: Arun Sharma <arun.sharma@intel.com> diff -purN linux-2.6.7-rc3-getdents/fs/compat.c linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c --- linux-2.6.7-rc3-getdents/fs/compat.c 2004-06-18 18:41:36.072597378 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c 2004-06-17 14:51:42.000000000 +0800 @@ -979,19 +979,14 @@ static int compat_filldir64(void * __buf dirent = buf->previous; if (dirent) { - if (__put_user(offset, (u32 __user *)&dirent->d_off)) - goto efault; - if (__put_user(offset >> 32, - ((u32 __user *)&dirent->d_off) + 1)) + if (__put_user_unaligned(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if ((__put_user(ino, (u32 __user *)&dirent->d_ino)) - || (__put_user(ino >> 32, ((u32 __user *)&dirent->d_ino) + 1))) + if (__put_user_unaligned(ino, &dirent->d_ino)) goto efault; off = 0; - if ((__put_user(off, (u32 __user *)&dirent->d_off)) - || (__put_user(off >> 32, ((u32 __user *)&dirent->d_off) + 1))) + if (__put_user_unaligned(off, &dirent->d_off)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -1040,8 +1035,7 @@ asmlinkage long compat_sys_getdents64(un lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; - __put_user(d_off, (u32 __user *)&lastdirent->d_off); - __put_user(d_off >> 32, ((u32 __user *)&lastdirent->d_off) + 1); + __put_user_unaligned(d_off, &lastdirent->d_off); error = count - buf.count; } diff -purN linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h 2004-06-18 18:20:19.274761456 +0800 @@ -0,0 +1,25 @@ +#ifndef _ASM_GENERIC_UACCESS_H_ +#define _ASM_GENERIC_UACCESS_H_ + +/* + * This macro should be used instead of __get_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __get_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x = (x); \ + __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ +}) + + +/* + * This macro should be used instead of __put_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __put_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x = (x); \ + __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ +}) + +#endif /* _ASM_GENERIC_UACCESS_H */ diff -purN linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h 2004-06-18 18:41:09.208339895 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h 2004-06-18 18:24:27.561867790 +0800 @@ -91,6 +91,42 @@ verify_area (int type, const void *addr, #define __put_user(x, ptr) __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr))) #define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) +extern long __put_user_unaligned_unknown (void); + +#define __put_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __put_user((x), (ptr)); break; \ + case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \ + | (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \ + | (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \ + | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __put_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + +extern long __get_user_unaligned_unknown (void); + +#define __get_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __get_user((x), (ptr)); break; \ + case 2: __ret = (__get_user((x), (u8 __user *)(ptr))) \ + | (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__get_user((x), (u16 __user *)(ptr))) \ + | (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__get_user((x), (u32 __user *)(ptr))) \ + | (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __get_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + #ifdef ASM_SUPPORTED struct __large_struct { unsigned long buf[100]; }; # define __m(x) (*(struct __large_struct *)(x)) diff -purN linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h 2004-06-18 18:41:06.639980551 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h 2004-06-17 14:51:42.000000000 +0800 @@ -13,6 +13,7 @@ #include <linux/compiler.h> #include <linux/errno.h> #include <linux/thread_info.h> +#include <asm-generic/uaccess.h> /* * The fs value determines whether argument validity checking should be diff -purN linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h 2004-06-18 18:41:04.989589946 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h 2004-06-18 18:27:57.600927717 +0800 @@ -111,6 +111,9 @@ extern unsigned long search_exception_ta #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +#define __get_user_unaligned __get_user +#define __put_user_unaligned __put_user + extern long __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ diff -purN linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h 2004-06-18 18:41:20.317714758 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h 2004-06-18 18:31:37.594089084 +0800 @@ -230,6 +230,9 @@ extern int __put_user_bad(void); extern int __get_user_bad(void); +#define __put_user_unaligned __put_user +#define __get_user_unaligned __get_user + extern long __copy_to_user_asm(const void *from, long n, void *to); /** diff -purN linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h 2004-06-18 18:41:21.579433493 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h 2004-06-17 14:51:42.000000000 +0800 @@ -14,6 +14,7 @@ #include <asm/asi.h> #include <asm/system.h> #include <asm/spitfire.h> +#include <asm-generic/uaccess.h> #endif #ifndef __ASSEMBLY__ diff -purN linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h 2004-06-18 18:41:04.255214955 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h 2004-06-18 18:32:15.028658938 +0800 @@ -147,6 +147,9 @@ extern void __put_user_bad(void); #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +#define __get_user_unaligned __get_user +#define __put_user_unaligned __put_user + #define __put_user_nocheck(x,ptr,size) \ ({ \ int __pu_err; \ ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-18 17:05 ` Arun Sharma @ 2004-06-20 21:50 ` Arnd Bergmann 2004-06-22 18:21 ` Arun Sharma 0 siblings, 1 reply; 14+ messages in thread From: Arnd Bergmann @ 2004-06-20 21:50 UTC (permalink / raw) To: Arun Sharma; +Cc: Andrew Morton, David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 1023 bytes --] On Freitag, 18. Juni 2004 19:05, Arun Sharma wrote: > Updated patch attached. I now noticed one more bug: > + * values at locations that are unknown to be aligned. > + */ > +#define __get_user_unaligned(x, ptr) \ > +({ \ > + __typeof__ (*(ptr)) __x = (x); \ > + __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ > +}) The assignment is done in the wrong direction, this needs to become something like: #define __get_user_unaligned(x, ptr) \ ({ \ __typeof__ (*(ptr)) __x; \ __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ (x) = __x; \ }) Hopefully that'll be the last change for this, the rest looks good to me. Arnd <>< [-- Attachment #2: signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: sys getdents64 needs compat wrapper ? 2004-06-20 21:50 ` Arnd Bergmann @ 2004-06-22 18:21 ` Arun Sharma 0 siblings, 0 replies; 14+ messages in thread From: Arun Sharma @ 2004-06-22 18:21 UTC (permalink / raw) To: Arnd Bergmann; +Cc: Andrew Morton, David S. Miller, linux-arch [-- Attachment #1: Type: text/plain, Size: 1041 bytes --] On 6/20/2004 2:50 PM, Arnd Bergmann wrote: > I now noticed one more bug: > >> + * values at locations that are unknown to be aligned. >> + */ >> +#define __get_user_unaligned(x, ptr) \ >> +({ \ >> + __typeof__ (*(ptr)) __x = (x); \ >> + __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ >> +}) > > The assignment is done in the wrong direction, this needs to become > something like: > > #define __get_user_unaligned(x, ptr) \ > ({ \ > __typeof__ (*(ptr)) __x; \ > __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ > (x) = __x; \ > }) > > Hopefully that'll be the last change for this, the rest looks good to > me. Hope so! Take 3. -Arun [-- Attachment #2: __get_put_user_unaligned.3.patch --] [-- Type: text/plain, Size: 7893 bytes --] (1) Fix compat_filldir64() which is broken on big-endian machines. (2) Introduce new APIs __{get,put}_user_unaligned. (3) Optimize __{get,put}_user_unaligned for ia64, x86-64, ppc64 and s390. Signed-off-by: Gordon Jin <gordon.jin@intel.com> Signed-off-by: Arun Sharma <arun.sharma@intel.com> diff -purN linux-2.6.7-rc3-getdents/fs/compat.c linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c --- linux-2.6.7-rc3-getdents/fs/compat.c 2004-06-18 18:41:36.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/fs/compat.c 2004-06-17 14:51:42.000000000 +0800 @@ -979,19 +979,14 @@ static int compat_filldir64(void * __buf dirent = buf->previous; if (dirent) { - if (__put_user(offset, (u32 __user *)&dirent->d_off)) - goto efault; - if (__put_user(offset >> 32, - ((u32 __user *)&dirent->d_off) + 1)) + if (__put_user_unaligned(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; - if ((__put_user(ino, (u32 __user *)&dirent->d_ino)) - || (__put_user(ino >> 32, ((u32 __user *)&dirent->d_ino) + 1))) + if (__put_user_unaligned(ino, &dirent->d_ino)) goto efault; off = 0; - if ((__put_user(off, (u32 __user *)&dirent->d_off)) - || (__put_user(off >> 32, ((u32 __user *)&dirent->d_off) + 1))) + if (__put_user_unaligned(off, &dirent->d_off)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; @@ -1040,8 +1035,7 @@ asmlinkage long compat_sys_getdents64(un lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; - __put_user(d_off, (u32 __user *)&lastdirent->d_off); - __put_user(d_off >> 32, ((u32 __user *)&lastdirent->d_off) + 1); + __put_user_unaligned(d_off, &lastdirent->d_off); error = count - buf.count; } diff -purN linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-generic/uaccess.h 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-generic/uaccess.h 2004-06-22 09:40:05.861305422 +0800 @@ -0,0 +1,26 @@ +#ifndef _ASM_GENERIC_UACCESS_H_ +#define _ASM_GENERIC_UACCESS_H_ + +/* + * This macro should be used instead of __get_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __get_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x; \ + __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ + (x) = __x; \ +}) + + +/* + * This macro should be used instead of __put_user() when accessing + * values at locations that are unknown to be aligned. + */ +#define __put_user_unaligned(x, ptr) \ +({ \ + __typeof__ (*(ptr)) __x = (x); \ + __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ +}) + +#endif /* _ASM_GENERIC_UACCESS_H */ diff -purN linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ia64/uaccess.h 2004-06-18 18:41:09.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ia64/uaccess.h 2004-06-18 18:24:27.000000000 +0800 @@ -91,6 +91,42 @@ verify_area (int type, const void *addr, #define __put_user(x, ptr) __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr))) #define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) +extern long __put_user_unaligned_unknown (void); + +#define __put_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __put_user((x), (ptr)); break; \ + case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \ + | (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \ + | (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \ + | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __put_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + +extern long __get_user_unaligned_unknown (void); + +#define __get_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __get_user((x), (ptr)); break; \ + case 2: __ret = (__get_user((x), (u8 __user *)(ptr))) \ + | (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__get_user((x), (u16 __user *)(ptr))) \ + | (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__get_user((x), (u32 __user *)(ptr))) \ + | (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __get_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + #ifdef ASM_SUPPORTED struct __large_struct { unsigned long buf[100]; }; # define __m(x) (*(struct __large_struct *)(x)) diff -purN linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-mips/uaccess.h 2004-06-18 18:41:06.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-mips/uaccess.h 2004-06-17 14:51:42.000000000 +0800 @@ -13,6 +13,7 @@ #include <linux/compiler.h> #include <linux/errno.h> #include <linux/thread_info.h> +#include <asm-generic/uaccess.h> /* * The fs value determines whether argument validity checking should be diff -purN linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-ppc64/uaccess.h 2004-06-18 18:41:04.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-ppc64/uaccess.h 2004-06-18 18:27:57.000000000 +0800 @@ -111,6 +111,9 @@ extern unsigned long search_exception_ta #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +#define __get_user_unaligned __get_user +#define __put_user_unaligned __put_user + extern long __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ diff -purN linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-s390/uaccess.h 2004-06-18 18:41:20.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-s390/uaccess.h 2004-06-18 18:31:37.000000000 +0800 @@ -230,6 +230,9 @@ extern int __put_user_bad(void); extern int __get_user_bad(void); +#define __put_user_unaligned __put_user +#define __get_user_unaligned __get_user + extern long __copy_to_user_asm(const void *from, long n, void *to); /** diff -purN linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-sparc64/uaccess.h 2004-06-18 18:41:21.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-sparc64/uaccess.h 2004-06-17 14:51:42.000000000 +0800 @@ -14,6 +14,7 @@ #include <asm/asi.h> #include <asm/system.h> #include <asm/spitfire.h> +#include <asm-generic/uaccess.h> #endif #ifndef __ASSEMBLY__ diff -purN linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h --- linux-2.6.7-rc3-getdents/include/asm-x86_64/uaccess.h 2004-06-18 18:41:04.000000000 +0800 +++ linux-2.6.7-rc3-getdents-user_unaligned/include/asm-x86_64/uaccess.h 2004-06-18 18:32:15.000000000 +0800 @@ -147,6 +147,9 @@ extern void __put_user_bad(void); #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +#define __get_user_unaligned __get_user +#define __put_user_unaligned __put_user + #define __put_user_nocheck(x,ptr,size) \ ({ \ int __pu_err; \ ^ permalink raw reply [flat|nested] 14+ messages in thread
* =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??=
@ 2004-05-20 20:54 Arnd Bergmann
0 siblings, 0 replies; 14+ messages in thread
From: Arnd Bergmann @ 2004-05-20 20:54 UTC (permalink / raw)
To: Arun Sharma; +Cc: linux-arch
Arun Sharma <arun.sharma@intel.com> schrieb am 20.05.2004, 20:32:23:
>
> Running 32 bit ls on ia64 produces kernel mode unaligned faults
> with the attached backtrace on 2.6.6. I'm curious why this isn't a
> problem for other compat archs.
At least s390x doesn't need 64 bit alignment for accessing 64 bit
variables. Other explanations could be
- 32 bit user space also needs 8 byte alignment for struct dirent64
- an architecture catches unaligned accesses only for user, not kernel
space.
- put_user(u64...) handles unaligned access itself.
The attachment has an older (but so far untested) patch of mine
to consolidate the syscalls from fs/readdir.c. I have added a
compat_sys_getdents64() that uses __copy_to_user instead of
__put_user. Does that work for you or did you have something
different in mind?
Alternatively, that change could be done in sys_getdents64()
itself so you can use it for ia64 compat like the others do.
Arnd <><
^ permalink raw reply [flat|nested] 14+ messages in threadend of thread, other threads:[~2004-06-22 18:21 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2004-05-20 21:06 =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arnd Bergmann 2004-06-05 0:16 ` =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arun Sharma 2004-06-05 0:28 ` sys getdents64 needs compat wrapper ? David S. Miller 2004-06-07 21:13 ` Arun Sharma 2004-06-07 21:58 ` David S. Miller 2004-06-11 15:09 ` Arnd Bergmann 2004-06-14 18:15 ` Arun Sharma 2004-06-17 22:28 ` Arun Sharma 2004-06-17 23:36 ` Arnd Bergmann 2004-06-18 0:56 ` Arun Sharma 2004-06-18 17:05 ` Arun Sharma 2004-06-20 21:50 ` Arnd Bergmann 2004-06-22 18:21 ` Arun Sharma -- strict thread matches above, loose matches on Subject: below -- 2004-05-20 20:54 =?iso-8859-1?Q?Re:_sys_getdents64_needs_compat_wrapper_??= Arnd Bergmann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox