Skip to contentSkip to conversation

generic compat_sys_ustat

PATCH In review Christoph Hellwig 5 participants 11 messages Nov 21, 2008 – Mar 14, 2009

Subsystems (6)
x86 VFS PowerPC MIPS +2 more subsystems
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 generic compat_sys_ustat

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

arch/x86/ia32/ia32entry.S +1 -1
Index: linux-2.6/arch/x86/ia32/ia32entry.S
===================================================================
@@ -555,7 +555,7 @@ ia32_sys_call_table:
 	.quad sys32_olduname
 	.quad sys_umask		/* 60 */
 	.quad sys_chroot
-	.quad sys32_ustat
+	.quad compat_sys_ustat
 	.quad sys_dup2
 	.quad sys_getppid
 	.quad sys_getpgrp		/* 65 */
arch/x86/ia32/sys_ia32.c +0 -22
Index: linux-2.6/arch/x86/ia32/sys_ia32.c
===================================================================
@@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __us
 	return err ? -EFAULT : 0;
 }
 
-long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
-{
-	struct ustat u;
-	mm_segment_t seg;
-	int ret;
-
-	seg = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ustat(dev, (struct ustat __user *)&u);
-	set_fs(seg);
-	if (ret < 0)
-		return ret;
-
-	if (!access_ok(VERIFY_WRITE, u32p, sizeof(struct ustat32)) ||
-	    __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
-	    __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
-	    __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
-	    __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
-		ret = -EFAULT;
-	return ret;
-}
-
 asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 			     compat_uptr_t __user *envp, struct pt_regs *regs)
 {
arch/x86/include/asm/ia32.h +0 -7
Index: linux-2.6/arch/x86/include/asm/ia32.h
===================================================================
@@ -147,13 +147,6 @@ struct rt_sigframe32 {
 	struct _fpstate_ia32 fpstate;
 };
 
-struct ustat32 {
-	__u32			f_tfree;
-	compat_ino_t		f_tinode;
-	char			f_fname[6];
-	char			f_fpack[6];
-};
-
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 
 #ifdef __KERNEL__
fs/compat.c +18 -0
Index: linux-2.6/fs/compat.c
===================================================================
@@ -378,6 +378,24 @@ out:
 	return error;
 }
 
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32)
+{
+	struct ustat *u = compat_alloc_user_space(sizeof(*u));
+	int ret;
+
+	ret = sys_ustat(dev, u);
+	if (ret < 0)
+		return ret;
+
+	if (!access_ok(VERIFY_WRITE, u32, sizeof(*u32)) ||
+	    __put_user((compat_daddr_t) u->f_tfree, &u32->f_tfree) ||
+	    __put_user((compat_ino_t) u->f_tinode, &u32->f_tfree) ||
+	    __copy_to_user(&u32->f_fname, u->f_fname, sizeof(u32->f_fname)) ||
+	    __copy_to_user(&u32->f_fpack, u->f_fpack, sizeof(u32->f_fpack)))
+		return -EFAULT;
+	return 0;
+}
+
 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 {
 	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
include/linux/compat.h +8 -0
Index: linux-2.6/include/linux/compat.h
===================================================================
@@ -125,6 +125,13 @@ struct compat_dirent {
 	char		d_name[256];
 };
 
+struct compat_ustat {
+	compat_daddr_t		f_tfree;
+	compat_ino_t		f_tinode;
+	char			f_fname[6];
+	char			f_fpack[6];
+};
+
 typedef union compat_sigval {
 	compat_int_t	sival_int;
 	compat_uptr_t	sival_ptr;
@@ -178,6 +185,7 @@ long compat_sys_semtimedop(int semid, st
 		unsigned nsems, const struct compat_timespec __user *timeout);
 asmlinkage long compat_sys_keyctl(u32 option,
 			      u32 arg2, u32 arg3, u32 arg4, u32 arg5);
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
 
 asmlinkage ssize_t compat_sys_readv(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
arch/ia64/ia32/ia32_entry.S +1 -1
Index: linux-2.6/arch/ia64/ia32/ia32_entry.S
===================================================================
@@ -240,7 +240,7 @@ ia32_syscall_table:
 	data8 sys_ni_syscall
 	data8 sys_umask		  /* 60 */
 	data8 sys_chroot
-	data8 sys_ustat
+	data8 compat_sys_ustat
 	data8 sys_dup2
 	data8 sys_getppid
 	data8 sys_getpgrp	  /* 65 */
arch/mips/kernel/linux32.c +0 -34
Index: linux-2.6/arch/mips/kernel/linux32.c
===================================================================
@@ -347,40 +347,6 @@ asmlinkage int sys32_personality(unsigne
 	return ret;
 }
 
-/* ustat compatibility */
-struct ustat32 {
-	compat_daddr_t	f_tfree;
-	compat_ino_t	f_tinode;
-	char		f_fname[6];
-	char		f_fpack[6];
-};
-
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
-
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
-{
-	int err;
-	struct ustat tmp;
-	struct ustat32 tmp32;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs(KERNEL_DS);
-	err = sys_ustat(dev, (struct ustat __user *)&tmp);
-	set_fs(old_fs);
-
-	if (err)
-		goto out;
-
-	memset(&tmp32, 0, sizeof(struct ustat32));
-	tmp32.f_tfree = tmp.f_tfree;
-	tmp32.f_tinode = tmp.f_tinode;
-
-	err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0;
-
-out:
-	return err;
-}
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
 	s32 count)
 {
arch/mips/kernel/scall64-n32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-n32.S
===================================================================
@@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_utime		/* 6130 */
 	PTR	sys_mknod
 	PTR	sys32_personality
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	compat_sys_statfs
 	PTR	compat_sys_fstatfs		/* 6135 */
 	PTR	sys_sysfs
arch/mips/kernel/scall64-o32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-o32.S
===================================================================
@@ -267,7 +267,7 @@ sys_call_table:
 	PTR	sys_olduname
 	PTR	sys_umask			/* 4060 */
 	PTR	sys_chroot
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	sys_dup2
 	PTR	sys_getppid
 	PTR	sys_getpgrp			/* 4065 */
arch/parisc/kernel/syscall_table.S +1 -1
Index: linux-2.6/arch/parisc/kernel/syscall_table.S
===================================================================
@@ -130,7 +130,7 @@
 	ENTRY_OURS(newuname)
 	ENTRY_SAME(umask)		/* 60 */
 	ENTRY_SAME(chroot)
-	ENTRY_SAME(ustat)
+	ENTRY_COMP(ustat)
 	ENTRY_SAME(dup2)
 	ENTRY_SAME(getppid)
 	ENTRY_SAME(getpgrp)		/* 65 */
arch/powerpc/include/asm/systbl.h +1 -1
Index: linux-2.6/arch/powerpc/include/asm/systbl.h
===================================================================
@@ -65,7 +65,7 @@ SYSCALL(ni_syscall)
 SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
 COMPAT_SYS_SPU(umask)
 SYSCALL_SPU(chroot)
-SYSCALL(ustat)
+COMPAT_SYS(ustat)
 SYSCALL_SPU(dup2)
 SYSCALL_SPU(getppid)
 SYSCALL_SPU(getpgrp)
arch/s390/kernel/compat_wrapper.S +1 -1
Index: linux-2.6/arch/s390/kernel/compat_wrapper.S
===================================================================
@@ -252,7 +252,7 @@ sys32_chroot_wrapper:
 sys32_ustat_wrapper:
 	llgfr	%r2,%r2			# dev_t
 	llgtr	%r3,%r3			# struct ustat *
-	jg	sys_ustat
+	jg	compat_sys_ustat
 
 	.globl	sys32_dup2_wrapper
 sys32_dup2_wrapper:
arch/sparc64/kernel/systbls.S +1 -1
Index: linux-2.6/arch/sparc64/kernel/systbls.S
===================================================================
@@ -51,7 +51,7 @@ sys_call_table32:
 /*150*/	.word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
 	.word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall
-	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys32_setxattr
+	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr
 /*170*/	.word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
 	.word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
Acked-by on v1 1/1
#1 lore raw
Quoted 10 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

For the MIPS bits:

Ralf

Tested-by on v1 1/1
#2 lore raw
In reply to Christoph Hellwig
Quoted 10 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

Works for me (fixes the case I had), thanks.

-Eric

#3 lore raw
In reply to Christoph Hellwig
Quoted 7 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

...

fs/compat.c out: · line 381

Quoted 9 lines

Index: linux-2.6/fs/compat.c
===================================================================

fs/compat.c +1 -0
@@ -378,6 +378,24 @@ out:
 	return error;
 }
 
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32)

Oh, I had also suggested that the use of "u32" here was slightly confusing, it at least made me do a double-take with the unsigned 32 bit type... not a big deal, but just thought I'd mention it.

Thanks,
-Eric

Quoted 17 lines
fs/compat.c +17 -0
+{
+	struct ustat *u = compat_alloc_user_space(sizeof(*u));
+	int ret;
+
+	ret = sys_ustat(dev, u);
+	if (ret < 0)
+		return ret;
+
+	if (!access_ok(VERIFY_WRITE, u32, sizeof(*u32)) ||
+	    __put_user((compat_daddr_t) u->f_tfree, &u32->f_tfree) ||
+	    __put_user((compat_ino_t) u->f_tinode, &u32->f_tfree) ||
+	    __copy_to_user(&u32->f_fname, u->f_fname, sizeof(u32->f_fname)) ||
+	    __copy_to_user(&u32->f_fpack, u->f_fpack, sizeof(u32->f_fpack)))
+		return -EFAULT;
+	return 0;
+}
+
#4 lore raw
In reply to Christoph Hellwig

Christoph Hellwig wrote:

...

fs/compat.c out: · line 383

Quoted 11 lines

Index: linux-2.6/fs/compat.c
===================================================================

fs/compat.c +3 -0
@@ -378,6 +378,24 @@ out:
 	return error;
 }
 
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32)
+{
+	struct ustat *u = compat_alloc_user_space(sizeof(*u));

Also, Pete Zaitcev pointed out to me:

Quoted 2 lines
Quoted 2 lines

Isn't this supposed to be:

	struct ustat __user *u = compat_alloc_user_space(sizeof(*u));

-Eric

Acked-by on v1 1/1
#5 lore raw
In reply to Christoph Hellwig
Quoted 11 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

Interesting we've been missing this without noticing...

#6 lore raw
In reply to Christoph Hellwig
Quoted 7 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

Updayed version fixing the naming issues Eric pointed out and some mess with kernel vs user pointers fixed by sparse.

arch/x86/ia32/ia32entry.S +1 -1
Index: linux-2.6/arch/x86/ia32/ia32entry.S
===================================================================
@@ -555,7 +555,7 @@ ia32_sys_call_table:
 	.quad sys32_olduname
 	.quad sys_umask		/* 60 */
 	.quad sys_chroot
-	.quad sys32_ustat
+	.quad compat_sys_ustat
 	.quad sys_dup2
 	.quad sys_getppid
 	.quad sys_getpgrp		/* 65 */
arch/x86/ia32/sys_ia32.c +0 -22
Index: linux-2.6/arch/x86/ia32/sys_ia32.c
===================================================================
@@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __us
 	return err ? -EFAULT : 0;
 }
 
-long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
-{
-	struct ustat u;
-	mm_segment_t seg;
-	int ret;
-
-	seg = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ustat(dev, (struct ustat __user *)&u);
-	set_fs(seg);
-	if (ret < 0)
-		return ret;
-
-	if (!access_ok(VERIFY_WRITE, u32p, sizeof(struct ustat32)) ||
-	    __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
-	    __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
-	    __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
-	    __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
-		ret = -EFAULT;
-	return ret;
-}
-
 asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 			     compat_uptr_t __user *envp, struct pt_regs *regs)
 {
arch/x86/include/asm/ia32.h +0 -7
Index: linux-2.6/arch/x86/include/asm/ia32.h
===================================================================
@@ -147,13 +147,6 @@ struct rt_sigframe32 {
 	struct _fpstate_ia32 fpstate;
 };
 
-struct ustat32 {
-	__u32			f_tfree;
-	compat_ino_t		f_tinode;
-	char			f_fname[6];
-	char			f_fpack[6];
-};
-
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 
 #ifdef __KERNEL__
fs/compat.c +18 -0
Index: linux-2.6/fs/compat.c
===================================================================
@@ -378,6 +378,24 @@ out:
 	return error;
 }
 
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *cu)
+{
+	struct ustat __user *u = compat_alloc_user_space(sizeof(*u));
+	int ret;
+
+	ret = sys_ustat(dev, u);
+	if (ret < 0)
+		return ret;
+
+	if (!access_ok(VERIFY_WRITE, cu, sizeof(*cu)) ||
+	    __copy_in_user(&cu->f_tfree, &u->f_tfree, sizeof(compat_daddr_t)) ||
+	    __copy_in_user(&cu->f_tinode, &u->f_tinode, sizeof(compat_ino_t)) ||
+	    __copy_in_user(&cu->f_fname, u->f_fname, sizeof(cu->f_fname)) ||
+	    __copy_in_user(&cu->f_fpack, u->f_fpack, sizeof(cu->f_fpack)))
+		return -EFAULT;
+	return 0;
+}
+
 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 {
 	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
include/linux/compat.h +8 -0
Index: linux-2.6/include/linux/compat.h
===================================================================
@@ -125,6 +125,13 @@ struct compat_dirent {
 	char		d_name[256];
 };
 
+struct compat_ustat {
+	compat_daddr_t		f_tfree;
+	compat_ino_t		f_tinode;
+	char			f_fname[6];
+	char			f_fpack[6];
+};
+
 typedef union compat_sigval {
 	compat_int_t	sival_int;
 	compat_uptr_t	sival_ptr;
@@ -178,6 +185,7 @@ long compat_sys_semtimedop(int semid, st
 		unsigned nsems, const struct compat_timespec __user *timeout);
 asmlinkage long compat_sys_keyctl(u32 option,
 			      u32 arg2, u32 arg3, u32 arg4, u32 arg5);
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
 
 asmlinkage ssize_t compat_sys_readv(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
arch/ia64/ia32/ia32_entry.S +1 -1
Index: linux-2.6/arch/ia64/ia32/ia32_entry.S
===================================================================
@@ -240,7 +240,7 @@ ia32_syscall_table:
 	data8 sys_ni_syscall
 	data8 sys_umask		  /* 60 */
 	data8 sys_chroot
-	data8 sys_ustat
+	data8 compat_sys_ustat
 	data8 sys_dup2
 	data8 sys_getppid
 	data8 sys_getpgrp	  /* 65 */
arch/mips/kernel/linux32.c +0 -34
Index: linux-2.6/arch/mips/kernel/linux32.c
===================================================================
@@ -347,40 +347,6 @@ asmlinkage int sys32_personality(unsigne
 	return ret;
 }
 
-/* ustat compatibility */
-struct ustat32 {
-	compat_daddr_t	f_tfree;
-	compat_ino_t	f_tinode;
-	char		f_fname[6];
-	char		f_fpack[6];
-};
-
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
-
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
-{
-	int err;
-	struct ustat tmp;
-	struct ustat32 tmp32;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs(KERNEL_DS);
-	err = sys_ustat(dev, (struct ustat __user *)&tmp);
-	set_fs(old_fs);
-
-	if (err)
-		goto out;
-
-	memset(&tmp32, 0, sizeof(struct ustat32));
-	tmp32.f_tfree = tmp.f_tfree;
-	tmp32.f_tinode = tmp.f_tinode;
-
-	err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0;
-
-out:
-	return err;
-}
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
 	s32 count)
 {
arch/mips/kernel/scall64-n32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-n32.S
===================================================================
@@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_utime		/* 6130 */
 	PTR	sys_mknod
 	PTR	sys32_personality
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	compat_sys_statfs
 	PTR	compat_sys_fstatfs		/* 6135 */
 	PTR	sys_sysfs
arch/mips/kernel/scall64-o32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-o32.S
===================================================================
@@ -267,7 +267,7 @@ sys_call_table:
 	PTR	sys_olduname
 	PTR	sys_umask			/* 4060 */
 	PTR	sys_chroot
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	sys_dup2
 	PTR	sys_getppid
 	PTR	sys_getpgrp			/* 4065 */
arch/parisc/kernel/syscall_table.S +1 -1
Index: linux-2.6/arch/parisc/kernel/syscall_table.S
===================================================================
@@ -130,7 +130,7 @@
 	ENTRY_OURS(newuname)
 	ENTRY_SAME(umask)		/* 60 */
 	ENTRY_SAME(chroot)
-	ENTRY_SAME(ustat)
+	ENTRY_COMP(ustat)
 	ENTRY_SAME(dup2)
 	ENTRY_SAME(getppid)
 	ENTRY_SAME(getpgrp)		/* 65 */
arch/powerpc/include/asm/systbl.h +1 -1
Index: linux-2.6/arch/powerpc/include/asm/systbl.h
===================================================================
@@ -65,7 +65,7 @@ SYSCALL(ni_syscall)
 SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
 COMPAT_SYS_SPU(umask)
 SYSCALL_SPU(chroot)
-SYSCALL(ustat)
+COMPAT_SYS(ustat)
 SYSCALL_SPU(dup2)
 SYSCALL_SPU(getppid)
 SYSCALL_SPU(getpgrp)
arch/s390/kernel/compat_wrapper.S +1 -1
Index: linux-2.6/arch/s390/kernel/compat_wrapper.S
===================================================================
@@ -252,7 +252,7 @@ sys32_chroot_wrapper:
 sys32_ustat_wrapper:
 	llgfr	%r2,%r2			# dev_t
 	llgtr	%r3,%r3			# struct ustat *
-	jg	sys_ustat
+	jg	compat_sys_ustat
 
 	.globl	sys32_dup2_wrapper
 sys32_dup2_wrapper:
arch/sparc64/kernel/systbls.S +1 -1
Index: linux-2.6/arch/sparc64/kernel/systbls.S
===================================================================
@@ -51,7 +51,7 @@ sys_call_table32:
 /*150*/	.word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
 	.word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall
-	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys32_setxattr
+	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr
 /*170*/	.word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
 	.word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
#7 lore raw
Quoted 7 lines · Christoph Hellwig
fs/compat.c +7 -0
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *cu)
+{
+       struct ustat __user *u = compat_alloc_user_space(sizeof(*u));
+       int ret;
+
+       ret = sys_ustat(dev, u);
+       if (ret < 0)

fs/compat.c out: · line 397

Quoted 10 lines
fs/compat.c +10 -0
+               return ret;
+
+       if (!access_ok(VERIFY_WRITE, cu, sizeof(*cu)) ||
+           __copy_in_user(&cu->f_tfree, &u->f_tfree, sizeof(compat_daddr_t)) ||
+           __copy_in_user(&cu->f_tinode, &u->f_tinode, sizeof(compat_ino_t)) ||
+           __copy_in_user(&cu->f_fname, u->f_fname, sizeof(cu->f_fname)) ||
+           __copy_in_user(&cu->f_fpack, u->f_fpack, sizeof(cu->f_fpack)))
+               return -EFAULT;
+       return 0;
+}

The __copy_in_user for f_tinode and f_tfree only work on little-endian systems, or if the sizes are the same for 32 and 64 bit. f_fname and f_fpack don't need to be copied at all, as they are always zero-filled in the current implementation (which is unlikely to ever change).

Also, this function is not much simpler than the actual sys_ustat function, so have you considered implementing it directly like this?

asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user * ubuf)

{
        struct super_block *s;
        struct compat_ustat tmp;
        struct kstatfs sbuf;
        int err = -EINVAL;

        s = user_get_super(new_decode_dev(dev));
        if (s == NULL)
                goto out;
        err = vfs_statfs(s->s_root, &sbuf);
        drop_super(s);
        if (err)
                goto out;

        memset(&tmp,0,sizeof(struct compat_ustat));
        tmp.f_tfree = sbuf.f_bfree;
        tmp.f_tinode = sbuf.f_ffree;

        err = copy_to_user(ubuf,&tmp,sizeof(struct compat_ustat)) ? -EFAULT : 0;
out:
        return err;
}

This code is directly lifted from the sys_ustat implementation, with a few compat_ added in the right places.

	Arnd <><
#8 lore raw
In reply to Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it. Instead of doing various user copy hacks compat_sys_ustat just reimplements sys_ustat as it's trivial. This was suggested by Arnd Bergmann.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

arch/x86/ia32/ia32entry.S +1 -1
Index: linux-2.6/arch/x86/ia32/ia32entry.S
===================================================================
@@ -555,7 +555,7 @@ ia32_sys_call_table:
 	.quad sys32_olduname
 	.quad sys_umask		/* 60 */
 	.quad sys_chroot
-	.quad sys32_ustat
+	.quad compat_sys_ustat
 	.quad sys_dup2
 	.quad sys_getppid
 	.quad sys_getpgrp		/* 65 */
arch/x86/ia32/sys_ia32.c +0 -22
Index: linux-2.6/arch/x86/ia32/sys_ia32.c
===================================================================
@@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __us
 	return err ? -EFAULT : 0;
 }
 
-long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
-{
-	struct ustat u;
-	mm_segment_t seg;
-	int ret;
-
-	seg = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ustat(dev, (struct ustat __user *)&u);
-	set_fs(seg);
-	if (ret < 0)
-		return ret;
-
-	if (!access_ok(VERIFY_WRITE, u32p, sizeof(struct ustat32)) ||
-	    __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
-	    __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
-	    __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
-	    __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
-		ret = -EFAULT;
-	return ret;
-}
-
 asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 			     compat_uptr_t __user *envp, struct pt_regs *regs)
 {
fs/compat.c +28 -0
Index: linux-2.6/fs/compat.c
===================================================================
@@ -378,6 +378,34 @@ out:
 	return error;
 }
 
+/*
+ * This is a copy of sys_ustat, just dealing with a structure layout.
+ * Given how simple this syscall is that apporach is more maintainable
+ * than the various conversion hacks.
+ */
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
+{
+	struct super_block *sb;
+	struct compat_ustat tmp;
+	struct kstatfs sbuf;
+	int err;
+
+	sb = user_get_super(new_decode_dev(dev));
+	if (!sb)
+		return -EINVAL;
+	err = vfs_statfs(sb->s_root, &sbuf);
+	drop_super(sb);
+	if (err)
+		return err;
+
+	memset(&tmp, 0, sizeof(struct compat_ustat));
+	tmp.f_tfree = sbuf.f_bfree;
+	tmp.f_tinode = sbuf.f_ffree;
+	if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
+		return -EFAULT;
+	return 0;
+}
+
 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 {
 	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
include/linux/compat.h +8 -0
Index: linux-2.6/include/linux/compat.h
===================================================================
@@ -125,6 +125,13 @@ struct compat_dirent {
 	char		d_name[256];
 };
 
+struct compat_ustat {
+	compat_daddr_t		f_tfree;
+	compat_ino_t		f_tinode;
+	char			f_fname[6];
+	char			f_fpack[6];
+};
+
 typedef union compat_sigval {
 	compat_int_t	sival_int;
 	compat_uptr_t	sival_ptr;
@@ -178,6 +185,7 @@ long compat_sys_semtimedop(int semid, st
 		unsigned nsems, const struct compat_timespec __user *timeout);
 asmlinkage long compat_sys_keyctl(u32 option,
 			      u32 arg2, u32 arg3, u32 arg4, u32 arg5);
+asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
 
 asmlinkage ssize_t compat_sys_readv(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
arch/ia64/ia32/ia32_entry.S +1 -1
Index: linux-2.6/arch/ia64/ia32/ia32_entry.S
===================================================================
@@ -240,7 +240,7 @@ ia32_syscall_table:
 	data8 sys_ni_syscall
 	data8 sys_umask		  /* 60 */
 	data8 sys_chroot
-	data8 sys_ustat
+	data8 compat_sys_ustat
 	data8 sys_dup2
 	data8 sys_getppid
 	data8 sys_getpgrp	  /* 65 */
arch/mips/kernel/linux32.c +0 -34
Index: linux-2.6/arch/mips/kernel/linux32.c
===================================================================
@@ -347,40 +347,6 @@ asmlinkage int sys32_personality(unsigne
 	return ret;
 }
 
-/* ustat compatibility */
-struct ustat32 {
-	compat_daddr_t	f_tfree;
-	compat_ino_t	f_tinode;
-	char		f_fname[6];
-	char		f_fpack[6];
-};
-
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
-
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
-{
-	int err;
-	struct ustat tmp;
-	struct ustat32 tmp32;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs(KERNEL_DS);
-	err = sys_ustat(dev, (struct ustat __user *)&tmp);
-	set_fs(old_fs);
-
-	if (err)
-		goto out;
-
-	memset(&tmp32, 0, sizeof(struct ustat32));
-	tmp32.f_tfree = tmp.f_tfree;
-	tmp32.f_tinode = tmp.f_tinode;
-
-	err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0;
-
-out:
-	return err;
-}
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
 	s32 count)
 {
arch/mips/kernel/scall64-n32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-n32.S
===================================================================
@@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_utime		/* 6130 */
 	PTR	sys_mknod
 	PTR	sys32_personality
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	compat_sys_statfs
 	PTR	compat_sys_fstatfs		/* 6135 */
 	PTR	sys_sysfs
arch/mips/kernel/scall64-o32.S +1 -1
Index: linux-2.6/arch/mips/kernel/scall64-o32.S
===================================================================
@@ -267,7 +267,7 @@ sys_call_table:
 	PTR	sys_olduname
 	PTR	sys_umask			/* 4060 */
 	PTR	sys_chroot
-	PTR	sys32_ustat
+	PTR	compat_sys_ustat
 	PTR	sys_dup2
 	PTR	sys_getppid
 	PTR	sys_getpgrp			/* 4065 */
arch/parisc/kernel/syscall_table.S +1 -1
Index: linux-2.6/arch/parisc/kernel/syscall_table.S
===================================================================
@@ -130,7 +130,7 @@
 	ENTRY_OURS(newuname)
 	ENTRY_SAME(umask)		/* 60 */
 	ENTRY_SAME(chroot)
-	ENTRY_SAME(ustat)
+	ENTRY_COMP(ustat)
 	ENTRY_SAME(dup2)
 	ENTRY_SAME(getppid)
 	ENTRY_SAME(getpgrp)		/* 65 */
arch/powerpc/include/asm/systbl.h +1 -1
Index: linux-2.6/arch/powerpc/include/asm/systbl.h
===================================================================
@@ -65,7 +65,7 @@ SYSCALL(ni_syscall)
 SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
 COMPAT_SYS_SPU(umask)
 SYSCALL_SPU(chroot)
-SYSCALL(ustat)
+COMPAT_SYS(ustat)
 SYSCALL_SPU(dup2)
 SYSCALL_SPU(getppid)
 SYSCALL_SPU(getpgrp)
arch/s390/kernel/compat_wrapper.S +1 -1
Index: linux-2.6/arch/s390/kernel/compat_wrapper.S
===================================================================
@@ -252,7 +252,7 @@ sys32_chroot_wrapper:
 sys32_ustat_wrapper:
 	llgfr	%r2,%r2			# dev_t
 	llgtr	%r3,%r3			# struct ustat *
-	jg	sys_ustat
+	jg	compat_sys_ustat
 
 	.globl	sys32_dup2_wrapper
 sys32_dup2_wrapper:
arch/sparc64/kernel/systbls.S +1 -1
Index: linux-2.6/arch/sparc64/kernel/systbls.S
===================================================================
@@ -51,7 +51,7 @@ sys_call_table32:
 /*150*/	.word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
 	.word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall
-	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys32_setxattr
+	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr
 /*170*/	.word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
 	.word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
arch/x86/include/asm/ia32.h +0 -7
Index: linux-2.6/arch/x86/include/asm/ia32.h
===================================================================
@@ -147,13 +147,6 @@ struct rt_sigframe32 {
 	struct _fpstate_ia32 fpstate;
 };
 
-struct ustat32 {
-	__u32			f_tfree;
-	compat_ino_t		f_tinode;
-	char			f_fname[6];
-	char			f_fpack[6];
-};
-
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 
 #ifdef __KERNEL__
#9 lore raw
Quoted 11 lines · Christoph Hellwig

Due to a different size of ino_t ustat needs a compat handler, but currently only x86 and mips provide one. Add a generic compat_sys_ustat and switch all architectures over to it. Instead of doing various user copy hacks compat_sys_ustat just reimplements sys_ustat as it's trivial. This was suggested by Arnd Bergmann.

Found by Eric Sandeen when running xfstests/017 on ppc64, which causes stack smashing warnings on RHEL/Fedora due to the too large amount of data writen by the syscall.

Looks like this got lost?

-Eric

Quoted 14 lines

Index: linux-2.6/arch/x86/ia32/ia32entry.S
===================================================================

arch/x86/ia32/ia32entry.S +1 -1
@@ -555,7 +555,7 @@ ia32_sys_call_table:
 	.quad sys32_olduname
 	.quad sys_umask		/* 60 */
 	.quad sys_chroot
-	.quad sys32_ustat
+	.quad compat_sys_ustat
 	.quad sys_dup2
 	.quad sys_getppid
 	.quad sys_getpgrp		/* 65 */

....

#10 lore raw
Quoted 2 lines · Eric Sandeen

Looks like this got lost?

Al promised to take it via the vfs queue, so hopefully it 'll go in for the next releases..