Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Quota code necessary even when VFS quota support is not compiled
4 : : * into the kernel. The interesting stuff is over in dquot.c, here
5 : : * we have symbols for initial quotactl(2) handling, the sysctl(2)
6 : : * variables, etc - things needed even when quota support disabled.
7 : : */
8 : :
9 : : #include <linux/fs.h>
10 : : #include <linux/namei.h>
11 : : #include <linux/slab.h>
12 : : #include <asm/current.h>
13 : : #include <linux/uaccess.h>
14 : : #include <linux/kernel.h>
15 : : #include <linux/security.h>
16 : : #include <linux/syscalls.h>
17 : : #include <linux/capability.h>
18 : : #include <linux/quotaops.h>
19 : : #include <linux/types.h>
20 : : #include <linux/writeback.h>
21 : : #include <linux/nospec.h>
22 : :
23 : 0 : static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
24 : : qid_t id)
25 : : {
26 : 0 : switch (cmd) {
27 : : /* these commands do not require any special privilegues */
28 : : case Q_GETFMT:
29 : : case Q_SYNC:
30 : : case Q_GETINFO:
31 : : case Q_XGETQSTAT:
32 : : case Q_XGETQSTATV:
33 : : case Q_XQUOTASYNC:
34 : : break;
35 : : /* allow to query information for dquots we "own" */
36 : : case Q_GETQUOTA:
37 : : case Q_XGETQUOTA:
38 : 0 : if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
39 : 0 : (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
40 : : break;
41 : : /*FALLTHROUGH*/
42 : : default:
43 : 0 : if (!capable(CAP_SYS_ADMIN))
44 : : return -EPERM;
45 : : }
46 : :
47 : 0 : return security_quotactl(cmd, type, id, sb);
48 : : }
49 : :
50 : 0 : static void quota_sync_one(struct super_block *sb, void *arg)
51 : : {
52 : 0 : int type = *(int *)arg;
53 : :
54 : 0 : if (sb->s_qcop && sb->s_qcop->quota_sync &&
55 : 0 : (sb->s_quota_types & (1 << type)))
56 : 0 : sb->s_qcop->quota_sync(sb, type);
57 : 0 : }
58 : :
59 : 0 : static int quota_sync_all(int type)
60 : : {
61 : : int ret;
62 : :
63 : 0 : if (type >= MAXQUOTAS)
64 : : return -EINVAL;
65 : 0 : ret = security_quotactl(Q_SYNC, type, 0, NULL);
66 : 0 : if (!ret)
67 : 0 : iterate_supers(quota_sync_one, &type);
68 : 0 : return ret;
69 : : }
70 : :
71 : 0 : unsigned int qtype_enforce_flag(int type)
72 : : {
73 : : switch (type) {
74 : : case USRQUOTA:
75 : : return FS_QUOTA_UDQ_ENFD;
76 : : case GRPQUOTA:
77 : : return FS_QUOTA_GDQ_ENFD;
78 : : case PRJQUOTA:
79 : : return FS_QUOTA_PDQ_ENFD;
80 : : }
81 : : return 0;
82 : : }
83 : :
84 : 0 : static int quota_quotaon(struct super_block *sb, int type, qid_t id,
85 : : const struct path *path)
86 : : {
87 : 0 : if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable)
88 : : return -ENOSYS;
89 : 0 : if (sb->s_qcop->quota_enable)
90 : 0 : return sb->s_qcop->quota_enable(sb, qtype_enforce_flag(type));
91 : 0 : if (IS_ERR(path))
92 : 0 : return PTR_ERR(path);
93 : 0 : return sb->s_qcop->quota_on(sb, type, id, path);
94 : : }
95 : :
96 : 0 : static int quota_quotaoff(struct super_block *sb, int type)
97 : : {
98 : 0 : if (!sb->s_qcop->quota_off && !sb->s_qcop->quota_disable)
99 : : return -ENOSYS;
100 : 0 : if (sb->s_qcop->quota_disable)
101 : 0 : return sb->s_qcop->quota_disable(sb, qtype_enforce_flag(type));
102 : 0 : return sb->s_qcop->quota_off(sb, type);
103 : : }
104 : :
105 : 0 : static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
106 : : {
107 : : __u32 fmt;
108 : :
109 : 0 : if (!sb_has_quota_active(sb, type))
110 : : return -ESRCH;
111 : 0 : fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
112 : 0 : if (copy_to_user(addr, &fmt, sizeof(fmt)))
113 : : return -EFAULT;
114 : 0 : return 0;
115 : : }
116 : :
117 : 0 : static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
118 : : {
119 : : struct qc_state state;
120 : : struct qc_type_state *tstate;
121 : : struct if_dqinfo uinfo;
122 : : int ret;
123 : :
124 : 0 : if (!sb->s_qcop->get_state)
125 : : return -ENOSYS;
126 : 0 : ret = sb->s_qcop->get_state(sb, &state);
127 : 0 : if (ret)
128 : : return ret;
129 : 0 : tstate = state.s_state + type;
130 : 0 : if (!(tstate->flags & QCI_ACCT_ENABLED))
131 : : return -ESRCH;
132 : 0 : memset(&uinfo, 0, sizeof(uinfo));
133 : 0 : uinfo.dqi_bgrace = tstate->spc_timelimit;
134 : 0 : uinfo.dqi_igrace = tstate->ino_timelimit;
135 : 0 : if (tstate->flags & QCI_SYSFILE)
136 : 0 : uinfo.dqi_flags |= DQF_SYS_FILE;
137 : 0 : if (tstate->flags & QCI_ROOT_SQUASH)
138 : 0 : uinfo.dqi_flags |= DQF_ROOT_SQUASH;
139 : 0 : uinfo.dqi_valid = IIF_ALL;
140 : 0 : if (copy_to_user(addr, &uinfo, sizeof(uinfo)))
141 : : return -EFAULT;
142 : 0 : return 0;
143 : : }
144 : :
145 : 0 : static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
146 : : {
147 : : struct if_dqinfo info;
148 : : struct qc_info qinfo;
149 : :
150 : 0 : if (copy_from_user(&info, addr, sizeof(info)))
151 : : return -EFAULT;
152 : 0 : if (!sb->s_qcop->set_info)
153 : : return -ENOSYS;
154 : 0 : if (info.dqi_valid & ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE))
155 : : return -EINVAL;
156 : 0 : memset(&qinfo, 0, sizeof(qinfo));
157 : 0 : if (info.dqi_valid & IIF_FLAGS) {
158 : 0 : if (info.dqi_flags & ~DQF_SETINFO_MASK)
159 : : return -EINVAL;
160 : 0 : if (info.dqi_flags & DQF_ROOT_SQUASH)
161 : 0 : qinfo.i_flags |= QCI_ROOT_SQUASH;
162 : 0 : qinfo.i_fieldmask |= QC_FLAGS;
163 : : }
164 : 0 : if (info.dqi_valid & IIF_BGRACE) {
165 : 0 : qinfo.i_spc_timelimit = info.dqi_bgrace;
166 : 0 : qinfo.i_fieldmask |= QC_SPC_TIMER;
167 : : }
168 : 0 : if (info.dqi_valid & IIF_IGRACE) {
169 : 0 : qinfo.i_ino_timelimit = info.dqi_igrace;
170 : 0 : qinfo.i_fieldmask |= QC_INO_TIMER;
171 : : }
172 : 0 : return sb->s_qcop->set_info(sb, type, &qinfo);
173 : : }
174 : :
175 : : static inline qsize_t qbtos(qsize_t blocks)
176 : : {
177 : 0 : return blocks << QIF_DQBLKSIZE_BITS;
178 : : }
179 : :
180 : : static inline qsize_t stoqb(qsize_t space)
181 : : {
182 : 0 : return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
183 : : }
184 : :
185 : 0 : static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
186 : : {
187 : 0 : memset(dst, 0, sizeof(*dst));
188 : 0 : dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
189 : 0 : dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
190 : 0 : dst->dqb_curspace = src->d_space;
191 : 0 : dst->dqb_ihardlimit = src->d_ino_hardlimit;
192 : 0 : dst->dqb_isoftlimit = src->d_ino_softlimit;
193 : 0 : dst->dqb_curinodes = src->d_ino_count;
194 : 0 : dst->dqb_btime = src->d_spc_timer;
195 : 0 : dst->dqb_itime = src->d_ino_timer;
196 : 0 : dst->dqb_valid = QIF_ALL;
197 : 0 : }
198 : :
199 : 0 : static int quota_getquota(struct super_block *sb, int type, qid_t id,
200 : : void __user *addr)
201 : : {
202 : : struct kqid qid;
203 : : struct qc_dqblk fdq;
204 : : struct if_dqblk idq;
205 : : int ret;
206 : :
207 : 0 : if (!sb->s_qcop->get_dqblk)
208 : : return -ENOSYS;
209 : 0 : qid = make_kqid(current_user_ns(), type, id);
210 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
211 : : return -EINVAL;
212 : 0 : ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
213 : 0 : if (ret)
214 : : return ret;
215 : 0 : copy_to_if_dqblk(&idq, &fdq);
216 : 0 : if (copy_to_user(addr, &idq, sizeof(idq)))
217 : : return -EFAULT;
218 : 0 : return 0;
219 : : }
220 : :
221 : : /*
222 : : * Return quota for next active quota >= this id, if any exists,
223 : : * otherwise return -ENOENT via ->get_nextdqblk
224 : : */
225 : 0 : static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
226 : : void __user *addr)
227 : : {
228 : : struct kqid qid;
229 : : struct qc_dqblk fdq;
230 : : struct if_nextdqblk idq;
231 : : int ret;
232 : :
233 : 0 : if (!sb->s_qcop->get_nextdqblk)
234 : : return -ENOSYS;
235 : 0 : qid = make_kqid(current_user_ns(), type, id);
236 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
237 : : return -EINVAL;
238 : 0 : ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
239 : 0 : if (ret)
240 : : return ret;
241 : : /* struct if_nextdqblk is a superset of struct if_dqblk */
242 : 0 : copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
243 : 0 : idq.dqb_id = from_kqid(current_user_ns(), qid);
244 : 0 : if (copy_to_user(addr, &idq, sizeof(idq)))
245 : : return -EFAULT;
246 : 0 : return 0;
247 : : }
248 : :
249 : 0 : static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
250 : : {
251 : 0 : dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
252 : 0 : dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
253 : 0 : dst->d_space = src->dqb_curspace;
254 : 0 : dst->d_ino_hardlimit = src->dqb_ihardlimit;
255 : 0 : dst->d_ino_softlimit = src->dqb_isoftlimit;
256 : 0 : dst->d_ino_count = src->dqb_curinodes;
257 : 0 : dst->d_spc_timer = src->dqb_btime;
258 : 0 : dst->d_ino_timer = src->dqb_itime;
259 : :
260 : 0 : dst->d_fieldmask = 0;
261 : 0 : if (src->dqb_valid & QIF_BLIMITS)
262 : 0 : dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
263 : 0 : if (src->dqb_valid & QIF_SPACE)
264 : 0 : dst->d_fieldmask |= QC_SPACE;
265 : 0 : if (src->dqb_valid & QIF_ILIMITS)
266 : 0 : dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
267 : 0 : if (src->dqb_valid & QIF_INODES)
268 : 0 : dst->d_fieldmask |= QC_INO_COUNT;
269 : 0 : if (src->dqb_valid & QIF_BTIME)
270 : 0 : dst->d_fieldmask |= QC_SPC_TIMER;
271 : 0 : if (src->dqb_valid & QIF_ITIME)
272 : 0 : dst->d_fieldmask |= QC_INO_TIMER;
273 : 0 : }
274 : :
275 : 0 : static int quota_setquota(struct super_block *sb, int type, qid_t id,
276 : : void __user *addr)
277 : : {
278 : : struct qc_dqblk fdq;
279 : : struct if_dqblk idq;
280 : : struct kqid qid;
281 : :
282 : 0 : if (copy_from_user(&idq, addr, sizeof(idq)))
283 : : return -EFAULT;
284 : 0 : if (!sb->s_qcop->set_dqblk)
285 : : return -ENOSYS;
286 : 0 : qid = make_kqid(current_user_ns(), type, id);
287 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
288 : : return -EINVAL;
289 : 0 : copy_from_if_dqblk(&fdq, &idq);
290 : 0 : return sb->s_qcop->set_dqblk(sb, qid, &fdq);
291 : : }
292 : :
293 : 0 : static int quota_enable(struct super_block *sb, void __user *addr)
294 : : {
295 : : __u32 flags;
296 : :
297 : 0 : if (copy_from_user(&flags, addr, sizeof(flags)))
298 : : return -EFAULT;
299 : 0 : if (!sb->s_qcop->quota_enable)
300 : : return -ENOSYS;
301 : 0 : return sb->s_qcop->quota_enable(sb, flags);
302 : : }
303 : :
304 : 0 : static int quota_disable(struct super_block *sb, void __user *addr)
305 : : {
306 : : __u32 flags;
307 : :
308 : 0 : if (copy_from_user(&flags, addr, sizeof(flags)))
309 : : return -EFAULT;
310 : 0 : if (!sb->s_qcop->quota_disable)
311 : : return -ENOSYS;
312 : 0 : return sb->s_qcop->quota_disable(sb, flags);
313 : : }
314 : :
315 : 0 : static int quota_state_to_flags(struct qc_state *state)
316 : : {
317 : : int flags = 0;
318 : :
319 : 0 : if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED)
320 : : flags |= FS_QUOTA_UDQ_ACCT;
321 : 0 : if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED)
322 : 0 : flags |= FS_QUOTA_UDQ_ENFD;
323 : 0 : if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)
324 : 0 : flags |= FS_QUOTA_GDQ_ACCT;
325 : 0 : if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED)
326 : 0 : flags |= FS_QUOTA_GDQ_ENFD;
327 : 0 : if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED)
328 : 0 : flags |= FS_QUOTA_PDQ_ACCT;
329 : 0 : if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED)
330 : 0 : flags |= FS_QUOTA_PDQ_ENFD;
331 : 0 : return flags;
332 : : }
333 : :
334 : 0 : static int quota_getstate(struct super_block *sb, int type,
335 : : struct fs_quota_stat *fqs)
336 : : {
337 : : struct qc_state state;
338 : : int ret;
339 : :
340 : 0 : memset(&state, 0, sizeof (struct qc_state));
341 : 0 : ret = sb->s_qcop->get_state(sb, &state);
342 : 0 : if (ret < 0)
343 : : return ret;
344 : :
345 : 0 : memset(fqs, 0, sizeof(*fqs));
346 : 0 : fqs->qs_version = FS_QSTAT_VERSION;
347 : 0 : fqs->qs_flags = quota_state_to_flags(&state);
348 : : /* No quota enabled? */
349 : 0 : if (!fqs->qs_flags)
350 : : return -ENOSYS;
351 : 0 : fqs->qs_incoredqs = state.s_incoredqs;
352 : :
353 : 0 : fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
354 : 0 : fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
355 : 0 : fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
356 : 0 : fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
357 : 0 : fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
358 : :
359 : : /* Inodes may be allocated even if inactive; copy out if present */
360 : 0 : if (state.s_state[USRQUOTA].ino) {
361 : 0 : fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
362 : 0 : fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
363 : 0 : fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
364 : : }
365 : 0 : if (state.s_state[GRPQUOTA].ino) {
366 : 0 : fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
367 : 0 : fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
368 : 0 : fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
369 : : }
370 : 0 : if (state.s_state[PRJQUOTA].ino) {
371 : : /*
372 : : * Q_XGETQSTAT doesn't have room for both group and project
373 : : * quotas. So, allow the project quota values to be copied out
374 : : * only if there is no group quota information available.
375 : : */
376 : 0 : if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) {
377 : 0 : fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino;
378 : 0 : fqs->qs_gquota.qfs_nblks =
379 : 0 : state.s_state[PRJQUOTA].blocks;
380 : 0 : fqs->qs_gquota.qfs_nextents =
381 : 0 : state.s_state[PRJQUOTA].nextents;
382 : : }
383 : : }
384 : : return 0;
385 : : }
386 : :
387 : 0 : static int quota_getxstate(struct super_block *sb, int type, void __user *addr)
388 : : {
389 : : struct fs_quota_stat fqs;
390 : : int ret;
391 : :
392 : 0 : if (!sb->s_qcop->get_state)
393 : : return -ENOSYS;
394 : 0 : ret = quota_getstate(sb, type, &fqs);
395 : 0 : if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
396 : : return -EFAULT;
397 : 0 : return ret;
398 : : }
399 : :
400 : 0 : static int quota_getstatev(struct super_block *sb, int type,
401 : : struct fs_quota_statv *fqs)
402 : : {
403 : : struct qc_state state;
404 : : int ret;
405 : :
406 : 0 : memset(&state, 0, sizeof (struct qc_state));
407 : 0 : ret = sb->s_qcop->get_state(sb, &state);
408 : 0 : if (ret < 0)
409 : : return ret;
410 : :
411 : 0 : memset(fqs, 0, sizeof(*fqs));
412 : 0 : fqs->qs_version = FS_QSTAT_VERSION;
413 : 0 : fqs->qs_flags = quota_state_to_flags(&state);
414 : : /* No quota enabled? */
415 : 0 : if (!fqs->qs_flags)
416 : : return -ENOSYS;
417 : 0 : fqs->qs_incoredqs = state.s_incoredqs;
418 : :
419 : 0 : fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
420 : 0 : fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
421 : 0 : fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
422 : 0 : fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
423 : 0 : fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
424 : :
425 : : /* Inodes may be allocated even if inactive; copy out if present */
426 : 0 : if (state.s_state[USRQUOTA].ino) {
427 : 0 : fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
428 : 0 : fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
429 : 0 : fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
430 : : }
431 : 0 : if (state.s_state[GRPQUOTA].ino) {
432 : 0 : fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
433 : 0 : fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
434 : 0 : fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
435 : : }
436 : 0 : if (state.s_state[PRJQUOTA].ino) {
437 : 0 : fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino;
438 : 0 : fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks;
439 : 0 : fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents;
440 : : }
441 : : return 0;
442 : : }
443 : :
444 : 0 : static int quota_getxstatev(struct super_block *sb, int type, void __user *addr)
445 : : {
446 : : struct fs_quota_statv fqs;
447 : : int ret;
448 : :
449 : 0 : if (!sb->s_qcop->get_state)
450 : : return -ENOSYS;
451 : :
452 : 0 : memset(&fqs, 0, sizeof(fqs));
453 : 0 : if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
454 : : return -EFAULT;
455 : :
456 : : /* If this kernel doesn't support user specified version, fail */
457 : 0 : switch (fqs.qs_version) {
458 : : case FS_QSTATV_VERSION1:
459 : : break;
460 : : default:
461 : : return -EINVAL;
462 : : }
463 : 0 : ret = quota_getstatev(sb, type, &fqs);
464 : 0 : if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
465 : : return -EFAULT;
466 : 0 : return ret;
467 : : }
468 : :
469 : : /*
470 : : * XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
471 : : * out of there as xfsprogs rely on definitions being in that header file. So
472 : : * just define same functions here for quota purposes.
473 : : */
474 : : #define XFS_BB_SHIFT 9
475 : :
476 : : static inline u64 quota_bbtob(u64 blocks)
477 : : {
478 : 0 : return blocks << XFS_BB_SHIFT;
479 : : }
480 : :
481 : : static inline u64 quota_btobb(u64 bytes)
482 : : {
483 : 0 : return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
484 : : }
485 : :
486 : 0 : static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
487 : : {
488 : 0 : dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
489 : 0 : dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
490 : 0 : dst->d_ino_hardlimit = src->d_ino_hardlimit;
491 : 0 : dst->d_ino_softlimit = src->d_ino_softlimit;
492 : 0 : dst->d_space = quota_bbtob(src->d_bcount);
493 : 0 : dst->d_ino_count = src->d_icount;
494 : 0 : dst->d_ino_timer = src->d_itimer;
495 : 0 : dst->d_spc_timer = src->d_btimer;
496 : 0 : dst->d_ino_warns = src->d_iwarns;
497 : 0 : dst->d_spc_warns = src->d_bwarns;
498 : 0 : dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
499 : 0 : dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
500 : 0 : dst->d_rt_space = quota_bbtob(src->d_rtbcount);
501 : 0 : dst->d_rt_spc_timer = src->d_rtbtimer;
502 : 0 : dst->d_rt_spc_warns = src->d_rtbwarns;
503 : 0 : dst->d_fieldmask = 0;
504 : 0 : if (src->d_fieldmask & FS_DQ_ISOFT)
505 : 0 : dst->d_fieldmask |= QC_INO_SOFT;
506 : 0 : if (src->d_fieldmask & FS_DQ_IHARD)
507 : 0 : dst->d_fieldmask |= QC_INO_HARD;
508 : 0 : if (src->d_fieldmask & FS_DQ_BSOFT)
509 : 0 : dst->d_fieldmask |= QC_SPC_SOFT;
510 : 0 : if (src->d_fieldmask & FS_DQ_BHARD)
511 : 0 : dst->d_fieldmask |= QC_SPC_HARD;
512 : 0 : if (src->d_fieldmask & FS_DQ_RTBSOFT)
513 : 0 : dst->d_fieldmask |= QC_RT_SPC_SOFT;
514 : 0 : if (src->d_fieldmask & FS_DQ_RTBHARD)
515 : 0 : dst->d_fieldmask |= QC_RT_SPC_HARD;
516 : 0 : if (src->d_fieldmask & FS_DQ_BTIMER)
517 : 0 : dst->d_fieldmask |= QC_SPC_TIMER;
518 : 0 : if (src->d_fieldmask & FS_DQ_ITIMER)
519 : 0 : dst->d_fieldmask |= QC_INO_TIMER;
520 : 0 : if (src->d_fieldmask & FS_DQ_RTBTIMER)
521 : 0 : dst->d_fieldmask |= QC_RT_SPC_TIMER;
522 : 0 : if (src->d_fieldmask & FS_DQ_BWARNS)
523 : 0 : dst->d_fieldmask |= QC_SPC_WARNS;
524 : 0 : if (src->d_fieldmask & FS_DQ_IWARNS)
525 : 0 : dst->d_fieldmask |= QC_INO_WARNS;
526 : 0 : if (src->d_fieldmask & FS_DQ_RTBWARNS)
527 : 0 : dst->d_fieldmask |= QC_RT_SPC_WARNS;
528 : 0 : if (src->d_fieldmask & FS_DQ_BCOUNT)
529 : 0 : dst->d_fieldmask |= QC_SPACE;
530 : 0 : if (src->d_fieldmask & FS_DQ_ICOUNT)
531 : 0 : dst->d_fieldmask |= QC_INO_COUNT;
532 : 0 : if (src->d_fieldmask & FS_DQ_RTBCOUNT)
533 : 0 : dst->d_fieldmask |= QC_RT_SPACE;
534 : 0 : }
535 : :
536 : 0 : static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst,
537 : : struct fs_disk_quota *src)
538 : : {
539 : 0 : memset(dst, 0, sizeof(*dst));
540 : 0 : dst->i_spc_timelimit = src->d_btimer;
541 : 0 : dst->i_ino_timelimit = src->d_itimer;
542 : 0 : dst->i_rt_spc_timelimit = src->d_rtbtimer;
543 : 0 : dst->i_ino_warnlimit = src->d_iwarns;
544 : 0 : dst->i_spc_warnlimit = src->d_bwarns;
545 : 0 : dst->i_rt_spc_warnlimit = src->d_rtbwarns;
546 : 0 : if (src->d_fieldmask & FS_DQ_BWARNS)
547 : 0 : dst->i_fieldmask |= QC_SPC_WARNS;
548 : 0 : if (src->d_fieldmask & FS_DQ_IWARNS)
549 : 0 : dst->i_fieldmask |= QC_INO_WARNS;
550 : 0 : if (src->d_fieldmask & FS_DQ_RTBWARNS)
551 : 0 : dst->i_fieldmask |= QC_RT_SPC_WARNS;
552 : 0 : if (src->d_fieldmask & FS_DQ_BTIMER)
553 : 0 : dst->i_fieldmask |= QC_SPC_TIMER;
554 : 0 : if (src->d_fieldmask & FS_DQ_ITIMER)
555 : 0 : dst->i_fieldmask |= QC_INO_TIMER;
556 : 0 : if (src->d_fieldmask & FS_DQ_RTBTIMER)
557 : 0 : dst->i_fieldmask |= QC_RT_SPC_TIMER;
558 : 0 : }
559 : :
560 : 0 : static int quota_setxquota(struct super_block *sb, int type, qid_t id,
561 : : void __user *addr)
562 : : {
563 : : struct fs_disk_quota fdq;
564 : : struct qc_dqblk qdq;
565 : : struct kqid qid;
566 : :
567 : 0 : if (copy_from_user(&fdq, addr, sizeof(fdq)))
568 : : return -EFAULT;
569 : 0 : if (!sb->s_qcop->set_dqblk)
570 : : return -ENOSYS;
571 : 0 : qid = make_kqid(current_user_ns(), type, id);
572 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
573 : : return -EINVAL;
574 : : /* Are we actually setting timer / warning limits for all users? */
575 : 0 : if (from_kqid(sb->s_user_ns, qid) == 0 &&
576 : 0 : fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) {
577 : : struct qc_info qinfo;
578 : : int ret;
579 : :
580 : 0 : if (!sb->s_qcop->set_info)
581 : 0 : return -EINVAL;
582 : 0 : copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq);
583 : 0 : ret = sb->s_qcop->set_info(sb, type, &qinfo);
584 : 0 : if (ret)
585 : : return ret;
586 : : /* These are already done */
587 : 0 : fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK);
588 : : }
589 : 0 : copy_from_xfs_dqblk(&qdq, &fdq);
590 : 0 : return sb->s_qcop->set_dqblk(sb, qid, &qdq);
591 : : }
592 : :
593 : 0 : static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
594 : : int type, qid_t id)
595 : : {
596 : 0 : memset(dst, 0, sizeof(*dst));
597 : 0 : dst->d_version = FS_DQUOT_VERSION;
598 : 0 : dst->d_id = id;
599 : 0 : if (type == USRQUOTA)
600 : 0 : dst->d_flags = FS_USER_QUOTA;
601 : 0 : else if (type == PRJQUOTA)
602 : 0 : dst->d_flags = FS_PROJ_QUOTA;
603 : : else
604 : 0 : dst->d_flags = FS_GROUP_QUOTA;
605 : 0 : dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
606 : 0 : dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
607 : 0 : dst->d_ino_hardlimit = src->d_ino_hardlimit;
608 : 0 : dst->d_ino_softlimit = src->d_ino_softlimit;
609 : 0 : dst->d_bcount = quota_btobb(src->d_space);
610 : 0 : dst->d_icount = src->d_ino_count;
611 : 0 : dst->d_itimer = src->d_ino_timer;
612 : 0 : dst->d_btimer = src->d_spc_timer;
613 : 0 : dst->d_iwarns = src->d_ino_warns;
614 : 0 : dst->d_bwarns = src->d_spc_warns;
615 : 0 : dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
616 : 0 : dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
617 : 0 : dst->d_rtbcount = quota_btobb(src->d_rt_space);
618 : 0 : dst->d_rtbtimer = src->d_rt_spc_timer;
619 : 0 : dst->d_rtbwarns = src->d_rt_spc_warns;
620 : 0 : }
621 : :
622 : 0 : static int quota_getxquota(struct super_block *sb, int type, qid_t id,
623 : : void __user *addr)
624 : : {
625 : : struct fs_disk_quota fdq;
626 : : struct qc_dqblk qdq;
627 : : struct kqid qid;
628 : : int ret;
629 : :
630 : 0 : if (!sb->s_qcop->get_dqblk)
631 : : return -ENOSYS;
632 : 0 : qid = make_kqid(current_user_ns(), type, id);
633 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
634 : : return -EINVAL;
635 : 0 : ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
636 : 0 : if (ret)
637 : : return ret;
638 : 0 : copy_to_xfs_dqblk(&fdq, &qdq, type, id);
639 : 0 : if (copy_to_user(addr, &fdq, sizeof(fdq)))
640 : : return -EFAULT;
641 : 0 : return ret;
642 : : }
643 : :
644 : : /*
645 : : * Return quota for next active quota >= this id, if any exists,
646 : : * otherwise return -ENOENT via ->get_nextdqblk.
647 : : */
648 : 0 : static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
649 : : void __user *addr)
650 : : {
651 : : struct fs_disk_quota fdq;
652 : : struct qc_dqblk qdq;
653 : : struct kqid qid;
654 : : qid_t id_out;
655 : : int ret;
656 : :
657 : 0 : if (!sb->s_qcop->get_nextdqblk)
658 : : return -ENOSYS;
659 : 0 : qid = make_kqid(current_user_ns(), type, id);
660 : 0 : if (!qid_has_mapping(sb->s_user_ns, qid))
661 : : return -EINVAL;
662 : 0 : ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq);
663 : 0 : if (ret)
664 : : return ret;
665 : 0 : id_out = from_kqid(current_user_ns(), qid);
666 : 0 : copy_to_xfs_dqblk(&fdq, &qdq, type, id_out);
667 : 0 : if (copy_to_user(addr, &fdq, sizeof(fdq)))
668 : : return -EFAULT;
669 : 0 : return ret;
670 : : }
671 : :
672 : 0 : static int quota_rmxquota(struct super_block *sb, void __user *addr)
673 : : {
674 : : __u32 flags;
675 : :
676 : 0 : if (copy_from_user(&flags, addr, sizeof(flags)))
677 : : return -EFAULT;
678 : 0 : if (!sb->s_qcop->rm_xquota)
679 : : return -ENOSYS;
680 : 0 : return sb->s_qcop->rm_xquota(sb, flags);
681 : : }
682 : :
683 : : /* Copy parameters and call proper function */
684 : 0 : static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
685 : : void __user *addr, const struct path *path)
686 : : {
687 : : int ret;
688 : :
689 : 0 : if (type >= MAXQUOTAS)
690 : : return -EINVAL;
691 : 0 : type = array_index_nospec(type, MAXQUOTAS);
692 : : /*
693 : : * Quota not supported on this fs? Check this before s_quota_types
694 : : * since they needn't be set if quota is not supported at all.
695 : : */
696 : 0 : if (!sb->s_qcop)
697 : : return -ENOSYS;
698 : 0 : if (!(sb->s_quota_types & (1 << type)))
699 : : return -EINVAL;
700 : :
701 : 0 : ret = check_quotactl_permission(sb, type, cmd, id);
702 : 0 : if (ret < 0)
703 : : return ret;
704 : :
705 : 0 : switch (cmd) {
706 : : case Q_QUOTAON:
707 : 0 : return quota_quotaon(sb, type, id, path);
708 : : case Q_QUOTAOFF:
709 : 0 : return quota_quotaoff(sb, type);
710 : : case Q_GETFMT:
711 : 0 : return quota_getfmt(sb, type, addr);
712 : : case Q_GETINFO:
713 : 0 : return quota_getinfo(sb, type, addr);
714 : : case Q_SETINFO:
715 : 0 : return quota_setinfo(sb, type, addr);
716 : : case Q_GETQUOTA:
717 : 0 : return quota_getquota(sb, type, id, addr);
718 : : case Q_GETNEXTQUOTA:
719 : 0 : return quota_getnextquota(sb, type, id, addr);
720 : : case Q_SETQUOTA:
721 : 0 : return quota_setquota(sb, type, id, addr);
722 : : case Q_SYNC:
723 : 0 : if (!sb->s_qcop->quota_sync)
724 : : return -ENOSYS;
725 : 0 : return sb->s_qcop->quota_sync(sb, type);
726 : : case Q_XQUOTAON:
727 : 0 : return quota_enable(sb, addr);
728 : : case Q_XQUOTAOFF:
729 : 0 : return quota_disable(sb, addr);
730 : : case Q_XQUOTARM:
731 : 0 : return quota_rmxquota(sb, addr);
732 : : case Q_XGETQSTAT:
733 : 0 : return quota_getxstate(sb, type, addr);
734 : : case Q_XGETQSTATV:
735 : 0 : return quota_getxstatev(sb, type, addr);
736 : : case Q_XSETQLIM:
737 : 0 : return quota_setxquota(sb, type, id, addr);
738 : : case Q_XGETQUOTA:
739 : 0 : return quota_getxquota(sb, type, id, addr);
740 : : case Q_XGETNEXTQUOTA:
741 : 0 : return quota_getnextxquota(sb, type, id, addr);
742 : : case Q_XQUOTASYNC:
743 : 0 : if (sb_rdonly(sb))
744 : : return -EROFS;
745 : : /* XFS quotas are fully coherent now, making this call a noop */
746 : 0 : return 0;
747 : : default:
748 : : return -EINVAL;
749 : : }
750 : : }
751 : :
752 : : #ifdef CONFIG_BLOCK
753 : :
754 : : /* Return 1 if 'cmd' will block on frozen filesystem */
755 : : static int quotactl_cmd_write(int cmd)
756 : : {
757 : : /*
758 : : * We cannot allow Q_GETQUOTA and Q_GETNEXTQUOTA without write access
759 : : * as dquot_acquire() may allocate space for new structure and OCFS2
760 : : * needs to increment on-disk use count.
761 : : */
762 : 0 : switch (cmd) {
763 : : case Q_GETFMT:
764 : : case Q_GETINFO:
765 : : case Q_SYNC:
766 : : case Q_XGETQSTAT:
767 : : case Q_XGETQSTATV:
768 : : case Q_XGETQUOTA:
769 : : case Q_XGETNEXTQUOTA:
770 : : case Q_XQUOTASYNC:
771 : : return 0;
772 : : }
773 : : return 1;
774 : : }
775 : : #endif /* CONFIG_BLOCK */
776 : :
777 : : /* Return true if quotactl command is manipulating quota on/off state */
778 : : static bool quotactl_cmd_onoff(int cmd)
779 : : {
780 : 0 : return (cmd == Q_QUOTAON) || (cmd == Q_QUOTAOFF) ||
781 : 0 : (cmd == Q_XQUOTAON) || (cmd == Q_XQUOTAOFF);
782 : : }
783 : :
784 : : /*
785 : : * look up a superblock on which quota ops will be performed
786 : : * - use the name of a block device to find the superblock thereon
787 : : */
788 : 0 : static struct super_block *quotactl_block(const char __user *special, int cmd)
789 : : {
790 : : #ifdef CONFIG_BLOCK
791 : : struct block_device *bdev;
792 : : struct super_block *sb;
793 : 0 : struct filename *tmp = getname(special);
794 : :
795 : 0 : if (IS_ERR(tmp))
796 : : return ERR_CAST(tmp);
797 : 0 : bdev = lookup_bdev(tmp->name);
798 : 0 : putname(tmp);
799 : 0 : if (IS_ERR(bdev))
800 : : return ERR_CAST(bdev);
801 : 0 : if (quotactl_cmd_onoff(cmd))
802 : 0 : sb = get_super_exclusive_thawed(bdev);
803 : 0 : else if (quotactl_cmd_write(cmd))
804 : 0 : sb = get_super_thawed(bdev);
805 : : else
806 : 0 : sb = get_super(bdev);
807 : 0 : bdput(bdev);
808 : 0 : if (!sb)
809 : : return ERR_PTR(-ENODEV);
810 : :
811 : 0 : return sb;
812 : : #else
813 : : return ERR_PTR(-ENODEV);
814 : : #endif
815 : : }
816 : :
817 : : /*
818 : : * This is the system call interface. This communicates with
819 : : * the user-level programs. Currently this only supports diskquota
820 : : * calls. Maybe we need to add the process quotas etc. in the future,
821 : : * but we probably should use rlimits for that.
822 : : */
823 : 0 : int kernel_quotactl(unsigned int cmd, const char __user *special,
824 : : qid_t id, void __user *addr)
825 : : {
826 : : uint cmds, type;
827 : : struct super_block *sb = NULL;
828 : : struct path path, *pathp = NULL;
829 : : int ret;
830 : :
831 : 0 : cmds = cmd >> SUBCMDSHIFT;
832 : 0 : type = cmd & SUBCMDMASK;
833 : :
834 : : /*
835 : : * As a special case Q_SYNC can be called without a specific device.
836 : : * It will iterate all superblocks that have quota enabled and call
837 : : * the sync action on each of them.
838 : : */
839 : 0 : if (!special) {
840 : 0 : if (cmds == Q_SYNC)
841 : 0 : return quota_sync_all(type);
842 : : return -ENODEV;
843 : : }
844 : :
845 : : /*
846 : : * Path for quotaon has to be resolved before grabbing superblock
847 : : * because that gets s_umount sem which is also possibly needed by path
848 : : * resolution (think about autofs) and thus deadlocks could arise.
849 : : */
850 : 0 : if (cmds == Q_QUOTAON) {
851 : : ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
852 : 0 : if (ret)
853 : : pathp = ERR_PTR(ret);
854 : : else
855 : : pathp = &path;
856 : : }
857 : :
858 : 0 : sb = quotactl_block(special, cmds);
859 : 0 : if (IS_ERR(sb)) {
860 : : ret = PTR_ERR(sb);
861 : 0 : goto out;
862 : : }
863 : :
864 : 0 : ret = do_quotactl(sb, type, cmds, id, addr, pathp);
865 : :
866 : 0 : if (!quotactl_cmd_onoff(cmds))
867 : 0 : drop_super(sb);
868 : : else
869 : 0 : drop_super_exclusive(sb);
870 : : out:
871 : 0 : if (pathp && !IS_ERR(pathp))
872 : 0 : path_put(pathp);
873 : 0 : return ret;
874 : : }
875 : :
876 : 0 : SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
877 : : qid_t, id, void __user *, addr)
878 : : {
879 : 0 : return kernel_quotactl(cmd, special, id, addr);
880 : : }
|