user.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. memcpy (dst, src, size);
  30. return (0);
  31. }
  32. int
  33. user_copy_to (void *udst, const void *src, size_t size)
  34. {
  35. return (user_check_range (udst, size) ?
  36. user_copy_impl (udst, src, size) : EFAULT);
  37. }
  38. int
  39. user_copy_from (void *dst, const void *usrc, size_t size)
  40. {
  41. return (user_check_range (usrc, size) ?
  42. user_copy_impl (dst, usrc, size) : EFAULT);
  43. }
  44. static bool
  45. user_check_iov_iter (struct ipc_iov_iter *iov)
  46. {
  47. return (iov->begin == &iov->head ||
  48. user_check_range (iov->begin, iov->end * sizeof (*iov->begin)));
  49. }
  50. static ssize_t
  51. user_copyv_impl (struct ipc_iov_iter *dst,
  52. struct ipc_iov_iter *src, int to_user)
  53. {
  54. struct unw_fixup fixup;
  55. ssize_t ret = unw_fixup_save (&fixup);
  56. if (unlikely (ret))
  57. return (-ret);
  58. else if (!user_check_iov_iter (to_user ? dst : src))
  59. return (-EFAULT);
  60. ssize_t *err1 = to_user ? &ret : NULL;
  61. ssize_t *err2 = to_user ? NULL : &ret;
  62. while (1)
  63. {
  64. struct iovec *dv = ipc_iov_iter_usrnext (dst, err1);
  65. if (! dv)
  66. return (ret);
  67. struct iovec *sv = ipc_iov_iter_usrnext (src, err2);
  68. if (! sv)
  69. return (ret);
  70. size_t nbytes = MIN (dv->iov_len, sv->iov_len);
  71. if (unlikely ((ret += nbytes) < 0))
  72. return (-EOVERFLOW);
  73. memcpy (dv->iov_base, sv->iov_base, nbytes);
  74. iovec_adv (dv, nbytes);
  75. iovec_adv (sv, nbytes);
  76. }
  77. }
  78. ssize_t
  79. user_copyv_to (struct ipc_iov_iter *udst, struct ipc_iov_iter *src)
  80. {
  81. return (user_copyv_impl (udst, src, 1));
  82. }
  83. ssize_t
  84. user_copyv_from (struct ipc_iov_iter *dst, struct ipc_iov_iter *usrc)
  85. {
  86. return (user_copyv_impl (dst, usrc, 0));
  87. }
  88. bool
  89. user_check_struct (const void *uptr, size_t min_size)
  90. {
  91. if (!user_check_range (uptr, sizeof (uint32_t)))
  92. return (false);
  93. struct unw_fixup fixup;
  94. int error = unw_fixup_save (&fixup);
  95. if (unlikely (error))
  96. return (false);
  97. uint32_t rsize = ((const union user_ua *)uptr)->u4;
  98. return (rsize >= min_size && user_check_range (uptr, rsize));
  99. }
  100. int
  101. user_read_struct (void *dst, const void *usrc, size_t size)
  102. {
  103. if (!user_check_range (usrc, sizeof (uint32_t)))
  104. return (EFAULT);
  105. struct unw_fixup fixup;
  106. int error = unw_fixup_save (&fixup);
  107. if (unlikely (error))
  108. return (error);
  109. size_t rsize = ((const union user_ua *)usrc)->u4;
  110. if (size < rsize)
  111. rsize = size;
  112. if (!user_check_range (usrc, rsize))
  113. return (EFAULT);
  114. memcpy (dst, usrc, rsize);
  115. return (0);
  116. }
  117. int
  118. user_write_struct (void *udst, const void *src, size_t size)
  119. {
  120. if (!user_check_range (udst, sizeof (uint32_t)))
  121. return (EFAULT);
  122. struct unw_fixup fixup;
  123. int error = unw_fixup_save (&fixup);
  124. if (unlikely (error))
  125. return (error);
  126. size_t rsize = ((const union user_ua *)udst)->u4;
  127. if (rsize < sizeof (uint32_t))
  128. return (EFAULT);
  129. else if (size < rsize)
  130. rsize = size;
  131. if (!user_check_range (udst, rsize))
  132. return (EFAULT);
  133. memcpy ((char *)udst + sizeof (uint32_t),
  134. (const char *)src + sizeof (uint32_t),
  135. rsize - sizeof (uint32_t));
  136. return (0);
  137. }