compat.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/syscalls.h>
  3. #include <linux/compat.h>
  4. #include <linux/quotaops.h>
  5. /*
  6. * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
  7. * and is necessary due to alignment problems.
  8. */
  9. struct compat_if_dqblk {
  10. compat_u64 dqb_bhardlimit;
  11. compat_u64 dqb_bsoftlimit;
  12. compat_u64 dqb_curspace;
  13. compat_u64 dqb_ihardlimit;
  14. compat_u64 dqb_isoftlimit;
  15. compat_u64 dqb_curinodes;
  16. compat_u64 dqb_btime;
  17. compat_u64 dqb_itime;
  18. compat_uint_t dqb_valid;
  19. };
  20. /* XFS structures */
  21. struct compat_fs_qfilestat {
  22. compat_u64 dqb_bhardlimit;
  23. compat_u64 qfs_nblks;
  24. compat_uint_t qfs_nextents;
  25. };
  26. struct compat_fs_quota_stat {
  27. __s8 qs_version;
  28. __u16 qs_flags;
  29. __s8 qs_pad;
  30. struct compat_fs_qfilestat qs_uquota;
  31. struct compat_fs_qfilestat qs_gquota;
  32. compat_uint_t qs_incoredqs;
  33. compat_int_t qs_btimelimit;
  34. compat_int_t qs_itimelimit;
  35. compat_int_t qs_rtbtimelimit;
  36. __u16 qs_bwarnlimit;
  37. __u16 qs_iwarnlimit;
  38. };
  39. COMPAT_SYSCALL_DEFINE4(quotactl32, unsigned int, cmd,
  40. const char __user *, special, qid_t, id,
  41. void __user *, addr)
  42. {
  43. unsigned int cmds;
  44. struct if_dqblk __user *dqblk;
  45. struct compat_if_dqblk __user *compat_dqblk;
  46. struct fs_quota_stat __user *fsqstat;
  47. struct compat_fs_quota_stat __user *compat_fsqstat;
  48. compat_uint_t data;
  49. u16 xdata;
  50. long ret;
  51. cmds = cmd >> SUBCMDSHIFT;
  52. switch (cmds) {
  53. case Q_GETQUOTA:
  54. dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
  55. compat_dqblk = addr;
  56. ret = kernel_quotactl(cmd, special, id, dqblk);
  57. if (ret)
  58. break;
  59. if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
  60. get_user(data, &dqblk->dqb_valid) ||
  61. put_user(data, &compat_dqblk->dqb_valid))
  62. ret = -EFAULT;
  63. break;
  64. case Q_SETQUOTA:
  65. dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
  66. compat_dqblk = addr;
  67. ret = -EFAULT;
  68. if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
  69. get_user(data, &compat_dqblk->dqb_valid) ||
  70. put_user(data, &dqblk->dqb_valid))
  71. break;
  72. ret = kernel_quotactl(cmd, special, id, dqblk);
  73. break;
  74. case Q_XGETQSTAT:
  75. fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
  76. compat_fsqstat = addr;
  77. ret = kernel_quotactl(cmd, special, id, fsqstat);
  78. if (ret)
  79. break;
  80. ret = -EFAULT;
  81. /* Copying qs_version, qs_flags, qs_pad */
  82. if (copy_in_user(compat_fsqstat, fsqstat,
  83. offsetof(struct compat_fs_quota_stat, qs_uquota)))
  84. break;
  85. /* Copying qs_uquota */
  86. if (copy_in_user(&compat_fsqstat->qs_uquota,
  87. &fsqstat->qs_uquota,
  88. sizeof(compat_fsqstat->qs_uquota)) ||
  89. get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
  90. put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
  91. break;
  92. /* Copying qs_gquota */
  93. if (copy_in_user(&compat_fsqstat->qs_gquota,
  94. &fsqstat->qs_gquota,
  95. sizeof(compat_fsqstat->qs_gquota)) ||
  96. get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
  97. put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
  98. break;
  99. /* Copying the rest */
  100. if (copy_in_user(&compat_fsqstat->qs_incoredqs,
  101. &fsqstat->qs_incoredqs,
  102. sizeof(struct compat_fs_quota_stat) -
  103. offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
  104. get_user(xdata, &fsqstat->qs_iwarnlimit) ||
  105. put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
  106. break;
  107. ret = 0;
  108. break;
  109. default:
  110. ret = kernel_quotactl(cmd, special, id, addr);
  111. }
  112. return ret;
  113. }