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. 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>
This commit is contained in:
Родитель
ec1ab0abde
Коммит
2b1c6bd77d
|
@ -240,7 +240,7 @@ ia32_syscall_table:
|
||||||
data8 sys_ni_syscall
|
data8 sys_ni_syscall
|
||||||
data8 sys_umask /* 60 */
|
data8 sys_umask /* 60 */
|
||||||
data8 sys_chroot
|
data8 sys_chroot
|
||||||
data8 sys_ustat
|
data8 compat_sys_ustat
|
||||||
data8 sys_dup2
|
data8 sys_dup2
|
||||||
data8 sys_getppid
|
data8 sys_getppid
|
||||||
data8 sys_getpgrp /* 65 */
|
data8 sys_getpgrp /* 65 */
|
||||||
|
|
|
@ -356,40 +356,6 @@ SYSCALL_DEFINE1(32_personality, unsigned long, personality)
|
||||||
return ret;
|
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,
|
SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
|
||||||
compat_off_t __user *, offset, s32, count)
|
compat_off_t __user *, offset, s32, count)
|
||||||
{
|
{
|
||||||
|
|
|
@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
|
||||||
PTR compat_sys_utime /* 6130 */
|
PTR compat_sys_utime /* 6130 */
|
||||||
PTR sys_mknod
|
PTR sys_mknod
|
||||||
PTR sys_32_personality
|
PTR sys_32_personality
|
||||||
PTR sys_32_ustat
|
PTR compat_sys_ustat
|
||||||
PTR compat_sys_statfs
|
PTR compat_sys_statfs
|
||||||
PTR compat_sys_fstatfs /* 6135 */
|
PTR compat_sys_fstatfs /* 6135 */
|
||||||
PTR sys_sysfs
|
PTR sys_sysfs
|
||||||
|
|
|
@ -265,7 +265,7 @@ sys_call_table:
|
||||||
PTR sys_olduname
|
PTR sys_olduname
|
||||||
PTR sys_umask /* 4060 */
|
PTR sys_umask /* 4060 */
|
||||||
PTR sys_chroot
|
PTR sys_chroot
|
||||||
PTR sys_32_ustat
|
PTR compat_sys_ustat
|
||||||
PTR sys_dup2
|
PTR sys_dup2
|
||||||
PTR sys_getppid
|
PTR sys_getppid
|
||||||
PTR sys_getpgrp /* 4065 */
|
PTR sys_getpgrp /* 4065 */
|
||||||
|
|
|
@ -130,7 +130,7 @@
|
||||||
ENTRY_OURS(newuname)
|
ENTRY_OURS(newuname)
|
||||||
ENTRY_SAME(umask) /* 60 */
|
ENTRY_SAME(umask) /* 60 */
|
||||||
ENTRY_SAME(chroot)
|
ENTRY_SAME(chroot)
|
||||||
ENTRY_SAME(ustat)
|
ENTRY_COMP(ustat)
|
||||||
ENTRY_SAME(dup2)
|
ENTRY_SAME(dup2)
|
||||||
ENTRY_SAME(getppid)
|
ENTRY_SAME(getppid)
|
||||||
ENTRY_SAME(getpgrp) /* 65 */
|
ENTRY_SAME(getpgrp) /* 65 */
|
||||||
|
|
|
@ -65,7 +65,7 @@ SYSCALL(ni_syscall)
|
||||||
SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
|
SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
|
||||||
COMPAT_SYS_SPU(umask)
|
COMPAT_SYS_SPU(umask)
|
||||||
SYSCALL_SPU(chroot)
|
SYSCALL_SPU(chroot)
|
||||||
SYSCALL(ustat)
|
COMPAT_SYS(ustat)
|
||||||
SYSCALL_SPU(dup2)
|
SYSCALL_SPU(dup2)
|
||||||
SYSCALL_SPU(getppid)
|
SYSCALL_SPU(getppid)
|
||||||
SYSCALL_SPU(getpgrp)
|
SYSCALL_SPU(getpgrp)
|
||||||
|
|
|
@ -252,7 +252,7 @@ sys32_chroot_wrapper:
|
||||||
sys32_ustat_wrapper:
|
sys32_ustat_wrapper:
|
||||||
llgfr %r2,%r2 # dev_t
|
llgfr %r2,%r2 # dev_t
|
||||||
llgtr %r3,%r3 # struct ustat *
|
llgtr %r3,%r3 # struct ustat *
|
||||||
jg sys_ustat
|
jg compat_sys_ustat
|
||||||
|
|
||||||
.globl sys32_dup2_wrapper
|
.globl sys32_dup2_wrapper
|
||||||
sys32_dup2_wrapper:
|
sys32_dup2_wrapper:
|
||||||
|
|
|
@ -557,7 +557,7 @@ ia32_sys_call_table:
|
||||||
.quad sys32_olduname
|
.quad sys32_olduname
|
||||||
.quad sys_umask /* 60 */
|
.quad sys_umask /* 60 */
|
||||||
.quad sys_chroot
|
.quad sys_chroot
|
||||||
.quad sys32_ustat
|
.quad compat_sys_ustat
|
||||||
.quad sys_dup2
|
.quad sys_dup2
|
||||||
.quad sys_getppid
|
.quad sys_getppid
|
||||||
.quad sys_getpgrp /* 65 */
|
.quad sys_getpgrp /* 65 */
|
||||||
|
|
|
@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __user *name)
|
||||||
return err ? -EFAULT : 0;
|
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,
|
asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
|
||||||
compat_uptr_t __user *envp, struct pt_regs *regs)
|
compat_uptr_t __user *envp, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -129,13 +129,6 @@ typedef struct compat_siginfo {
|
||||||
} _sifields;
|
} _sifields;
|
||||||
} compat_siginfo_t;
|
} 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
|
#define IA32_STACK_TOP IA32_PAGE_OFFSET
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
|
@ -70,8 +70,6 @@ struct old_utsname;
|
||||||
asmlinkage long sys32_olduname(struct oldold_utsname __user *);
|
asmlinkage long sys32_olduname(struct oldold_utsname __user *);
|
||||||
long sys32_uname(struct old_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 *,
|
asmlinkage long sys32_execve(char __user *, compat_uptr_t __user *,
|
||||||
compat_uptr_t __user *, struct pt_regs *);
|
compat_uptr_t __user *, struct pt_regs *);
|
||||||
asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
|
asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
|
||||||
|
|
28
fs/compat.c
28
fs/compat.c
|
@ -378,6 +378,34 @@ out:
|
||||||
return error;
|
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)
|
static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
|
||||||
{
|
{
|
||||||
if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
|
if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
|
||||||
|
|
|
@ -125,6 +125,13 @@ struct compat_dirent {
|
||||||
char d_name[256];
|
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 {
|
typedef union compat_sigval {
|
||||||
compat_int_t sival_int;
|
compat_int_t sival_int;
|
||||||
compat_uptr_t sival_ptr;
|
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);
|
unsigned nsems, const struct compat_timespec __user *timeout);
|
||||||
asmlinkage long compat_sys_keyctl(u32 option,
|
asmlinkage long compat_sys_keyctl(u32 option,
|
||||||
u32 arg2, u32 arg3, u32 arg4, u32 arg5);
|
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,
|
asmlinkage ssize_t compat_sys_readv(unsigned long fd,
|
||||||
const struct compat_iovec __user *vec, unsigned long vlen);
|
const struct compat_iovec __user *vec, unsigned long vlen);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче