generic compat_sys_ustat
Christoph Hellwig [Fri, 28 Nov 2008 09:09:09 +0000 (10:09 +0100)]
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.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

13 files changed:
arch/ia64/ia32/ia32_entry.S
arch/mips/kernel/linux32.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/systbl.h
arch/s390/kernel/compat_wrapper.S
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/ia32.h
arch/x86/include/asm/sys_ia32.h
fs/compat.c
include/linux/compat.h

index a46f839..af9405c 100644 (file)
@@ -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 */
index 1a86f84..784859c 100644 (file)
@@ -356,40 +356,6 @@ SYSCALL_DEFINE1(32_personality, unsigned long, personality)
        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);
-
-SYSCALL_DEFINE2(32_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;
-}
-
 SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
        compat_off_t __user *, offset, s32, count)
 {
index 7438e92..f61d6b0 100644 (file)
@@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_utime                /* 6130 */
        PTR     sys_mknod
        PTR     sys_32_personality
-       PTR     sys_32_ustat
+       PTR     compat_sys_ustat
        PTR     compat_sys_statfs
        PTR     compat_sys_fstatfs              /* 6135 */
        PTR     sys_sysfs
index b0fef4f..60997f1 100644 (file)
@@ -265,7 +265,7 @@ sys_call_table:
        PTR     sys_olduname
        PTR     sys_umask                       /* 4060 */
        PTR     sys_chroot
-       PTR     sys_32_ustat
+       PTR     compat_sys_ustat
        PTR     sys_dup2
        PTR     sys_getppid
        PTR     sys_getpgrp                     /* 4065 */
index 303d2b6..03b9a01 100644 (file)
        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 */
index 72353f6..fe16649 100644 (file)
@@ -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)
index 62c706e..87cf5a7 100644 (file)
@@ -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:
index 5a0d76d..8ef8876 100644 (file)
@@ -557,7 +557,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 */
index 6c0d7f6..efac92f 100644 (file)
@@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __user *name)
        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)
 {
index 50ca486..1f7e625 100644 (file)
@@ -129,13 +129,6 @@ typedef struct compat_siginfo {
        } _sifields;
 } compat_siginfo_t;
 
-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__
index ffb08be..72a6dcd 100644 (file)
@@ -70,8 +70,6 @@ struct old_utsname;
 asmlinkage long sys32_olduname(struct oldold_utsname __user *);
 long sys32_uname(struct old_utsname __user *);
 
-long sys32_ustat(unsigned, struct ustat32 __user *);
-
 asmlinkage long sys32_execve(char __user *, compat_uptr_t __user *,
                             compat_uptr_t __user *, struct pt_regs *);
 asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
index d0145ca..4e0db94 100644 (file)
@@ -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)) ||
index 3fd2194..b880864 100644 (file)
@@ -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, struct sembuf __user *tsems,
                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);