Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/usercopy: Remove .fixup usage

Typically usercopy does whole word copies followed by a number of byte
copies to finish the tail. This means that on exception it needs to
compute the remaining length as: words*sizeof(long) + bytes.

Create a new extable handler to do just this.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/r/20211110101326.081701085@infradead.org

+22 -28
+5
arch/x86/include/asm/extable_fixup_types.h
··· 50 50 51 51 #define EX_TYPE_FAULT_SGX 18 52 52 53 + #define EX_TYPE_UCOPY_LEN 19 /* cx := reg + imm*cx */ 54 + #define EX_TYPE_UCOPY_LEN1 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(1)) 55 + #define EX_TYPE_UCOPY_LEN4 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(4)) 56 + #define EX_TYPE_UCOPY_LEN8 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(8)) 57 + 53 58 #endif
+5 -23
arch/x86/lib/usercopy_32.c
··· 42 42 " movl %2,%0\n" \ 43 43 "1: rep; stosb\n" \ 44 44 "2: " ASM_CLAC "\n" \ 45 - ".section .fixup,\"ax\"\n" \ 46 - "3: lea 0(%2,%0,4),%0\n" \ 47 - " jmp 2b\n" \ 48 - ".previous\n" \ 49 - _ASM_EXTABLE_UA(0b, 3b) \ 45 + _ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %2) \ 50 46 _ASM_EXTABLE_UA(1b, 2b) \ 51 47 : "=&c"(size), "=&D" (__d0) \ 52 48 : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ ··· 144 148 "36: movl %%eax, %0\n" 145 149 "37: rep; movsb\n" 146 150 "100:\n" 147 - ".section .fixup,\"ax\"\n" 148 - "101: lea 0(%%eax,%0,4),%0\n" 149 - " jmp 100b\n" 150 - ".previous\n" 151 151 _ASM_EXTABLE_UA(1b, 100b) 152 152 _ASM_EXTABLE_UA(2b, 100b) 153 153 _ASM_EXTABLE_UA(3b, 100b) ··· 181 189 _ASM_EXTABLE_UA(35b, 100b) 182 190 _ASM_EXTABLE_UA(36b, 100b) 183 191 _ASM_EXTABLE_UA(37b, 100b) 184 - _ASM_EXTABLE_UA(99b, 101b) 192 + _ASM_EXTABLE_TYPE_REG(99b, 100b, EX_TYPE_UCOPY_LEN4, %%eax) 185 193 : "=&c"(size), "=&D" (d0), "=&S" (d1) 186 194 : "1"(to), "2"(from), "0"(size) 187 195 : "eax", "edx", "memory"); ··· 246 254 " movl %%eax,%0\n" 247 255 "7: rep; movsb\n" 248 256 "8:\n" 249 - ".section .fixup,\"ax\"\n" 250 - "9: lea 0(%%eax,%0,4),%0\n" 251 - " jmp 8b\n" 252 - ".previous\n" 253 257 _ASM_EXTABLE_UA(0b, 8b) 254 258 _ASM_EXTABLE_UA(1b, 8b) 255 259 _ASM_EXTABLE_UA(2b, 8b) ··· 264 276 _ASM_EXTABLE_UA(81b, 8b) 265 277 _ASM_EXTABLE_UA(14b, 8b) 266 278 _ASM_EXTABLE_UA(91b, 8b) 267 - _ASM_EXTABLE_UA(6b, 9b) 279 + _ASM_EXTABLE_TYPE_REG(6b, 8b, EX_TYPE_UCOPY_LEN4, %%eax) 268 280 _ASM_EXTABLE_UA(7b, 8b) 269 281 : "=&c"(size), "=&D" (d0), "=&S" (d1) 270 282 : "1"(to), "2"(from), "0"(size) ··· 302 314 " movl %3,%0\n" \ 303 315 "1: rep; movsb\n" \ 304 316 "2:\n" \ 305 - ".section .fixup,\"ax\"\n" \ 306 - "5: addl %3,%0\n" \ 307 - " jmp 2b\n" \ 308 - "3: lea 0(%3,%0,4),%0\n" \ 309 - " jmp 2b\n" \ 310 - ".previous\n" \ 311 - _ASM_EXTABLE_UA(4b, 5b) \ 312 - _ASM_EXTABLE_UA(0b, 3b) \ 317 + _ASM_EXTABLE_TYPE_REG(4b, 2b, EX_TYPE_UCOPY_LEN1, %3) \ 318 + _ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %3) \ 313 319 _ASM_EXTABLE_UA(1b, 2b) \ 314 320 : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ 315 321 : "3"(size), "0"(size), "1"(to), "2"(from) \
+3 -5
arch/x86/lib/usercopy_64.c
··· 35 35 " incq %[dst]\n" 36 36 " decl %%ecx ; jnz 1b\n" 37 37 "2:\n" 38 - ".section .fixup,\"ax\"\n" 39 - "3: lea 0(%[size1],%[size8],8),%[size8]\n" 40 - " jmp 2b\n" 41 - ".previous\n" 42 - _ASM_EXTABLE_UA(0b, 3b) 38 + 39 + _ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN8, %[size1]) 43 40 _ASM_EXTABLE_UA(1b, 2b) 41 + 44 42 : [size8] "=&c"(size), [dst] "=&D" (__d0) 45 43 : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr)); 46 44 clac();
+9
arch/x86/mm/extable.c
··· 145 145 return ex_handler_default(fixup, regs); 146 146 } 147 147 148 + static bool ex_handler_ucopy_len(const struct exception_table_entry *fixup, 149 + struct pt_regs *regs, int trapnr, int reg, int imm) 150 + { 151 + regs->cx = imm * regs->cx + *pt_regs_nr(regs, reg); 152 + return ex_handler_uaccess(fixup, regs, trapnr); 153 + } 154 + 148 155 int ex_get_fixup_type(unsigned long ip) 149 156 { 150 157 const struct exception_table_entry *e = search_exception_tables(ip); ··· 224 217 return ex_handler_imm_reg(e, regs, reg, imm); 225 218 case EX_TYPE_FAULT_SGX: 226 219 return ex_handler_sgx(e, regs, trapnr); 220 + case EX_TYPE_UCOPY_LEN: 221 + return ex_handler_ucopy_len(e, regs, trapnr, reg, imm); 227 222 } 228 223 BUG(); 229 224 }