Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'work.quota-compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull compat quotactl cleanups from Al Viro:
"More Christoph's compat cleanups: quotactl(2)"

* 'work.quota-compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
quota: simplify the quotactl compat handling
compat: add a compat_need_64bit_alignment_fixup() helper
compat: lift compat_s64 and compat_u64 to <asm-generic/compat.h>

+113 -159
-2
arch/arm64/include/asm/compat.h
··· 35 35 typedef u16 compat_ipc_pid_t; 36 36 typedef u32 compat_caddr_t; 37 37 typedef __kernel_fsid_t compat_fsid_t; 38 - typedef s64 compat_s64; 39 - typedef u64 compat_u64; 40 38 41 39 struct compat_stat { 42 40 #ifdef __AARCH64EB__
-2
arch/mips/include/asm/compat.h
··· 26 26 typedef struct { 27 27 s32 val[2]; 28 28 } compat_fsid_t; 29 - typedef s64 compat_s64; 30 - typedef u64 compat_u64; 31 29 32 30 struct compat_stat { 33 31 compat_dev_t st_dev;
-2
arch/parisc/include/asm/compat.h
··· 22 22 typedef u16 compat_nlink_t; 23 23 typedef u16 compat_ipc_pid_t; 24 24 typedef u32 compat_caddr_t; 25 - typedef s64 compat_s64; 26 - typedef u64 compat_u64; 27 25 28 26 struct compat_stat { 29 27 compat_dev_t st_dev; /* dev_t is 32 bits on parisc */
-2
arch/powerpc/include/asm/compat.h
··· 27 27 typedef u16 compat_ipc_pid_t; 28 28 typedef u32 compat_caddr_t; 29 29 typedef __kernel_fsid_t compat_fsid_t; 30 - typedef s64 compat_s64; 31 - typedef u64 compat_u64; 32 30 33 31 struct compat_stat { 34 32 compat_dev_t st_dev;
-2
arch/s390/include/asm/compat.h
··· 63 63 typedef u16 compat_ipc_pid_t; 64 64 typedef u32 compat_caddr_t; 65 65 typedef __kernel_fsid_t compat_fsid_t; 66 - typedef s64 compat_s64; 67 - typedef u64 compat_u64; 68 66 69 67 typedef struct { 70 68 u32 mask;
+1 -2
arch/sparc/include/asm/compat.h
··· 21 21 typedef u16 compat_ipc_pid_t; 22 22 typedef u32 compat_caddr_t; 23 23 typedef __kernel_fsid_t compat_fsid_t; 24 - typedef s64 compat_s64; 25 - typedef u64 compat_u64; 24 + 26 25 struct compat_stat { 27 26 compat_dev_t st_dev; 28 27 compat_ino_t st_ino;
+1 -1
arch/x86/entry/syscalls/syscall_32.tbl
··· 142 142 128 i386 init_module sys_init_module 143 143 129 i386 delete_module sys_delete_module 144 144 130 i386 get_kernel_syms 145 - 131 i386 quotactl sys_quotactl compat_sys_quotactl32 145 + 131 i386 quotactl sys_quotactl 146 146 132 i386 getpgid sys_getpgid 147 147 133 i386 fchdir sys_fchdir 148 148 134 i386 bdflush sys_bdflush
+1 -2
arch/x86/include/asm/compat.h
··· 27 27 typedef u16 compat_ipc_pid_t; 28 28 typedef u32 compat_caddr_t; 29 29 typedef __kernel_fsid_t compat_fsid_t; 30 - typedef s64 __attribute__((aligned(4))) compat_s64; 31 - typedef u64 __attribute__((aligned(4))) compat_u64; 32 30 33 31 struct compat_stat { 34 32 compat_dev_t st_dev; ··· 209 211 return in_32bit_syscall(); 210 212 } 211 213 #define in_compat_syscall in_compat_syscall /* override the generic impl */ 214 + #define compat_need_64bit_alignment_fixup in_ia32_syscall 212 215 #endif 213 216 214 217 struct compat_siginfo;
-5
fs/quota/Kconfig
··· 70 70 config QUOTACTL 71 71 bool 72 72 default n 73 - 74 - config QUOTACTL_COMPAT 75 - bool 76 - depends on QUOTACTL && COMPAT_FOR_U64_ALIGNMENT 77 - default y
-1
fs/quota/Makefile
··· 4 4 obj-$(CONFIG_QFMT_V2) += quota_v2.o 5 5 obj-$(CONFIG_QUOTA_TREE) += quota_tree.o 6 6 obj-$(CONFIG_QUOTACTL) += quota.o kqid.o 7 - obj-$(CONFIG_QUOTACTL_COMPAT) += compat.o 8 7 obj-$(CONFIG_QUOTA_NETLINK_INTERFACE) += netlink.o
-120
fs/quota/compat.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - 3 - #include <linux/syscalls.h> 4 - #include <linux/compat.h> 5 - #include <linux/quotaops.h> 6 - 7 - /* 8 - * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) 9 - * and is necessary due to alignment problems. 10 - */ 11 - struct compat_if_dqblk { 12 - compat_u64 dqb_bhardlimit; 13 - compat_u64 dqb_bsoftlimit; 14 - compat_u64 dqb_curspace; 15 - compat_u64 dqb_ihardlimit; 16 - compat_u64 dqb_isoftlimit; 17 - compat_u64 dqb_curinodes; 18 - compat_u64 dqb_btime; 19 - compat_u64 dqb_itime; 20 - compat_uint_t dqb_valid; 21 - }; 22 - 23 - /* XFS structures */ 24 - struct compat_fs_qfilestat { 25 - compat_u64 dqb_bhardlimit; 26 - compat_u64 qfs_nblks; 27 - compat_uint_t qfs_nextents; 28 - }; 29 - 30 - struct compat_fs_quota_stat { 31 - __s8 qs_version; 32 - __u16 qs_flags; 33 - __s8 qs_pad; 34 - struct compat_fs_qfilestat qs_uquota; 35 - struct compat_fs_qfilestat qs_gquota; 36 - compat_uint_t qs_incoredqs; 37 - compat_int_t qs_btimelimit; 38 - compat_int_t qs_itimelimit; 39 - compat_int_t qs_rtbtimelimit; 40 - __u16 qs_bwarnlimit; 41 - __u16 qs_iwarnlimit; 42 - }; 43 - 44 - COMPAT_SYSCALL_DEFINE4(quotactl32, unsigned int, cmd, 45 - const char __user *, special, qid_t, id, 46 - void __user *, addr) 47 - { 48 - unsigned int cmds; 49 - struct if_dqblk __user *dqblk; 50 - struct compat_if_dqblk __user *compat_dqblk; 51 - struct fs_quota_stat __user *fsqstat; 52 - struct compat_fs_quota_stat __user *compat_fsqstat; 53 - compat_uint_t data; 54 - u16 xdata; 55 - long ret; 56 - 57 - cmds = cmd >> SUBCMDSHIFT; 58 - 59 - switch (cmds) { 60 - case Q_GETQUOTA: 61 - dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 62 - compat_dqblk = addr; 63 - ret = kernel_quotactl(cmd, special, id, dqblk); 64 - if (ret) 65 - break; 66 - if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || 67 - get_user(data, &dqblk->dqb_valid) || 68 - put_user(data, &compat_dqblk->dqb_valid)) 69 - ret = -EFAULT; 70 - break; 71 - case Q_SETQUOTA: 72 - dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 73 - compat_dqblk = addr; 74 - ret = -EFAULT; 75 - if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || 76 - get_user(data, &compat_dqblk->dqb_valid) || 77 - put_user(data, &dqblk->dqb_valid)) 78 - break; 79 - ret = kernel_quotactl(cmd, special, id, dqblk); 80 - break; 81 - case Q_XGETQSTAT: 82 - fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); 83 - compat_fsqstat = addr; 84 - ret = kernel_quotactl(cmd, special, id, fsqstat); 85 - if (ret) 86 - break; 87 - ret = -EFAULT; 88 - /* Copying qs_version, qs_flags, qs_pad */ 89 - if (copy_in_user(compat_fsqstat, fsqstat, 90 - offsetof(struct compat_fs_quota_stat, qs_uquota))) 91 - break; 92 - /* Copying qs_uquota */ 93 - if (copy_in_user(&compat_fsqstat->qs_uquota, 94 - &fsqstat->qs_uquota, 95 - sizeof(compat_fsqstat->qs_uquota)) || 96 - get_user(data, &fsqstat->qs_uquota.qfs_nextents) || 97 - put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) 98 - break; 99 - /* Copying qs_gquota */ 100 - if (copy_in_user(&compat_fsqstat->qs_gquota, 101 - &fsqstat->qs_gquota, 102 - sizeof(compat_fsqstat->qs_gquota)) || 103 - get_user(data, &fsqstat->qs_gquota.qfs_nextents) || 104 - put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) 105 - break; 106 - /* Copying the rest */ 107 - if (copy_in_user(&compat_fsqstat->qs_incoredqs, 108 - &fsqstat->qs_incoredqs, 109 - sizeof(struct compat_fs_quota_stat) - 110 - offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || 111 - get_user(xdata, &fsqstat->qs_iwarnlimit) || 112 - put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) 113 - break; 114 - ret = 0; 115 - break; 116 - default: 117 - ret = kernel_quotactl(cmd, special, id, addr); 118 - } 119 - return ret; 120 - }
+34
fs/quota/compat.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/compat.h> 3 + 4 + struct compat_if_dqblk { 5 + compat_u64 dqb_bhardlimit; 6 + compat_u64 dqb_bsoftlimit; 7 + compat_u64 dqb_curspace; 8 + compat_u64 dqb_ihardlimit; 9 + compat_u64 dqb_isoftlimit; 10 + compat_u64 dqb_curinodes; 11 + compat_u64 dqb_btime; 12 + compat_u64 dqb_itime; 13 + compat_uint_t dqb_valid; 14 + }; 15 + 16 + struct compat_fs_qfilestat { 17 + compat_u64 dqb_bhardlimit; 18 + compat_u64 qfs_nblks; 19 + compat_uint_t qfs_nextents; 20 + }; 21 + 22 + struct compat_fs_quota_stat { 23 + __s8 qs_version; 24 + __u16 qs_flags; 25 + __s8 qs_pad; 26 + struct compat_fs_qfilestat qs_uquota; 27 + struct compat_fs_qfilestat qs_gquota; 28 + compat_uint_t qs_incoredqs; 29 + compat_int_t qs_btimelimit; 30 + compat_int_t qs_itimelimit; 31 + compat_int_t qs_rtbtimelimit; 32 + __u16 qs_bwarnlimit; 33 + __u16 qs_iwarnlimit; 34 + };
+59 -14
fs/quota/quota.c
··· 19 19 #include <linux/types.h> 20 20 #include <linux/writeback.h> 21 21 #include <linux/nospec.h> 22 + #include "compat.h" 22 23 23 24 static int check_quotactl_permission(struct super_block *sb, int type, int cmd, 24 25 qid_t id) ··· 212 211 if (ret) 213 212 return ret; 214 213 copy_to_if_dqblk(&idq, &fdq); 215 - if (copy_to_user(addr, &idq, sizeof(idq))) 216 - return -EFAULT; 214 + 215 + if (compat_need_64bit_alignment_fixup()) { 216 + struct compat_if_dqblk __user *compat_dqblk = addr; 217 + 218 + if (copy_to_user(compat_dqblk, &idq, sizeof(*compat_dqblk))) 219 + return -EFAULT; 220 + if (put_user(idq.dqb_valid, &compat_dqblk->dqb_valid)) 221 + return -EFAULT; 222 + } else { 223 + if (copy_to_user(addr, &idq, sizeof(idq))) 224 + return -EFAULT; 225 + } 217 226 return 0; 218 227 } 219 228 ··· 288 277 struct if_dqblk idq; 289 278 struct kqid qid; 290 279 291 - if (copy_from_user(&idq, addr, sizeof(idq))) 292 - return -EFAULT; 280 + if (compat_need_64bit_alignment_fixup()) { 281 + struct compat_if_dqblk __user *compat_dqblk = addr; 282 + 283 + if (copy_from_user(&idq, compat_dqblk, sizeof(*compat_dqblk)) || 284 + get_user(idq.dqb_valid, &compat_dqblk->dqb_valid)) 285 + return -EFAULT; 286 + } else { 287 + if (copy_from_user(&idq, addr, sizeof(idq))) 288 + return -EFAULT; 289 + } 293 290 if (!sb->s_qcop->set_dqblk) 294 291 return -ENOSYS; 295 292 qid = make_kqid(current_user_ns(), type, id); ··· 401 382 return 0; 402 383 } 403 384 385 + static int compat_copy_fs_qfilestat(struct compat_fs_qfilestat __user *to, 386 + struct fs_qfilestat *from) 387 + { 388 + if (copy_to_user(to, from, sizeof(*to)) || 389 + put_user(from->qfs_nextents, &to->qfs_nextents)) 390 + return -EFAULT; 391 + return 0; 392 + } 393 + 394 + static int compat_copy_fs_quota_stat(struct compat_fs_quota_stat __user *to, 395 + struct fs_quota_stat *from) 396 + { 397 + if (put_user(from->qs_version, &to->qs_version) || 398 + put_user(from->qs_flags, &to->qs_flags) || 399 + put_user(from->qs_pad, &to->qs_pad) || 400 + compat_copy_fs_qfilestat(&to->qs_uquota, &from->qs_uquota) || 401 + compat_copy_fs_qfilestat(&to->qs_gquota, &from->qs_gquota) || 402 + put_user(from->qs_incoredqs, &to->qs_incoredqs) || 403 + put_user(from->qs_btimelimit, &to->qs_btimelimit) || 404 + put_user(from->qs_itimelimit, &to->qs_itimelimit) || 405 + put_user(from->qs_rtbtimelimit, &to->qs_rtbtimelimit) || 406 + put_user(from->qs_bwarnlimit, &to->qs_bwarnlimit) || 407 + put_user(from->qs_iwarnlimit, &to->qs_iwarnlimit)) 408 + return -EFAULT; 409 + return 0; 410 + } 411 + 404 412 static int quota_getxstate(struct super_block *sb, int type, void __user *addr) 405 413 { 406 414 struct fs_quota_stat fqs; ··· 436 390 if (!sb->s_qcop->get_state) 437 391 return -ENOSYS; 438 392 ret = quota_getstate(sb, type, &fqs); 439 - if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) 393 + if (ret) 394 + return ret; 395 + 396 + if (compat_need_64bit_alignment_fixup()) 397 + return compat_copy_fs_quota_stat(addr, &fqs); 398 + if (copy_to_user(addr, &fqs, sizeof(fqs))) 440 399 return -EFAULT; 441 - return ret; 400 + return 0; 442 401 } 443 402 444 403 static int quota_getstatev(struct super_block *sb, int type, ··· 867 816 * calls. Maybe we need to add the process quotas etc. in the future, 868 817 * but we probably should use rlimits for that. 869 818 */ 870 - int kernel_quotactl(unsigned int cmd, const char __user *special, 871 - qid_t id, void __user *addr) 819 + SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, 820 + qid_t, id, void __user *, addr) 872 821 { 873 822 uint cmds, type; 874 823 struct super_block *sb = NULL; ··· 921 870 if (pathp && !IS_ERR(pathp)) 922 871 path_put(pathp); 923 872 return ret; 924 - } 925 - 926 - SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, 927 - qid_t, id, void __user *, addr) 928 - { 929 - return kernel_quotactl(cmd, special, id, addr); 930 873 }
+8
include/asm-generic/compat.h
··· 22 22 typedef u32 compat_uptr_t; 23 23 typedef u32 compat_aio_context_t; 24 24 25 + #ifdef CONFIG_COMPAT_FOR_U64_ALIGNMENT 26 + typedef s64 __attribute__((aligned(4))) compat_s64; 27 + typedef u64 __attribute__((aligned(4))) compat_u64; 28 + #else 29 + typedef s64 compat_s64; 30 + typedef u64 compat_u64; 31 + #endif 32 + 25 33 #endif
+9
include/linux/compat.h
··· 911 911 #endif /* CONFIG_COMPAT */ 912 912 913 913 /* 914 + * Some legacy ABIs like the i386 one use less than natural alignment for 64-bit 915 + * types, and will need special compat treatment for that. Most architectures 916 + * don't need that special handling even for compat syscalls. 917 + */ 918 + #ifndef compat_need_64bit_alignment_fixup 919 + #define compat_need_64bit_alignment_fixup() false 920 + #endif 921 + 922 + /* 914 923 * A pointer passed in from user mode. This should not 915 924 * be used for syscall parameters, just declare them 916 925 * as pointers because the syscall entry code will have
-3
include/linux/quotaops.h
··· 27 27 (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); 28 28 } 29 29 30 - int kernel_quotactl(unsigned int cmd, const char __user *special, 31 - qid_t id, void __user *addr); 32 - 33 30 #if defined(CONFIG_QUOTA) 34 31 35 32 #define quota_error(sb, fmt, args...) \
-1
kernel/sys_ni.c
··· 369 369 /* x86 */ 370 370 COND_SYSCALL(vm86old); 371 371 COND_SYSCALL(modify_ldt); 372 - COND_SYSCALL_COMPAT(quotactl32); 373 372 COND_SYSCALL(vm86); 374 373 COND_SYSCALL(kexec_file_load); 375 374