getuser.S 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * __get_user functions.
  4. *
  5. * (C) Copyright 1998 Linus Torvalds
  6. * (C) Copyright 2005 Andi Kleen
  7. * (C) Copyright 2008 Glauber Costa
  8. *
  9. * These functions have a non-standard call interface
  10. * to make them more efficient, especially as they
  11. * return an error value in addition to the "real"
  12. * return value.
  13. */
  14. /*
  15. * __get_user_X
  16. *
  17. * Inputs: %[r|e]ax contains the address.
  18. *
  19. * Outputs: %[r|e]ax is error code (0 or -EFAULT)
  20. * %[r|e]dx contains zero-extended value
  21. * %ecx contains the high half for 32-bit __get_user_8
  22. *
  23. *
  24. * These functions should not modify any other registers,
  25. * as they get called from within inline assembly.
  26. */
  27. #include <linux/export.h>
  28. #include <linux/linkage.h>
  29. #include <asm/page_types.h>
  30. #include <asm/errno.h>
  31. #include <asm/asm-offsets.h>
  32. #include <asm/thread_info.h>
  33. #include <asm/asm.h>
  34. #include <asm/smap.h>
  35. #define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
  36. .macro check_range size:req
  37. .if IS_ENABLED(CONFIG_X86_64)
  38. movq $0x0123456789abcdef,%rdx
  39. 1:
  40. .pushsection runtime_ptr_USER_PTR_MAX,"a"
  41. .long 1b - 8 - .
  42. .popsection
  43. cmp %rax, %rdx
  44. sbb %rdx, %rdx
  45. or %rdx, %rax
  46. .else
  47. cmp $TASK_SIZE_MAX-\size+1, %eax
  48. jae .Lbad_get_user
  49. sbb %edx, %edx /* array_index_mask_nospec() */
  50. and %edx, %eax
  51. .endif
  52. .endm
  53. .macro UACCESS op src dst
  54. 1: \op \src,\dst
  55. _ASM_EXTABLE_UA(1b, __get_user_handle_exception)
  56. .endm
  57. .text
  58. SYM_FUNC_START(__get_user_1)
  59. check_range size=1
  60. ASM_STAC
  61. UACCESS movzbl (%_ASM_AX),%edx
  62. xor %eax,%eax
  63. ASM_CLAC
  64. RET
  65. SYM_FUNC_END(__get_user_1)
  66. EXPORT_SYMBOL(__get_user_1)
  67. SYM_FUNC_START(__get_user_2)
  68. check_range size=2
  69. ASM_STAC
  70. UACCESS movzwl (%_ASM_AX),%edx
  71. xor %eax,%eax
  72. ASM_CLAC
  73. RET
  74. SYM_FUNC_END(__get_user_2)
  75. EXPORT_SYMBOL(__get_user_2)
  76. SYM_FUNC_START(__get_user_4)
  77. check_range size=4
  78. ASM_STAC
  79. UACCESS movl (%_ASM_AX),%edx
  80. xor %eax,%eax
  81. ASM_CLAC
  82. RET
  83. SYM_FUNC_END(__get_user_4)
  84. EXPORT_SYMBOL(__get_user_4)
  85. SYM_FUNC_START(__get_user_8)
  86. #ifndef CONFIG_X86_64
  87. xor %ecx,%ecx
  88. #endif
  89. check_range size=8
  90. ASM_STAC
  91. #ifdef CONFIG_X86_64
  92. UACCESS movq (%_ASM_AX),%rdx
  93. #else
  94. UACCESS movl (%_ASM_AX),%edx
  95. UACCESS movl 4(%_ASM_AX),%ecx
  96. #endif
  97. xor %eax,%eax
  98. ASM_CLAC
  99. RET
  100. SYM_FUNC_END(__get_user_8)
  101. EXPORT_SYMBOL(__get_user_8)
  102. /* .. and the same for __get_user, just without the range checks */
  103. SYM_FUNC_START(__get_user_nocheck_1)
  104. ASM_STAC
  105. ASM_BARRIER_NOSPEC
  106. UACCESS movzbl (%_ASM_AX),%edx
  107. xor %eax,%eax
  108. ASM_CLAC
  109. RET
  110. SYM_FUNC_END(__get_user_nocheck_1)
  111. EXPORT_SYMBOL(__get_user_nocheck_1)
  112. SYM_FUNC_START(__get_user_nocheck_2)
  113. ASM_STAC
  114. ASM_BARRIER_NOSPEC
  115. UACCESS movzwl (%_ASM_AX),%edx
  116. xor %eax,%eax
  117. ASM_CLAC
  118. RET
  119. SYM_FUNC_END(__get_user_nocheck_2)
  120. EXPORT_SYMBOL(__get_user_nocheck_2)
  121. SYM_FUNC_START(__get_user_nocheck_4)
  122. ASM_STAC
  123. ASM_BARRIER_NOSPEC
  124. UACCESS movl (%_ASM_AX),%edx
  125. xor %eax,%eax
  126. ASM_CLAC
  127. RET
  128. SYM_FUNC_END(__get_user_nocheck_4)
  129. EXPORT_SYMBOL(__get_user_nocheck_4)
  130. SYM_FUNC_START(__get_user_nocheck_8)
  131. ASM_STAC
  132. ASM_BARRIER_NOSPEC
  133. #ifdef CONFIG_X86_64
  134. UACCESS movq (%_ASM_AX),%rdx
  135. #else
  136. xor %ecx,%ecx
  137. UACCESS movl (%_ASM_AX),%edx
  138. UACCESS movl 4(%_ASM_AX),%ecx
  139. #endif
  140. xor %eax,%eax
  141. ASM_CLAC
  142. RET
  143. SYM_FUNC_END(__get_user_nocheck_8)
  144. EXPORT_SYMBOL(__get_user_nocheck_8)
  145. SYM_CODE_START_LOCAL(__get_user_handle_exception)
  146. ASM_CLAC
  147. .Lbad_get_user:
  148. xor %edx,%edx
  149. mov $(-EFAULT),%_ASM_AX
  150. RET
  151. SYM_CODE_END(__get_user_handle_exception)