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