user.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. {
  52. _Auto iov = it->begin + it->cur;
  53. if (check && (!user_check_range (iov, sizeof (*iov)) ||
  54. !user_check_range (iov->iov_base, iov->iov_len)))
  55. {
  56. *errp = -EFAULT;
  57. return (NULL);
  58. }
  59. it->head = *iov;
  60. ++it->cur;
  61. }
  62. else
  63. return (NULL);
  64. }
  65. }
  66. ssize_t
  67. user_copyv_impl (struct ipc_iov_iter *dst,
  68. struct ipc_iov_iter *src, int to_user)
  69. {
  70. struct unw_fixup fixup;
  71. int error = unw_fixup_save (&fixup);
  72. if (unlikely (error))
  73. return (-error);
  74. for (ssize_t ret = 0 ; ; )
  75. {
  76. struct iovec *dv = user_iov_next (dst, to_user, &error);
  77. if (! dv)
  78. return (error ?: ret);
  79. struct iovec *sv = user_iov_next (src, !to_user, &error);
  80. if (! sv)
  81. return (error ?: ret);
  82. size_t nbytes = MIN (dv->iov_len, sv->iov_len);
  83. if (unlikely ((ret += nbytes) < 0))
  84. return (-EOVERFLOW);
  85. memcpy (dv->iov_base, sv->iov_base, nbytes);
  86. iovec_adv (dv, nbytes);
  87. iovec_adv (sv, nbytes);
  88. }
  89. }
  90. ssize_t
  91. user_copyv_to (struct ipc_iov_iter *udst, struct ipc_iov_iter *src)
  92. {
  93. return (user_copyv_impl (udst, src, 1));
  94. }
  95. ssize_t
  96. user_copyv_from (struct ipc_iov_iter *dst, struct ipc_iov_iter *usrc)
  97. {
  98. return (user_copyv_impl (dst, usrc, 0));
  99. }