usercopy_64.c 3.5 KB

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