1 2#include <linux/syscalls.h> 3#include <linux/compat.h> 4#include <linux/quotaops.h> 5 6/* 7 * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) 8 * and is necessary due to alignment problems. 9 */ 10struct compat_if_dqblk { 11 compat_u64 dqb_bhardlimit; 12 compat_u64 dqb_bsoftlimit; 13 compat_u64 dqb_curspace; 14 compat_u64 dqb_ihardlimit; 15 compat_u64 dqb_isoftlimit; 16 compat_u64 dqb_curinodes; 17 compat_u64 dqb_btime; 18 compat_u64 dqb_itime; 19 compat_uint_t dqb_valid; 20}; 21 22/* XFS structures */ 23struct compat_fs_qfilestat { 24 compat_u64 dqb_bhardlimit; 25 compat_u64 qfs_nblks; 26 compat_uint_t qfs_nextents; 27}; 28 29struct compat_fs_quota_stat { 30 __s8 qs_version; 31 __u16 qs_flags; 32 __s8 qs_pad; 33 struct compat_fs_qfilestat qs_uquota; 34 struct compat_fs_qfilestat qs_gquota; 35 compat_uint_t qs_incoredqs; 36 compat_int_t qs_btimelimit; 37 compat_int_t qs_itimelimit; 38 compat_int_t qs_rtbtimelimit; 39 __u16 qs_bwarnlimit; 40 __u16 qs_iwarnlimit; 41}; 42 43asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, 44 qid_t id, void __user *addr) 45{ 46 unsigned int cmds; 47 struct if_dqblk __user *dqblk; 48 struct compat_if_dqblk __user *compat_dqblk; 49 struct fs_quota_stat __user *fsqstat; 50 struct compat_fs_quota_stat __user *compat_fsqstat; 51 compat_uint_t data; 52 u16 xdata; 53 long ret; 54 55 cmds = cmd >> SUBCMDSHIFT; 56 57 switch (cmds) { 58 case Q_GETQUOTA: 59 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 60 compat_dqblk = addr; 61 ret = sys_quotactl(cmd, special, id, dqblk); 62 if (ret) 63 break; 64 if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || 65 get_user(data, &dqblk->dqb_valid) || 66 put_user(data, &compat_dqblk->dqb_valid)) 67 ret = -EFAULT; 68 break; 69 case Q_SETQUOTA: 70 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 71 compat_dqblk = addr; 72 ret = -EFAULT; 73 if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || 74 get_user(data, &compat_dqblk->dqb_valid) || 75 put_user(data, &dqblk->dqb_valid)) 76 break; 77 ret = sys_quotactl(cmd, special, id, dqblk); 78 break; 79 case Q_XGETQSTAT: 80 fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); 81 compat_fsqstat = addr; 82 ret = sys_quotactl(cmd, special, id, fsqstat); 83 if (ret) 84 break; 85 ret = -EFAULT; 86 /* Copying qs_version, qs_flags, qs_pad */ 87 if (copy_in_user(compat_fsqstat, fsqstat, 88 offsetof(struct compat_fs_quota_stat, qs_uquota))) 89 break; 90 /* Copying qs_uquota */ 91 if (copy_in_user(&compat_fsqstat->qs_uquota, 92 &fsqstat->qs_uquota, 93 sizeof(compat_fsqstat->qs_uquota)) || 94 get_user(data, &fsqstat->qs_uquota.qfs_nextents) || 95 put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) 96 break; 97 /* Copying qs_gquota */ 98 if (copy_in_user(&compat_fsqstat->qs_gquota, 99 &fsqstat->qs_gquota, 100 sizeof(compat_fsqstat->qs_gquota)) || 101 get_user(data, &fsqstat->qs_gquota.qfs_nextents) || 102 put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) 103 break; 104 /* Copying the rest */ 105 if (copy_in_user(&compat_fsqstat->qs_incoredqs, 106 &fsqstat->qs_incoredqs, 107 sizeof(struct compat_fs_quota_stat) - 108 offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || 109 get_user(xdata, &fsqstat->qs_iwarnlimit) || 110 put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) 111 break; 112 ret = 0; 113 break; 114 default: 115 ret = sys_quotactl(cmd, special, id, addr); 116 } 117 return ret; 118} 119