Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
5582c76f CH |
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 | ||
ab0d1e85 DB |
44 | COMPAT_SYSCALL_DEFINE4(quotactl32, unsigned int, cmd, |
45 | const char __user *, special, qid_t, id, | |
46 | void __user *, addr) | |
5582c76f CH |
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; | |
cb0b476a | 63 | ret = kernel_quotactl(cmd, special, id, dqblk); |
5582c76f CH |
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; | |
cb0b476a | 79 | ret = kernel_quotactl(cmd, special, id, dqblk); |
5582c76f CH |
80 | break; |
81 | case Q_XGETQSTAT: | |
82 | fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); | |
83 | compat_fsqstat = addr; | |
cb0b476a | 84 | ret = kernel_quotactl(cmd, special, id, fsqstat); |
5582c76f CH |
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: | |
cb0b476a | 117 | ret = kernel_quotactl(cmd, special, id, addr); |
5582c76f CH |
118 | } |
119 | return ret; | |
120 | } |