forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/fs/quota/quota.c
....@@ -19,6 +19,7 @@
1919 #include <linux/types.h>
2020 #include <linux/writeback.h>
2121 #include <linux/nospec.h>
22
+#include "compat.h"
2223
2324 static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
2425 qid_t id)
....@@ -38,7 +39,7 @@
3839 if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
3940 (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
4041 break;
41
- /*FALLTHROUGH*/
42
+ fallthrough;
4243 default:
4344 if (!capable(CAP_SYS_ADMIN))
4445 return -EPERM;
....@@ -60,8 +61,6 @@
6061 {
6162 int ret;
6263
63
- if (type >= MAXQUOTAS)
64
- return -EINVAL;
6564 ret = security_quotactl(Q_SYNC, type, 0, NULL);
6665 if (!ret)
6766 iterate_supers(quota_sync_one, &type);
....@@ -213,8 +212,18 @@
213212 if (ret)
214213 return ret;
215214 copy_to_if_dqblk(&idq, &fdq);
216
- if (copy_to_user(addr, &idq, sizeof(idq)))
217
- return -EFAULT;
215
+
216
+ if (compat_need_64bit_alignment_fixup()) {
217
+ struct compat_if_dqblk __user *compat_dqblk = addr;
218
+
219
+ if (copy_to_user(compat_dqblk, &idq, sizeof(*compat_dqblk)))
220
+ return -EFAULT;
221
+ if (put_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
222
+ return -EFAULT;
223
+ } else {
224
+ if (copy_to_user(addr, &idq, sizeof(idq)))
225
+ return -EFAULT;
226
+ }
218227 return 0;
219228 }
220229
....@@ -279,8 +288,16 @@
279288 struct if_dqblk idq;
280289 struct kqid qid;
281290
282
- if (copy_from_user(&idq, addr, sizeof(idq)))
283
- return -EFAULT;
291
+ if (compat_need_64bit_alignment_fixup()) {
292
+ struct compat_if_dqblk __user *compat_dqblk = addr;
293
+
294
+ if (copy_from_user(&idq, compat_dqblk, sizeof(*compat_dqblk)) ||
295
+ get_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
296
+ return -EFAULT;
297
+ } else {
298
+ if (copy_from_user(&idq, addr, sizeof(idq)))
299
+ return -EFAULT;
300
+ }
284301 if (!sb->s_qcop->set_dqblk)
285302 return -ENOSYS;
286303 qid = make_kqid(current_user_ns(), type, id);
....@@ -331,9 +348,9 @@
331348 return flags;
332349 }
333350
334
-static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs)
351
+static int quota_getstate(struct super_block *sb, int type,
352
+ struct fs_quota_stat *fqs)
335353 {
336
- int type;
337354 struct qc_state state;
338355 int ret;
339356
....@@ -349,14 +366,7 @@
349366 if (!fqs->qs_flags)
350367 return -ENOSYS;
351368 fqs->qs_incoredqs = state.s_incoredqs;
352
- /*
353
- * GETXSTATE quotactl has space for just one set of time limits so
354
- * report them for the first enabled quota type
355
- */
356
- for (type = 0; type < MAXQUOTAS; type++)
357
- if (state.s_state[type].flags & QCI_ACCT_ENABLED)
358
- break;
359
- BUG_ON(type == MAXQUOTAS);
369
+
360370 fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
361371 fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
362372 fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
....@@ -391,22 +401,54 @@
391401 return 0;
392402 }
393403
394
-static int quota_getxstate(struct super_block *sb, void __user *addr)
404
+static int compat_copy_fs_qfilestat(struct compat_fs_qfilestat __user *to,
405
+ struct fs_qfilestat *from)
406
+{
407
+ if (copy_to_user(to, from, sizeof(*to)) ||
408
+ put_user(from->qfs_nextents, &to->qfs_nextents))
409
+ return -EFAULT;
410
+ return 0;
411
+}
412
+
413
+static int compat_copy_fs_quota_stat(struct compat_fs_quota_stat __user *to,
414
+ struct fs_quota_stat *from)
415
+{
416
+ if (put_user(from->qs_version, &to->qs_version) ||
417
+ put_user(from->qs_flags, &to->qs_flags) ||
418
+ put_user(from->qs_pad, &to->qs_pad) ||
419
+ compat_copy_fs_qfilestat(&to->qs_uquota, &from->qs_uquota) ||
420
+ compat_copy_fs_qfilestat(&to->qs_gquota, &from->qs_gquota) ||
421
+ put_user(from->qs_incoredqs, &to->qs_incoredqs) ||
422
+ put_user(from->qs_btimelimit, &to->qs_btimelimit) ||
423
+ put_user(from->qs_itimelimit, &to->qs_itimelimit) ||
424
+ put_user(from->qs_rtbtimelimit, &to->qs_rtbtimelimit) ||
425
+ put_user(from->qs_bwarnlimit, &to->qs_bwarnlimit) ||
426
+ put_user(from->qs_iwarnlimit, &to->qs_iwarnlimit))
427
+ return -EFAULT;
428
+ return 0;
429
+}
430
+
431
+static int quota_getxstate(struct super_block *sb, int type, void __user *addr)
395432 {
396433 struct fs_quota_stat fqs;
397434 int ret;
398435
399436 if (!sb->s_qcop->get_state)
400437 return -ENOSYS;
401
- ret = quota_getstate(sb, &fqs);
402
- if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
438
+ ret = quota_getstate(sb, type, &fqs);
439
+ if (ret)
440
+ return ret;
441
+
442
+ if (compat_need_64bit_alignment_fixup())
443
+ return compat_copy_fs_quota_stat(addr, &fqs);
444
+ if (copy_to_user(addr, &fqs, sizeof(fqs)))
403445 return -EFAULT;
404
- return ret;
446
+ return 0;
405447 }
406448
407
-static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs)
449
+static int quota_getstatev(struct super_block *sb, int type,
450
+ struct fs_quota_statv *fqs)
408451 {
409
- int type;
410452 struct qc_state state;
411453 int ret;
412454
....@@ -422,14 +464,7 @@
422464 if (!fqs->qs_flags)
423465 return -ENOSYS;
424466 fqs->qs_incoredqs = state.s_incoredqs;
425
- /*
426
- * GETXSTATV quotactl has space for just one set of time limits so
427
- * report them for the first enabled quota type
428
- */
429
- for (type = 0; type < MAXQUOTAS; type++)
430
- if (state.s_state[type].flags & QCI_ACCT_ENABLED)
431
- break;
432
- BUG_ON(type == MAXQUOTAS);
467
+
433468 fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
434469 fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
435470 fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
....@@ -455,7 +490,7 @@
455490 return 0;
456491 }
457492
458
-static int quota_getxstatev(struct super_block *sb, void __user *addr)
493
+static int quota_getxstatev(struct super_block *sb, int type, void __user *addr)
459494 {
460495 struct fs_quota_statv fqs;
461496 int ret;
....@@ -474,7 +509,7 @@
474509 default:
475510 return -EINVAL;
476511 }
477
- ret = quota_getstatev(sb, &fqs);
512
+ ret = quota_getstatev(sb, type, &fqs);
478513 if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
479514 return -EFAULT;
480515 return ret;
....@@ -497,6 +532,14 @@
497532 return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
498533 }
499534
535
+static inline s64 copy_from_xfs_dqblk_ts(const struct fs_disk_quota *d,
536
+ __s32 timer, __s8 timer_hi)
537
+{
538
+ if (d->d_fieldmask & FS_DQ_BIGTIME)
539
+ return (u32)timer | (s64)timer_hi << 32;
540
+ return timer;
541
+}
542
+
500543 static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
501544 {
502545 dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
....@@ -505,14 +548,17 @@
505548 dst->d_ino_softlimit = src->d_ino_softlimit;
506549 dst->d_space = quota_bbtob(src->d_bcount);
507550 dst->d_ino_count = src->d_icount;
508
- dst->d_ino_timer = src->d_itimer;
509
- dst->d_spc_timer = src->d_btimer;
551
+ dst->d_ino_timer = copy_from_xfs_dqblk_ts(src, src->d_itimer,
552
+ src->d_itimer_hi);
553
+ dst->d_spc_timer = copy_from_xfs_dqblk_ts(src, src->d_btimer,
554
+ src->d_btimer_hi);
510555 dst->d_ino_warns = src->d_iwarns;
511556 dst->d_spc_warns = src->d_bwarns;
512557 dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
513558 dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
514559 dst->d_rt_space = quota_bbtob(src->d_rtbcount);
515
- dst->d_rt_spc_timer = src->d_rtbtimer;
560
+ dst->d_rt_spc_timer = copy_from_xfs_dqblk_ts(src, src->d_rtbtimer,
561
+ src->d_rtbtimer_hi);
516562 dst->d_rt_spc_warns = src->d_rtbwarns;
517563 dst->d_fieldmask = 0;
518564 if (src->d_fieldmask & FS_DQ_ISOFT)
....@@ -604,10 +650,26 @@
604650 return sb->s_qcop->set_dqblk(sb, qid, &qdq);
605651 }
606652
653
+static inline void copy_to_xfs_dqblk_ts(const struct fs_disk_quota *d,
654
+ __s32 *timer_lo, __s8 *timer_hi, s64 timer)
655
+{
656
+ *timer_lo = timer;
657
+ if (d->d_fieldmask & FS_DQ_BIGTIME)
658
+ *timer_hi = timer >> 32;
659
+}
660
+
661
+static inline bool want_bigtime(s64 timer)
662
+{
663
+ return timer > S32_MAX || timer < S32_MIN;
664
+}
665
+
607666 static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
608667 int type, qid_t id)
609668 {
610669 memset(dst, 0, sizeof(*dst));
670
+ if (want_bigtime(src->d_ino_timer) || want_bigtime(src->d_spc_timer) ||
671
+ want_bigtime(src->d_rt_spc_timer))
672
+ dst->d_fieldmask |= FS_DQ_BIGTIME;
611673 dst->d_version = FS_DQUOT_VERSION;
612674 dst->d_id = id;
613675 if (type == USRQUOTA)
....@@ -622,14 +684,17 @@
622684 dst->d_ino_softlimit = src->d_ino_softlimit;
623685 dst->d_bcount = quota_btobb(src->d_space);
624686 dst->d_icount = src->d_ino_count;
625
- dst->d_itimer = src->d_ino_timer;
626
- dst->d_btimer = src->d_spc_timer;
687
+ copy_to_xfs_dqblk_ts(dst, &dst->d_itimer, &dst->d_itimer_hi,
688
+ src->d_ino_timer);
689
+ copy_to_xfs_dqblk_ts(dst, &dst->d_btimer, &dst->d_btimer_hi,
690
+ src->d_spc_timer);
627691 dst->d_iwarns = src->d_ino_warns;
628692 dst->d_bwarns = src->d_spc_warns;
629693 dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
630694 dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
631695 dst->d_rtbcount = quota_btobb(src->d_rt_space);
632
- dst->d_rtbtimer = src->d_rt_spc_timer;
696
+ copy_to_xfs_dqblk_ts(dst, &dst->d_rtbtimer, &dst->d_rtbtimer_hi,
697
+ src->d_rt_spc_timer);
633698 dst->d_rtbwarns = src->d_rt_spc_warns;
634699 }
635700
....@@ -700,8 +765,6 @@
700765 {
701766 int ret;
702767
703
- if (type >= MAXQUOTAS)
704
- return -EINVAL;
705768 type = array_index_nospec(type, MAXQUOTAS);
706769 /*
707770 * Quota not supported on this fs? Check this before s_quota_types
....@@ -744,9 +807,9 @@
744807 case Q_XQUOTARM:
745808 return quota_rmxquota(sb, addr);
746809 case Q_XGETQSTAT:
747
- return quota_getxstate(sb, addr);
810
+ return quota_getxstate(sb, type, addr);
748811 case Q_XGETQSTATV:
749
- return quota_getxstatev(sb, addr);
812
+ return quota_getxstatev(sb, type, addr);
750813 case Q_XSETQLIM:
751814 return quota_setxquota(sb, type, id, addr);
752815 case Q_XGETQUOTA:
....@@ -834,8 +897,8 @@
834897 * calls. Maybe we need to add the process quotas etc. in the future,
835898 * but we probably should use rlimits for that.
836899 */
837
-int kernel_quotactl(unsigned int cmd, const char __user *special,
838
- qid_t id, void __user *addr)
900
+SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
901
+ qid_t, id, void __user *, addr)
839902 {
840903 uint cmds, type;
841904 struct super_block *sb = NULL;
....@@ -844,6 +907,9 @@
844907
845908 cmds = cmd >> SUBCMDSHIFT;
846909 type = cmd & SUBCMDMASK;
910
+
911
+ if (type >= MAXQUOTAS)
912
+ return -EINVAL;
847913
848914 /*
849915 * As a special case Q_SYNC can be called without a specific device.
....@@ -885,10 +951,4 @@
885951 if (pathp && !IS_ERR(pathp))
886952 path_put(pathp);
887953 return ret;
888
-}
889
-
890
-SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
891
- qid_t, id, void __user *, addr)
892
-{
893
- return kernel_quotactl(cmd, special, id, addr);
894954 }