copyinout.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #include <types.h>
  30. #include <kern/errno.h>
  31. #include <lib.h>
  32. #include <setjmp.h>
  33. #include <thread.h>
  34. #include <current.h>
  35. #include <vm.h>
  36. #include <copyinout.h>
  37. /*
  38. * User/kernel memory copying functions.
  39. *
  40. * These are arranged to prevent fatal kernel memory faults if invalid
  41. * addresses are supplied by user-level code. This code is itself
  42. * machine-independent; it uses the machine-dependent C setjmp/longjmp
  43. * facility to perform recovery.
  44. *
  45. * However, it assumes things about the memory subsystem that may not
  46. * be true on all platforms.
  47. *
  48. * (1) It assumes that user memory is mapped into the current address
  49. * space while running in the kernel, and can be accessed by just
  50. * dereferencing a pointer in the ordinary way. (And not, for example,
  51. * with special instructions or via special segment registers.)
  52. *
  53. * (2) It assumes that the user-space region of memory is contiguous
  54. * and extends from 0 to some virtual address USERSPACETOP, and so if
  55. * a user process passes a kernel address the logic in copycheck()
  56. * will trap it.
  57. *
  58. * (3) It assumes that access to user memory from the kernel behaves
  59. * the same way as access to user memory from user space: for
  60. * instance, that the processor honors read-only bits on memory pages
  61. * when in kernel mode.
  62. *
  63. * (4) It assumes that if a proper user-space address that is valid
  64. * but not present, or not valid at all, is touched from the kernel,
  65. * that the correct faults will occur and the VM system will load the
  66. * necessary pages and whatnot.
  67. *
  68. * (5) It assumes that the machine-dependent trap logic provides and
  69. * honors a tm_badfaultfunc field in the thread_machdep structure.
  70. * This feature works as follows: if an otherwise fatal fault occurs
  71. * in kernel mode, and tm_badfaultfunc is set, execution resumes in
  72. * the function pointed to by tm_badfaultfunc.
  73. *
  74. * This code works by setting tm_badfaultfunc and then copying memory
  75. * in an ordinary fashion. If these five assumptions are satisfied,
  76. * which is the case for many ordinary CPU types, this code should
  77. * function correctly. If the assumptions are not satisfied on some
  78. * platform (for instance, certain old 80386 processors violate
  79. * assumption 3), this code cannot be used, and cpu- or platform-
  80. * specific code must be written.
  81. *
  82. * To make use of this code, in addition to tm_badfaultfunc the
  83. * thread_machdep structure should contain a jmp_buf called
  84. * "tm_copyjmp".
  85. */
  86. /*
  87. * Recovery function. If a fatal fault occurs during copyin, copyout,
  88. * copyinstr, or copyoutstr, execution resumes here. (This behavior is
  89. * caused by setting t_machdep.tm_badfaultfunc and is implemented in
  90. * machine-dependent code.)
  91. *
  92. * We use the C standard function longjmp() to teleport up the call
  93. * stack to where setjmp() was called. At that point we return EFAULT.
  94. */
  95. static
  96. void
  97. copyfail(void)
  98. {
  99. longjmp(curthread->t_machdep.tm_copyjmp, 1);
  100. }
  101. /*
  102. * Memory region check function. This checks to make sure the block of
  103. * user memory provided (an address and a length) falls within the
  104. * proper userspace region. If it does not, EFAULT is returned.
  105. *
  106. * stoplen is set to the actual maximum length that can be copied.
  107. * This differs from len if and only if the region partially overlaps
  108. * the kernel.
  109. *
  110. * Assumes userspace runs from 0 through USERSPACETOP-1.
  111. */
  112. static
  113. int
  114. copycheck(const_userptr_t userptr, size_t len, size_t *stoplen)
  115. {
  116. vaddr_t bot, top;
  117. *stoplen = len;
  118. bot = (vaddr_t) userptr;
  119. top = bot+len-1;
  120. if (top < bot) {
  121. /* addresses wrapped around */
  122. return EFAULT;
  123. }
  124. if (bot >= USERSPACETOP) {
  125. /* region is within the kernel */
  126. return EFAULT;
  127. }
  128. if (top >= USERSPACETOP) {
  129. /* region overlaps the kernel. adjust the max length. */
  130. *stoplen = USERSPACETOP - bot;
  131. }
  132. return 0;
  133. }
  134. /*
  135. * copyin
  136. *
  137. * Copy a block of memory of length LEN from user-level address USERSRC
  138. * to kernel address DEST. We can use memcpy because it's protected by
  139. * the tm_badfaultfunc/copyfail logic.
  140. */
  141. int
  142. copyin(const_userptr_t usersrc, void *dest, size_t len)
  143. {
  144. int result;
  145. size_t stoplen;
  146. result = copycheck(usersrc, len, &stoplen);
  147. if (result) {
  148. return result;
  149. }
  150. if (stoplen != len) {
  151. /* Single block, can't legally truncate it. */
  152. return EFAULT;
  153. }
  154. curthread->t_machdep.tm_badfaultfunc = copyfail;
  155. result = setjmp(curthread->t_machdep.tm_copyjmp);
  156. if (result) {
  157. curthread->t_machdep.tm_badfaultfunc = NULL;
  158. return EFAULT;
  159. }
  160. memcpy(dest, (const void *)usersrc, len);
  161. curthread->t_machdep.tm_badfaultfunc = NULL;
  162. return 0;
  163. }
  164. /*
  165. * copyout
  166. *
  167. * Copy a block of memory of length LEN from kernel address SRC to
  168. * user-level address USERDEST. We can use memcpy because it's
  169. * protected by the tm_badfaultfunc/copyfail logic.
  170. */
  171. int
  172. copyout(const void *src, userptr_t userdest, size_t len)
  173. {
  174. int result;
  175. size_t stoplen;
  176. result = copycheck(userdest, len, &stoplen);
  177. if (result) {
  178. return result;
  179. }
  180. if (stoplen != len) {
  181. /* Single block, can't legally truncate it. */
  182. return EFAULT;
  183. }
  184. curthread->t_machdep.tm_badfaultfunc = copyfail;
  185. result = setjmp(curthread->t_machdep.tm_copyjmp);
  186. if (result) {
  187. curthread->t_machdep.tm_badfaultfunc = NULL;
  188. return EFAULT;
  189. }
  190. memcpy((void *)userdest, src, len);
  191. curthread->t_machdep.tm_badfaultfunc = NULL;
  192. return 0;
  193. }
  194. /*
  195. * Common string copying function that behaves the way that's desired
  196. * for copyinstr and copyoutstr.
  197. *
  198. * Copies a null-terminated string of maximum length MAXLEN from SRC
  199. * to DEST. If GOTLEN is not null, store the actual length found
  200. * there. Both lengths include the null-terminator. If the string
  201. * exceeds the available length, the call fails and returns
  202. * ENAMETOOLONG.
  203. *
  204. * STOPLEN is like MAXLEN but is assumed to have come from copycheck.
  205. * If we hit MAXLEN it's because the string is too long to fit; if we
  206. * hit STOPLEN it's because the string has run into the end of
  207. * userspace. Thus in the latter case we return EFAULT, not
  208. * ENAMETOOLONG.
  209. */
  210. static
  211. int
  212. copystr(char *dest, const char *src, size_t maxlen, size_t stoplen,
  213. size_t *gotlen)
  214. {
  215. size_t i;
  216. for (i=0; i<maxlen && i<stoplen; i++) {
  217. dest[i] = src[i];
  218. if (src[i] == 0) {
  219. if (gotlen != NULL) {
  220. *gotlen = i+1;
  221. }
  222. return 0;
  223. }
  224. }
  225. if (stoplen < maxlen) {
  226. /* ran into user-kernel boundary */
  227. return EFAULT;
  228. }
  229. /* otherwise just ran out of space */
  230. return ENAMETOOLONG;
  231. }
  232. /*
  233. * copyinstr
  234. *
  235. * Copy a string from user-level address USERSRC to kernel address
  236. * DEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
  237. * logic to protect against invalid addresses supplied by a user
  238. * process.
  239. */
  240. int
  241. copyinstr(const_userptr_t usersrc, char *dest, size_t len, size_t *actual)
  242. {
  243. int result;
  244. size_t stoplen;
  245. result = copycheck(usersrc, len, &stoplen);
  246. if (result) {
  247. return result;
  248. }
  249. curthread->t_machdep.tm_badfaultfunc = copyfail;
  250. result = setjmp(curthread->t_machdep.tm_copyjmp);
  251. if (result) {
  252. curthread->t_machdep.tm_badfaultfunc = NULL;
  253. return EFAULT;
  254. }
  255. result = copystr(dest, (const char *)usersrc, len, stoplen, actual);
  256. curthread->t_machdep.tm_badfaultfunc = NULL;
  257. return result;
  258. }
  259. /*
  260. * copyoutstr
  261. *
  262. * Copy a string from kernel address SRC to user-level address
  263. * USERDEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
  264. * logic to protect against invalid addresses supplied by a user
  265. * process.
  266. */
  267. int
  268. copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *actual)
  269. {
  270. int result;
  271. size_t stoplen;
  272. result = copycheck(userdest, len, &stoplen);
  273. if (result) {
  274. return result;
  275. }
  276. curthread->t_machdep.tm_badfaultfunc = copyfail;
  277. result = setjmp(curthread->t_machdep.tm_copyjmp);
  278. if (result) {
  279. curthread->t_machdep.tm_badfaultfunc = NULL;
  280. return EFAULT;
  281. }
  282. result = copystr((char *)userdest, src, len, stoplen, actual);
  283. curthread->t_machdep.tm_badfaultfunc = NULL;
  284. return result;
  285. }