user.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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 (void *dst, const void *src, size_t size)
  24. {
  25. struct unw_fixup fixup;
  26. int error = unw_fixup_save (&fixup);
  27. if (likely (! error))
  28. memcpy (dst, src, size);
  29. return (error);
  30. }
  31. int
  32. user_copy_to (void *udst, const void *src, size_t size)
  33. {
  34. return (user_check_range (udst, size) ?
  35. user_copy_impl (udst, src, size) : EFAULT);
  36. }
  37. int
  38. user_copy_from (void *dst, const void *usrc, size_t size)
  39. {
  40. return (user_check_range (usrc, size) ?
  41. user_copy_impl (dst, usrc, size) : EFAULT);
  42. }
  43. static struct iovec*
  44. user_iov_next (struct ipc_iov_iter *it, int check, int *errp)
  45. {
  46. while (1)
  47. {
  48. if (it->head.iov_len)
  49. return (&it->head);
  50. else if (it->cur >= it->end)
  51. return (NULL);
  52. _Auto iov = it->begin + it->cur;
  53. if (check && !user_check_range (iov->iov_base, iov->iov_len))
  54. {
  55. *errp = -EFAULT;
  56. return (NULL);
  57. }
  58. it->head = *iov;
  59. ++it->cur;
  60. }
  61. }
  62. static bool
  63. user_check_iov_iter (struct ipc_iov_iter *iov)
  64. {
  65. return (iov->begin == &iov->head ||
  66. user_check_range (iov->begin, iov->end * sizeof (*iov->begin)));
  67. }
  68. ssize_t
  69. user_copyv_impl (struct ipc_iov_iter *dst,
  70. struct ipc_iov_iter *src, int to_user)
  71. {
  72. struct unw_fixup fixup;
  73. int error = unw_fixup_save (&fixup);
  74. if (unlikely (error))
  75. return (-error);
  76. else if ((to_user && !user_check_iov_iter (dst)) ||
  77. (!to_user && !user_check_iov_iter (src)))
  78. return (-EFAULT);
  79. for (ssize_t ret = 0 ; ; )
  80. {
  81. struct iovec *dv = user_iov_next (dst, to_user, &error);
  82. if (! dv)
  83. return (error ?: ret);
  84. struct iovec *sv = user_iov_next (src, !to_user, &error);
  85. if (! sv)
  86. return (error ?: ret);
  87. size_t nbytes = MIN (dv->iov_len, sv->iov_len);
  88. if (unlikely ((ret += nbytes) < 0))
  89. return (-EOVERFLOW);
  90. memcpy (dv->iov_base, sv->iov_base, nbytes);
  91. iovec_adv (dv, nbytes);
  92. iovec_adv (sv, nbytes);
  93. }
  94. }
  95. ssize_t
  96. user_copyv_to (struct ipc_iov_iter *udst, struct ipc_iov_iter *src)
  97. {
  98. return (user_copyv_impl (udst, src, 1));
  99. }
  100. ssize_t
  101. user_copyv_from (struct ipc_iov_iter *dst, struct ipc_iov_iter *usrc)
  102. {
  103. return (user_copyv_impl (dst, usrc, 0));
  104. }