diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2020-09-09 15:45:47 +0200 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2020-09-17 10:10:36 +0200 |
| commit | 92d46ccadbf113267842414a27b6d611dc4369a6 (patch) | |
| tree | 81a2f6e52f4730ebd58c4942ec919ea2a8b9eb16 | |
| parent | c28f2a3405e27b1b4c6614526418b0b7ac102ee8 (diff) | |
| download | playground-92d46ccadbf113267842414a27b6d611dc4369a6.tar.gz | |
quota: merge compat handling back into quotactl
Moving the compat handling into a separate file in commit 5582c76f901d
("quota: split out compat_sys_quotactl support from quota.c") did help
to reduce conditional compilation in the main file, but it makes it hard
to get rid of the last users of compat_alloc_user_space().
Move the type conversion back into the main quota.c file, but do it
directly in the handlers with an in_ia32_syscall() check that avoids
copying every word multiple times.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | arch/x86/entry/syscalls/syscall_32.tbl | 2 | ||||
| -rw-r--r-- | fs/quota/Kconfig | 5 | ||||
| -rw-r--r-- | fs/quota/Makefile | 1 | ||||
| -rw-r--r-- | fs/quota/compat.c | 120 | ||||
| -rw-r--r-- | fs/quota/quota.c | 99 | ||||
| -rw-r--r-- | kernel/sys_ni.c | 1 |
6 files changed, 98 insertions, 130 deletions
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 3e9576138baff..7e4140b78aad5 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -142,7 +142,7 @@ 128 i386 init_module sys_init_module 129 i386 delete_module sys_delete_module 130 i386 get_kernel_syms -131 i386 quotactl sys_quotactl compat_sys_quotactl32 +131 i386 quotactl sys_quotactl 132 i386 getpgid sys_getpgid 133 i386 fchdir sys_fchdir 134 i386 bdflush sys_bdflush diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index d1ceb76adb71e..b59cd172b5f97 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig @@ -70,8 +70,3 @@ config QFMT_V2 config QUOTACTL bool default n - -config QUOTACTL_COMPAT - bool - depends on QUOTACTL && COMPAT_FOR_U64_ALIGNMENT - default y diff --git a/fs/quota/Makefile b/fs/quota/Makefile index f2b49d0f0287c..9160639daffa7 100644 --- a/fs/quota/Makefile +++ b/fs/quota/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_QFMT_V1) += quota_v1.o obj-$(CONFIG_QFMT_V2) += quota_v2.o obj-$(CONFIG_QUOTA_TREE) += quota_tree.o obj-$(CONFIG_QUOTACTL) += quota.o kqid.o -obj-$(CONFIG_QUOTACTL_COMPAT) += compat.o obj-$(CONFIG_QUOTA_NETLINK_INTERFACE) += netlink.o diff --git a/fs/quota/compat.c b/fs/quota/compat.c deleted file mode 100644 index c305728576193..0000000000000 --- a/fs/quota/compat.c +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include <linux/syscalls.h> -#include <linux/compat.h> -#include <linux/quotaops.h> - -/* - * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) - * and is necessary due to alignment problems. - */ -struct compat_if_dqblk { - compat_u64 dqb_bhardlimit; - compat_u64 dqb_bsoftlimit; - compat_u64 dqb_curspace; - compat_u64 dqb_ihardlimit; - compat_u64 dqb_isoftlimit; - compat_u64 dqb_curinodes; - compat_u64 dqb_btime; - compat_u64 dqb_itime; - compat_uint_t dqb_valid; -}; - -/* XFS structures */ -struct compat_fs_qfilestat { - compat_u64 dqb_bhardlimit; - compat_u64 qfs_nblks; - compat_uint_t qfs_nextents; -}; - -struct compat_fs_quota_stat { - __s8 qs_version; - __u16 qs_flags; - __s8 qs_pad; - struct compat_fs_qfilestat qs_uquota; - struct compat_fs_qfilestat qs_gquota; - compat_uint_t qs_incoredqs; - compat_int_t qs_btimelimit; - compat_int_t qs_itimelimit; - compat_int_t qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; -}; - -COMPAT_SYSCALL_DEFINE4(quotactl32, unsigned int, cmd, - const char __user *, special, qid_t, id, - void __user *, addr) -{ - unsigned int cmds; - struct if_dqblk __user *dqblk; - struct compat_if_dqblk __user *compat_dqblk; - struct fs_quota_stat __user *fsqstat; - struct compat_fs_quota_stat __user *compat_fsqstat; - compat_uint_t data; - u16 xdata; - long ret; - - cmds = cmd >> SUBCMDSHIFT; - - switch (cmds) { - case Q_GETQUOTA: - dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); - compat_dqblk = addr; - ret = kernel_quotactl(cmd, special, id, dqblk); - if (ret) - break; - if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || - get_user(data, &dqblk->dqb_valid) || - put_user(data, &compat_dqblk->dqb_valid)) - ret = -EFAULT; - break; - case Q_SETQUOTA: - dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); - compat_dqblk = addr; - ret = -EFAULT; - if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || - get_user(data, &compat_dqblk->dqb_valid) || - put_user(data, &dqblk->dqb_valid)) - break; - ret = kernel_quotactl(cmd, special, id, dqblk); - break; - case Q_XGETQSTAT: - fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); - compat_fsqstat = addr; - ret = kernel_quotactl(cmd, special, id, fsqstat); - if (ret) - break; - ret = -EFAULT; - /* Copying qs_version, qs_flags, qs_pad */ - if (copy_in_user(compat_fsqstat, fsqstat, - offsetof(struct compat_fs_quota_stat, qs_uquota))) - break; - /* Copying qs_uquota */ - if (copy_in_user(&compat_fsqstat->qs_uquota, - &fsqstat->qs_uquota, - sizeof(compat_fsqstat->qs_uquota)) || - get_user(data, &fsqstat->qs_uquota.qfs_nextents) || - put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) - break; - /* Copying qs_gquota */ - if (copy_in_user(&compat_fsqstat->qs_gquota, - &fsqstat->qs_gquota, - sizeof(compat_fsqstat->qs_gquota)) || - get_user(data, &fsqstat->qs_gquota.qfs_nextents) || - put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) - break; - /* Copying the rest */ - if (copy_in_user(&compat_fsqstat->qs_incoredqs, - &fsqstat->qs_incoredqs, - sizeof(struct compat_fs_quota_stat) - - offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || - get_user(xdata, &fsqstat->qs_iwarnlimit) || - put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) - break; - ret = 0; - break; - default: - ret = kernel_quotactl(cmd, special, id, addr); - } - return ret; -} diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 5444d3c4d93f3..9270174534fdc 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -194,6 +194,22 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src) dst->dqb_valid = QIF_ALL; } +/* + * This code works only for 32 bit quota tools over 64 bit x86 kernels + * and is necessary due to alignment problems. + */ +struct compat_if_dqblk { + compat_u64 dqb_bhardlimit; + compat_u64 dqb_bsoftlimit; + compat_u64 dqb_curspace; + compat_u64 dqb_ihardlimit; + compat_u64 dqb_isoftlimit; + compat_u64 dqb_curinodes; + compat_u64 dqb_btime; + compat_u64 dqb_itime; + compat_uint_t dqb_valid; +}; + static int quota_getquota(struct super_block *sb, int type, qid_t id, void __user *addr) { @@ -211,8 +227,19 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id, if (ret) return ret; copy_to_if_dqblk(&idq, &fdq); + +#ifdef CONFIG_IA32_EMULATION + if (in_ia32_syscall()) { + if (copy_to_user(addr, &idq, sizeof(struct compat_if_dqblk))) + return -EFAULT; + + return 0; + } +#endif + if (copy_to_user(addr, &idq, sizeof(idq))) return -EFAULT; + return 0; } @@ -277,6 +304,14 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id, struct if_dqblk idq; struct kqid qid; +#ifdef CONFIG_IA32_EMULATION + if (in_ia32_syscall()) { + if (copy_from_user(&idq, addr, sizeof(struct compat_if_dqblk))) + return -EFAULT; + + return 0; + } else +#endif if (copy_from_user(&idq, addr, sizeof(idq))) return -EFAULT; if (!sb->s_qcop->set_dqblk) @@ -382,6 +417,27 @@ static int quota_getstate(struct super_block *sb, int type, return 0; } +/* XFS structures */ +struct compat_fs_qfilestat { + compat_u64 qfs_ino; + compat_u64 qfs_nblks; + compat_uint_t qfs_nextents; +}; + +struct compat_fs_quota_stat { + __s8 qs_version; + __u16 qs_flags; + __s8 qs_pad; + struct compat_fs_qfilestat qs_uquota; + struct compat_fs_qfilestat qs_gquota; + compat_uint_t qs_incoredqs; + compat_int_t qs_btimelimit; + compat_int_t qs_itimelimit; + compat_int_t qs_rtbtimelimit; + __u16 qs_bwarnlimit; + __u16 qs_iwarnlimit; +}; + static int quota_getxstate(struct super_block *sb, int type, void __user *addr) { struct fs_quota_stat fqs; @@ -390,9 +446,48 @@ static int quota_getxstate(struct super_block *sb, int type, void __user *addr) if (!sb->s_qcop->get_state) return -ENOSYS; ret = quota_getstate(sb, type, &fqs); - if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) + if (ret) + return ret; + +#ifdef CONFIG_IA32_EMULATION + if (in_ia32_syscall()) { + struct compat_fs_quota_stat cfqs; + + memset(&cfqs, 0, sizeof(cfqs)); + + cfqs = (struct compat_fs_quota_stat) { + .qs_version = fqs.qs_version, + .qs_flags = fqs.qs_flags, + .qs_pad = fqs.qs_pad, + .qs_uquota = { + .qfs_ino = fqs.qs_uquota.qfs_ino, + .qfs_nblks = fqs.qs_uquota.qfs_nblks, + .qfs_nextents = fqs.qs_uquota.qfs_nextents, + }, + .qs_gquota = { + .qfs_ino = fqs.qs_gquota.qfs_ino, + .qfs_nblks = fqs.qs_gquota.qfs_nblks, + .qfs_nextents = fqs.qs_gquota.qfs_nextents, + }, + .qs_incoredqs = fqs.qs_incoredqs, + .qs_btimelimit = fqs.qs_btimelimit, + .qs_itimelimit = fqs.qs_itimelimit, + .qs_rtbtimelimit = fqs.qs_rtbtimelimit, + .qs_bwarnlimit = fqs.qs_bwarnlimit, + .qs_iwarnlimit = fqs.qs_iwarnlimit, + }; + + if (copy_to_user(addr, &cfqs, sizeof(cfqs))) + return -EFAULT; + + return 0; + } +#endif + + if (copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; - return ret; + + return 0; } static int quota_getstatev(struct super_block *sb, int type, diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 4d59775ea79c1..c925d1e1777ef 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -369,7 +369,6 @@ COND_SYSCALL_COMPAT(fanotify_mark); /* x86 */ COND_SYSCALL(vm86old); COND_SYSCALL(modify_ldt); -COND_SYSCALL_COMPAT(quotactl32); COND_SYSCALL(vm86); COND_SYSCALL(kexec_file_load); |
