1
2
3
4
5
6
7
8#include <linux/fs.h>
9#include <linux/namei.h>
10#include <linux/slab.h>
11#include <asm/current.h>
12#include <linux/uaccess.h>
13#include <linux/kernel.h>
14#include <linux/security.h>
15#include <linux/syscalls.h>
16#include <linux/capability.h>
17#include <linux/quotaops.h>
18#include <linux/types.h>
19#include <linux/writeback.h>
20
21static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
22 qid_t id)
23{
24 switch (cmd) {
25
26 case Q_GETFMT:
27 case Q_SYNC:
28 case Q_GETINFO:
29 case Q_XGETQSTAT:
30 case Q_XGETQSTATV:
31 case Q_XQUOTASYNC:
32 break;
33
34 case Q_GETQUOTA:
35 case Q_XGETQUOTA:
36 if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
37 (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
38 break;
39
40 default:
41 if (!capable(CAP_SYS_ADMIN))
42 return -EPERM;
43 }
44
45 return security_quotactl(cmd, type, id, sb);
46}
47
48static void quota_sync_one(struct super_block *sb, void *arg)
49{
50 if (sb->s_qcop && sb->s_qcop->quota_sync)
51 sb->s_qcop->quota_sync(sb, *(int *)arg);
52}
53
54static int quota_sync_all(int type)
55{
56 int ret;
57
58 if (type >= MAXQUOTAS)
59 return -EINVAL;
60 ret = security_quotactl(Q_SYNC, type, 0, NULL);
61 if (!ret)
62 iterate_supers(quota_sync_one, &type);
63 return ret;
64}
65
66static int quota_quotaon(struct super_block *sb, int type, qid_t id,
67 struct path *path)
68{
69 if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
70 return -ENOSYS;
71 if (sb->s_qcop->quota_on_meta)
72 return sb->s_qcop->quota_on_meta(sb, type, id);
73 if (IS_ERR(path))
74 return PTR_ERR(path);
75 return sb->s_qcop->quota_on(sb, type, id, path);
76}
77
78static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
79{
80 __u32 fmt;
81
82 mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
83 if (!sb_has_quota_active(sb, type)) {
84 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
85 return -ESRCH;
86 }
87 fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
88 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
89 if (copy_to_user(addr, &fmt, sizeof(fmt)))
90 return -EFAULT;
91 return 0;
92}
93
94static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
95{
96 struct if_dqinfo info;
97 int ret;
98
99 if (!sb->s_qcop->get_info)
100 return -ENOSYS;
101 ret = sb->s_qcop->get_info(sb, type, &info);
102 if (!ret && copy_to_user(addr, &info, sizeof(info)))
103 return -EFAULT;
104 return ret;
105}
106
107static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
108{
109 struct if_dqinfo info;
110
111 if (copy_from_user(&info, addr, sizeof(info)))
112 return -EFAULT;
113 if (!sb->s_qcop->set_info)
114 return -ENOSYS;
115 return sb->s_qcop->set_info(sb, type, &info);
116}
117
118static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
119{
120 dst->dqb_bhardlimit = src->d_blk_hardlimit;
121 dst->dqb_bsoftlimit = src->d_blk_softlimit;
122 dst->dqb_curspace = src->d_bcount;
123 dst->dqb_ihardlimit = src->d_ino_hardlimit;
124 dst->dqb_isoftlimit = src->d_ino_softlimit;
125 dst->dqb_curinodes = src->d_icount;
126 dst->dqb_btime = src->d_btimer;
127 dst->dqb_itime = src->d_itimer;
128 dst->dqb_valid = QIF_ALL;
129}
130
131static int quota_getquota(struct super_block *sb, int type, qid_t id,
132 void __user *addr)
133{
134 struct kqid qid;
135 struct fs_disk_quota fdq;
136 struct if_dqblk idq;
137 int ret;
138
139 if (!sb->s_qcop->get_dqblk)
140 return -ENOSYS;
141 qid = make_kqid(current_user_ns(), type, id);
142 if (!qid_valid(qid))
143 return -EINVAL;
144 ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
145 if (ret)
146 return ret;
147 copy_to_if_dqblk(&idq, &fdq);
148 if (copy_to_user(addr, &idq, sizeof(idq)))
149 return -EFAULT;
150 return 0;
151}
152
153
154
155
156
157static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
158 void __user *addr)
159{
160 struct kqid qid;
161 struct fs_disk_quota fdq;
162 struct if_nextdqblk idq;
163 int ret;
164
165 if (!sb_has_nextdqblk(sb) || !sb->s_qcop->get_nextdqblk)
166 return -ENOSYS;
167 qid = make_kqid(current_user_ns(), type, id);
168 if (!qid_valid(qid))
169 return -EINVAL;
170 ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
171 if (ret)
172 return ret;
173
174 copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
175 idq.dqb_id = from_kqid(current_user_ns(), qid);
176 if (copy_to_user(addr, &idq, sizeof(idq)))
177 return -EFAULT;
178 return 0;
179}
180
181static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
182{
183 dst->d_blk_hardlimit = src->dqb_bhardlimit;
184 dst->d_blk_softlimit = src->dqb_bsoftlimit;
185 dst->d_bcount = src->dqb_curspace;
186 dst->d_ino_hardlimit = src->dqb_ihardlimit;
187 dst->d_ino_softlimit = src->dqb_isoftlimit;
188 dst->d_icount = src->dqb_curinodes;
189 dst->d_btimer = src->dqb_btime;
190 dst->d_itimer = src->dqb_itime;
191
192 dst->d_fieldmask = 0;
193 if (src->dqb_valid & QIF_BLIMITS)
194 dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
195 if (src->dqb_valid & QIF_SPACE)
196 dst->d_fieldmask |= FS_DQ_BCOUNT;
197 if (src->dqb_valid & QIF_ILIMITS)
198 dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD;
199 if (src->dqb_valid & QIF_INODES)
200 dst->d_fieldmask |= FS_DQ_ICOUNT;
201 if (src->dqb_valid & QIF_BTIME)
202 dst->d_fieldmask |= FS_DQ_BTIMER;
203 if (src->dqb_valid & QIF_ITIME)
204 dst->d_fieldmask |= FS_DQ_ITIMER;
205}
206
207static int quota_setquota(struct super_block *sb, int type, qid_t id,
208 void __user *addr)
209{
210 struct fs_disk_quota fdq;
211 struct if_dqblk idq;
212 struct kqid qid;
213
214 if (copy_from_user(&idq, addr, sizeof(idq)))
215 return -EFAULT;
216 if (!sb->s_qcop->set_dqblk)
217 return -ENOSYS;
218 qid = make_kqid(current_user_ns(), type, id);
219 if (!qid_valid(qid))
220 return -EINVAL;
221 copy_from_if_dqblk(&fdq, &idq);
222 return sb->s_qcop->set_dqblk(sb, qid, &fdq);
223}
224
225static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
226{
227 __u32 flags;
228
229 if (copy_from_user(&flags, addr, sizeof(flags)))
230 return -EFAULT;
231 if (!sb->s_qcop->set_xstate)
232 return -ENOSYS;
233 return sb->s_qcop->set_xstate(sb, flags, cmd);
234}
235
236static int quota_getxstate(struct super_block *sb, void __user *addr)
237{
238 struct fs_quota_stat fqs;
239 int ret;
240
241 if (!sb->s_qcop->get_xstate)
242 return -ENOSYS;
243 ret = sb->s_qcop->get_xstate(sb, &fqs);
244 if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
245 return -EFAULT;
246 return ret;
247}
248
249static int quota_getxstatev(struct super_block *sb, void __user *addr)
250{
251 struct fs_quota_statv fqs;
252 int ret;
253
254 if (!sb->s_qcop->get_xstatev)
255 return -ENOSYS;
256
257 memset(&fqs, 0, sizeof(fqs));
258 if (copy_from_user(&fqs, addr, 1))
259 return -EFAULT;
260
261
262 switch (fqs.qs_version) {
263 case FS_QSTATV_VERSION1:
264 break;
265 default:
266 return -EINVAL;
267 }
268 ret = sb->s_qcop->get_xstatev(sb, &fqs);
269 if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
270 return -EFAULT;
271 return ret;
272}
273
274static int quota_setxquota(struct super_block *sb, int type, qid_t id,
275 void __user *addr)
276{
277 struct fs_disk_quota fdq;
278 struct kqid qid;
279
280 if (copy_from_user(&fdq, addr, sizeof(fdq)))
281 return -EFAULT;
282 if (!sb->s_qcop->set_dqblk)
283 return -ENOSYS;
284 qid = make_kqid(current_user_ns(), type, id);
285 if (!qid_valid(qid))
286 return -EINVAL;
287 return sb->s_qcop->set_dqblk(sb, qid, &fdq);
288}
289
290static int quota_getxquota(struct super_block *sb, int type, qid_t id,
291 void __user *addr)
292{
293 struct fs_disk_quota fdq;
294 struct kqid qid;
295 int ret;
296
297 if (!sb->s_qcop->get_dqblk)
298 return -ENOSYS;
299 qid = make_kqid(current_user_ns(), type, id);
300 if (!qid_valid(qid))
301 return -EINVAL;
302 ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
303 if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
304 return -EFAULT;
305 return ret;
306}
307
308
309
310
311
312static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
313 void __user *addr)
314{
315 struct fs_disk_quota fdq;
316 struct kqid qid;
317 qid_t id_out;
318 int ret;
319
320 if (!sb_has_nextdqblk(sb) || !sb->s_qcop->get_nextdqblk)
321 return -ENOSYS;
322 qid = make_kqid(current_user_ns(), type, id);
323 if (!qid_valid(qid))
324 return -EINVAL;
325 ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
326 if (ret)
327 return ret;
328 id_out = from_kqid(current_user_ns(), qid);
329 fdq.d_id = id_out;
330 if (copy_to_user(addr, &fdq, sizeof(fdq)))
331 return -EFAULT;
332 return ret;
333}
334
335static int quota_rmxquota(struct super_block *sb, void __user *addr)
336{
337 __u32 flags;
338
339 if (copy_from_user(&flags, addr, sizeof(flags)))
340 return -EFAULT;
341 if (!sb_has_rm_xquota(sb) || !sb->s_qcop->rm_xquota)
342 return -ENOSYS;
343 return sb->s_qcop->rm_xquota(sb, flags);
344}
345
346
347static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
348 void __user *addr, struct path *path)
349{
350 int ret;
351
352 if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
353 return -EINVAL;
354 if (!sb->s_qcop)
355 return -ENOSYS;
356
357 ret = check_quotactl_permission(sb, type, cmd, id);
358 if (ret < 0)
359 return ret;
360
361 switch (cmd) {
362 case Q_QUOTAON:
363 return quota_quotaon(sb, type, id, path);
364 case Q_QUOTAOFF:
365 if (!sb->s_qcop->quota_off)
366 return -ENOSYS;
367 return sb->s_qcop->quota_off(sb, type);
368 case Q_GETFMT:
369 return quota_getfmt(sb, type, addr);
370 case Q_GETINFO:
371 return quota_getinfo(sb, type, addr);
372 case Q_SETINFO:
373 return quota_setinfo(sb, type, addr);
374 case Q_GETQUOTA:
375 return quota_getquota(sb, type, id, addr);
376 case Q_GETNEXTQUOTA:
377 return quota_getnextquota(sb, type, id, addr);
378 case Q_SETQUOTA:
379 return quota_setquota(sb, type, id, addr);
380 case Q_SYNC:
381 if (!sb->s_qcop->quota_sync)
382 return -ENOSYS;
383 return sb->s_qcop->quota_sync(sb, type);
384 case Q_XQUOTAON:
385 case Q_XQUOTAOFF:
386 return quota_setxstate(sb, cmd, addr);
387 case Q_XQUOTARM:
388 return quota_rmxquota(sb, addr);
389 case Q_XGETQSTAT:
390 return quota_getxstate(sb, addr);
391 case Q_XGETQSTATV:
392 return quota_getxstatev(sb, addr);
393 case Q_XSETQLIM:
394 return quota_setxquota(sb, type, id, addr);
395 case Q_XGETQUOTA:
396 return quota_getxquota(sb, type, id, addr);
397 case Q_XGETNEXTQUOTA:
398 return quota_getnextxquota(sb, type, id, addr);
399 case Q_XQUOTASYNC:
400 if (sb->s_flags & MS_RDONLY)
401 return -EROFS;
402
403 return 0;
404 default:
405 return -EINVAL;
406 }
407}
408
409#ifdef CONFIG_BLOCK
410
411
412static int quotactl_cmd_write(int cmd)
413{
414 switch (cmd) {
415 case Q_GETFMT:
416 case Q_GETINFO:
417 case Q_GETNEXTQUOTA:
418 case Q_SYNC:
419 case Q_XGETQSTAT:
420 case Q_XGETQSTATV:
421 case Q_XGETQUOTA:
422 case Q_XGETNEXTQUOTA:
423 case Q_XQUOTASYNC:
424 return 0;
425 }
426 return 1;
427}
428
429#endif
430
431
432
433
434
435static struct super_block *quotactl_block(const char __user *special, int cmd)
436{
437#ifdef CONFIG_BLOCK
438 struct block_device *bdev;
439 struct super_block *sb;
440 struct filename *tmp = getname(special);
441
442 if (IS_ERR(tmp))
443 return ERR_CAST(tmp);
444 bdev = lookup_bdev(tmp->name);
445 putname(tmp);
446 if (IS_ERR(bdev))
447 return ERR_CAST(bdev);
448 if (quotactl_cmd_write(cmd))
449 sb = get_super_thawed(bdev);
450 else
451 sb = get_super(bdev);
452 bdput(bdev);
453 if (!sb)
454 return ERR_PTR(-ENODEV);
455
456 return sb;
457#else
458 return ERR_PTR(-ENODEV);
459#endif
460}
461
462
463
464
465
466
467
468SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
469 qid_t, id, void __user *, addr)
470{
471 uint cmds, type;
472 struct super_block *sb = NULL;
473 struct path path, *pathp = NULL;
474 int ret;
475
476 cmds = cmd >> SUBCMDSHIFT;
477 type = cmd & SUBCMDMASK;
478
479
480
481
482
483
484 if (!special) {
485 if (cmds == Q_SYNC)
486 return quota_sync_all(type);
487 return -ENODEV;
488 }
489
490
491
492
493
494
495 if (cmds == Q_QUOTAON) {
496 ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
497 if (ret)
498 pathp = ERR_PTR(ret);
499 else
500 pathp = &path;
501 }
502
503 sb = quotactl_block(special, cmds);
504 if (IS_ERR(sb)) {
505 ret = PTR_ERR(sb);
506 goto out;
507 }
508
509 ret = do_quotactl(sb, type, cmds, id, addr, pathp);
510
511 drop_super(sb);
512out:
513 if (pathp && !IS_ERR(pathp))
514 path_put(pathp);
515 return ret;
516}
517