user.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c) 2023 Agustina Arzille.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. */
  18. #include <iovec.h>
  19. #include <kern/ipc.h>
  20. #include <kern/unwind.h>
  21. #include <kern/user.h>
  22. static int
  23. user_copy_impl (char *dst, const char *src, size_t size)
  24. {
  25. struct unw_fixup fixup;
  26. int error = unw_fixup_save (&fixup);
  27. if (unlikely (error))
  28. return (error);
  29. #define user_ua_cpy(sz) \
  30. ((union user_ua *)dst)->u##sz = ((const union user_ua *)src)->u##sz
  31. switch (size)
  32. {
  33. case 0:
  34. return (0);
  35. case 3:
  36. dst[2] = src[2];
  37. __fallthrough;
  38. case 2:
  39. user_ua_cpy (2);
  40. break;
  41. case 1:
  42. dst[0] = src[0];
  43. break;
  44. case 7:
  45. dst[6] = src[6];
  46. __fallthrough;
  47. case 6:
  48. user_ua_cpy (4);
  49. dst += 4, src += 4;
  50. user_ua_cpy (2);
  51. break;
  52. case 5:
  53. dst[4] = src[4];
  54. __fallthrough;
  55. case 4:
  56. user_ua_cpy (4);
  57. break;
  58. case 8:
  59. user_ua_cpy (8);
  60. break;
  61. #undef user_ua_cpy
  62. default:
  63. memcpy (dst, src, size);
  64. }
  65. return (0);
  66. }
  67. int
  68. user_copy_to (void *udst, const void *src, size_t size)
  69. {
  70. return (user_check_range (udst, size) ?
  71. user_copy_impl (udst, src, size) : EFAULT);
  72. }
  73. int
  74. user_copy_from (void *dst, const void *usrc, size_t size)
  75. {
  76. return (user_check_range (usrc, size) ?
  77. user_copy_impl (dst, usrc, size) : EFAULT);
  78. }
  79. static bool
  80. user_check_iov_iter (struct ipc_iov_iter *iov)
  81. {
  82. return (iov->begin == &iov->head ||
  83. user_check_range (iov->begin, iov->end * sizeof (*iov->begin)));
  84. }
  85. ssize_t
  86. user_copyv_impl (struct ipc_iov_iter *dst,
  87. struct ipc_iov_iter *src, bool to_user)
  88. {
  89. struct unw_fixup fixup;
  90. ssize_t ret = unw_fixup_save (&fixup);
  91. if (unlikely (ret))
  92. return (-ret);
  93. else if (!user_check_iov_iter (to_user ? dst : src))
  94. return (-EFAULT);
  95. while (1)
  96. {
  97. struct iovec *dv = ipc_iov_iter_usrnext (dst, to_user, &ret);
  98. if (! dv)
  99. return (ret);
  100. struct iovec *sv = ipc_iov_iter_usrnext (src, !to_user, &ret);
  101. if (! sv)
  102. return (ret);
  103. size_t nbytes = MIN (dv->iov_len, sv->iov_len);
  104. if (unlikely ((ret += nbytes) < 0))
  105. return (-EOVERFLOW);
  106. memcpy (dv->iov_base, sv->iov_base, nbytes);
  107. iovec_adv (dv, nbytes);
  108. iovec_adv (sv, nbytes);
  109. }
  110. }
  111. ssize_t
  112. user_copyv_to (struct ipc_iov_iter *udst, struct ipc_iov_iter *src)
  113. {
  114. return (user_copyv_impl (udst, src, true));
  115. }
  116. ssize_t
  117. user_copyv_from (struct ipc_iov_iter *dst, struct ipc_iov_iter *usrc)
  118. {
  119. return (user_copyv_impl (dst, usrc, false));
  120. }
  121. int
  122. user_read_struct (void *dst, const void *usrc, size_t size)
  123. {
  124. if (!user_check_range (usrc, sizeof (uint32_t)))
  125. return (EFAULT);
  126. struct unw_fixup fixup;
  127. int error = unw_fixup_save (&fixup);
  128. if (unlikely (error))
  129. return (error);
  130. size_t rsize = ((const union user_ua *)usrc)->u4;
  131. if (size < rsize)
  132. rsize = size;
  133. if (!user_check_range (usrc, rsize))
  134. return (EFAULT);
  135. memcpy (dst, usrc, rsize);
  136. return (0);
  137. }
  138. int
  139. user_write_struct (void *udst, const void *src, size_t size)
  140. {
  141. if (!user_check_range (udst, sizeof (uint32_t)))
  142. return (EFAULT);
  143. struct unw_fixup fixup;
  144. int error = unw_fixup_save (&fixup);
  145. if (unlikely (error))
  146. return (error);
  147. size_t rsize = ((const union user_ua *)udst)->u4;
  148. if (size < rsize)
  149. rsize = size;
  150. if (!user_check_range (udst, rsize))
  151. return (EFAULT);
  152. memcpy (udst, src, rsize);
  153. return (0);
  154. }