usercopy.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * User address space access functions.
  3. *
  4. * Copyright 1997 Andi Kleen <ak@muc.de>
  5. * Copyright 1997 Linus Torvalds
  6. * Copyright 2002 Andi Kleen <ak@suse.de>
  7. */
  8. #include <asm/uaccess.h>
  9. /*
  10. * Copy a null terminated string from userspace.
  11. */
  12. #define __do_strncpy_from_user(dst,src,count,res) \
  13. do { \
  14. long __d0, __d1, __d2; \
  15. might_sleep(); \
  16. __asm__ __volatile__( \
  17. " testq %1,%1\n" \
  18. " jz 2f\n" \
  19. "0: lodsb\n" \
  20. " stosb\n" \
  21. " testb %%al,%%al\n" \
  22. " jz 1f\n" \
  23. " decq %1\n" \
  24. " jnz 0b\n" \
  25. "1: subq %1,%0\n" \
  26. "2:\n" \
  27. ".section .fixup,\"ax\"\n" \
  28. "3: movq %5,%0\n" \
  29. " jmp 2b\n" \
  30. ".previous\n" \
  31. ".section __ex_table,\"a\"\n" \
  32. " .align 8\n" \
  33. " .quad 0b,3b\n" \
  34. ".previous" \
  35. : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
  36. "=&D" (__d2) \
  37. : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
  38. : "memory"); \
  39. } while (0)
  40. long
  41. __strncpy_from_user(char *dst, const char __user *src, long count)
  42. {
  43. long res;
  44. __do_strncpy_from_user(dst, src, count, res);
  45. return res;
  46. }
  47. long
  48. strncpy_from_user(char *dst, const char __user *src, long count)
  49. {
  50. long res = -EFAULT;
  51. if (access_ok(VERIFY_READ, src, 1))
  52. __do_strncpy_from_user(dst, src, count, res);
  53. return res;
  54. }
  55. /*
  56. * Zero Userspace
  57. */
  58. unsigned long __clear_user(void __user *addr, unsigned long size)
  59. {
  60. long __d0;
  61. might_sleep();
  62. /* no memory constraint because it doesn't change any memory gcc knows
  63. about */
  64. asm volatile(
  65. " testq %[size8],%[size8]\n"
  66. " jz 4f\n"
  67. "0: movq %[zero],(%[dst])\n"
  68. " addq %[eight],%[dst]\n"
  69. " decl %%ecx ; jnz 0b\n"
  70. "4: movq %[size1],%%rcx\n"
  71. " testl %%ecx,%%ecx\n"
  72. " jz 2f\n"
  73. "1: movb %b[zero],(%[dst])\n"
  74. " incq %[dst]\n"
  75. " decl %%ecx ; jnz 1b\n"
  76. "2:\n"
  77. ".section .fixup,\"ax\"\n"
  78. "3: lea 0(%[size1],%[size8],8),%[size8]\n"
  79. " jmp 2b\n"
  80. ".previous\n"
  81. ".section __ex_table,\"a\"\n"
  82. " .align 8\n"
  83. " .quad 0b,3b\n"
  84. " .quad 1b,2b\n"
  85. ".previous"
  86. : [size8] "=c"(size), [dst] "=&D" (__d0)
  87. : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
  88. [zero] "r" (0UL), [eight] "r" (8UL));
  89. return size;
  90. }
  91. unsigned long clear_user(void __user *to, unsigned long n)
  92. {
  93. if (access_ok(VERIFY_WRITE, to, n))
  94. return __clear_user(to, n);
  95. return n;
  96. }
  97. /*
  98. * Return the size of a string (including the ending 0)
  99. *
  100. * Return 0 on exception, a value greater than N if too long
  101. */
  102. long __strnlen_user(const char __user *s, long n)
  103. {
  104. long res = 0;
  105. char c;
  106. while (1) {
  107. if (res>n)
  108. return n+1;
  109. if (__get_user(c, s))
  110. return 0;
  111. if (!c)
  112. return res+1;
  113. res++;
  114. s++;
  115. }
  116. }
  117. long strnlen_user(const char __user *s, long n)
  118. {
  119. if (!access_ok(VERIFY_READ, s, n))
  120. return 0;
  121. return __strnlen_user(s, n);
  122. }
  123. long strlen_user(const char __user *s)
  124. {
  125. long res = 0;
  126. char c;
  127. for (;;) {
  128. if (get_user(c, s))
  129. return 0;
  130. if (!c)
  131. return res+1;
  132. res++;
  133. s++;
  134. }
  135. }
  136. unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
  137. {
  138. if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
  139. return copy_user_generic((__force void *)to, (__force void *)from, len);
  140. }
  141. return len;
  142. }