Skip to content

Commit

Permalink
generic compat_sys_ustat
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Christoph Hellwig authored and Al Viro committed Mar 27, 2009
1 parent ec1ab0a commit 2b1c6bd
Show file tree
Hide file tree
Showing 13 changed files with 43 additions and 72 deletions.
2 changes: 1 addition & 1 deletion arch/ia64/ia32/ia32_entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
34 changes: 0 additions & 34 deletions arch/mips/kernel/linux32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/kernel/scall64-n32.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/kernel/scall64-o32.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion arch/parisc/kernel/syscall_table.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/systbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/kernel/compat_wrapper.S
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/ia32/ia32entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
22 changes: 0 additions & 22 deletions arch/x86/ia32/sys_ia32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
7 changes: 0 additions & 7 deletions arch/x86/include/asm/ia32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/include/asm/sys_ia32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
28 changes: 28 additions & 0 deletions fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,34 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
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)) ||
Expand Down
8 changes: 8 additions & 0 deletions include/linux/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2b1c6bd

Please sign in to comment.