hc
2023-02-17 557c24d082b6ecb9bfe5407b77ae43fa7650a5dc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// 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;
}