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

[PATCH] m32r: security fix of {get,put}_user macros

Update {get,put}_user macros for m32r kernel.
- Modify get_user to use __get_user_asm macro, instead of __get_user_x macro.
- Remove arch/m32r/lib/{get,put}user.S.
- Some cosmetic updates.

I would like to thank NIIBE Yutaka for his reporting about the m32r kernel's
security problem in {get,put}_user macros.

There were no address checking for user space access in {get,put}_user macros.
;-)

Signed-off-by: Hirokazu Takata <takata@linux-m32r.org>
Cc: NIIBE Yutaka <gniibe@fsij.org>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Hirokazu Takata and committed by
Linus Torvalds
04dfd0de 7c1c4e54

+117 -329
-4
arch/m32r/kernel/m32r_ksyms.c
··· 38 38 EXPORT_SYMBOL(__delay); 39 39 EXPORT_SYMBOL(__const_udelay); 40 40 41 - EXPORT_SYMBOL(__get_user_1); 42 - EXPORT_SYMBOL(__get_user_2); 43 - EXPORT_SYMBOL(__get_user_4); 44 - 45 41 EXPORT_SYMBOL(strpbrk); 46 42 EXPORT_SYMBOL(strstr); 47 43
+2 -2
arch/m32r/lib/Makefile
··· 2 2 # Makefile for M32R-specific library files.. 3 3 # 4 4 5 - lib-y := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \ 6 - putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o 5 + lib-y := checksum.o ashxdi3.o memset.o memcpy.o \ 6 + delay.o strlen.o usercopy.o csum_partial_copy.o 7 7
-88
arch/m32r/lib/getuser.S
··· 1 - /* 2 - * __get_user functions. 3 - * 4 - * (C) Copyright 2001 Hirokazu Takata 5 - * 6 - * These functions have a non-standard call interface 7 - * to make them more efficient, especially as they 8 - * return an error value in addition to the "real" 9 - * return value. 10 - */ 11 - 12 - #include <linux/config.h> 13 - 14 - /* 15 - * __get_user_X 16 - * 17 - * Inputs: r0 contains the address 18 - * 19 - * Outputs: r0 is error code (0 or -EFAULT) 20 - * r1 contains zero-extended value 21 - * 22 - * These functions should not modify any other registers, 23 - * as they get called from within inline assembly. 24 - */ 25 - 26 - #ifdef CONFIG_ISA_DUAL_ISSUE 27 - 28 - .text 29 - .balign 4 30 - .globl __get_user_1 31 - __get_user_1: 32 - 1: ldub r1, @r0 || ldi r0, #0 33 - jmp r14 34 - 35 - .balign 4 36 - .globl __get_user_2 37 - __get_user_2: 38 - 2: lduh r1, @r0 || ldi r0, #0 39 - jmp r14 40 - 41 - .balign 4 42 - .globl __get_user_4 43 - __get_user_4: 44 - 3: ld r1, @r0 || ldi r0, #0 45 - jmp r14 46 - 47 - bad_get_user: 48 - ldi r1, #0 || ldi r0, #-14 49 - jmp r14 50 - 51 - #else /* not CONFIG_ISA_DUAL_ISSUE */ 52 - 53 - .text 54 - .balign 4 55 - .globl __get_user_1 56 - __get_user_1: 57 - 1: ldub r1, @r0 58 - ldi r0, #0 59 - jmp r14 60 - 61 - .balign 4 62 - .globl __get_user_2 63 - __get_user_2: 64 - 2: lduh r1, @r0 65 - ldi r0, #0 66 - jmp r14 67 - 68 - .balign 4 69 - .globl __get_user_4 70 - __get_user_4: 71 - 3: ld r1, @r0 72 - ldi r0, #0 73 - jmp r14 74 - 75 - bad_get_user: 76 - ldi r1, #0 77 - ldi r0, #-14 78 - jmp r14 79 - 80 - #endif /* not CONFIG_ISA_DUAL_ISSUE */ 81 - 82 - .section __ex_table,"a" 83 - .long 1b,bad_get_user 84 - .long 2b,bad_get_user 85 - .long 3b,bad_get_user 86 - .previous 87 - 88 - .end
-84
arch/m32r/lib/putuser.S
··· 1 - /* 2 - * __put_user functions. 3 - * 4 - * (C) Copyright 1998 Linus Torvalds 5 - * (C) Copyright 2001 Hirokazu Takata 6 - * 7 - * These functions have a non-standard call interface 8 - * to make them more efficient. 9 - */ 10 - 11 - #include <linux/config.h> 12 - 13 - /* 14 - * __put_user_X 15 - * 16 - * Inputs: r0 contains the address 17 - * r1 contains the value 18 - * 19 - * Outputs: r0 is error code (0 or -EFAULT) 20 - * r1 is corrupted (will contain "current_task"). 21 - * 22 - * These functions should not modify any other registers, 23 - * as they get called from within inline assembly. 24 - */ 25 - 26 - #ifdef CONFIG_ISA_DUAL_ISSUE 27 - 28 - .text 29 - .balign 4 30 - .globl __put_user_1 31 - __put_user_1: 32 - 1: stb r1, @r0 || ldi r0, #0 33 - jmp r14 34 - 35 - .balign 4 36 - .globl __put_user_2 37 - __put_user_2: 38 - 2: sth r1, @r0 || ldi r0, #0 39 - jmp r14 40 - 41 - .balign 4 42 - .globl __put_user_4 43 - __put_user_4: 44 - 3: st r1, @r0 || ldi r0, #0 45 - jmp r14 46 - 47 - bad_put_user: 48 - ldi r0, #-14 || jmp r14 49 - 50 - #else /* not CONFIG_ISA_DUAL_ISSUE */ 51 - 52 - .text 53 - .balign 4 54 - .globl __put_user_1 55 - __put_user_1: 56 - 1: stb r1, @r0 57 - ldi r0, #0 58 - jmp r14 59 - 60 - .balign 4 61 - .globl __put_user_2 62 - __put_user_2: 63 - 2: sth r1, @r0 64 - ldi r0, #0 65 - jmp r14 66 - 67 - .balign 4 68 - .globl __put_user_4 69 - __put_user_4: 70 - 3: st r1, @r0 71 - ldi r0, #0 72 - jmp r14 73 - 74 - bad_put_user: 75 - ldi r0, #-14 76 - jmp r14 77 - 78 - #endif /* not CONFIG_ISA_DUAL_ISSUE */ 79 - 80 - .section __ex_table,"a" 81 - .long 1b,bad_put_user 82 - .long 2b,bad_put_user 83 - .long 3b,bad_put_user 84 - .previous
+115 -151
include/asm-m32r/uaccess.h
··· 5 5 * linux/include/asm-m32r/uaccess.h 6 6 * 7 7 * M32R version. 8 - * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> 8 + * Copyright (C) 2004, 2006 Hirokazu Takata <takata at linux-m32r.org> 9 9 */ 10 - 11 - #undef UACCESS_DEBUG 12 - 13 - #ifdef UACCESS_DEBUG 14 - #define UAPRINTK(args...) printk(args) 15 - #else 16 - #define UAPRINTK(args...) 17 - #endif /* UACCESS_DEBUG */ 18 10 19 11 /* 20 12 * User space memory access functions ··· 30 38 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) 31 39 32 40 #ifdef CONFIG_MMU 41 + 33 42 #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) 34 43 #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) 35 - #else 36 - #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) 37 - #define USER_DS MAKE_MM_SEG(0xFFFFFFFF) 38 - #endif /* CONFIG_MMU */ 39 - 40 44 #define get_ds() (KERNEL_DS) 41 - #ifdef CONFIG_MMU 42 45 #define get_fs() (current_thread_info()->addr_limit) 43 46 #define set_fs(x) (current_thread_info()->addr_limit = (x)) 44 - #else 47 + 48 + #else /* not CONFIG_MMU */ 49 + 50 + #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) 51 + #define USER_DS MAKE_MM_SEG(0xFFFFFFFF) 52 + #define get_ds() (KERNEL_DS) 53 + 45 54 static inline mm_segment_t get_fs(void) 46 55 { 47 - return USER_DS; 56 + return USER_DS; 48 57 } 49 58 50 59 static inline void set_fs(mm_segment_t s) 51 60 { 52 61 } 53 - #endif /* CONFIG_MMU */ 62 + 63 + #endif /* not CONFIG_MMU */ 54 64 55 65 #define segment_eq(a,b) ((a).seg == (b).seg) 56 66 ··· 77 83 " subx %0, %0\n" \ 78 84 " cmpu %4, %1\n" \ 79 85 " subx %0, %5\n" \ 80 - : "=&r"(flag), "=r"(sum) \ 81 - : "1"(addr), "r"((int)(size)), \ 82 - "r"(current_thread_info()->addr_limit.seg), "r"(0) \ 86 + : "=&r" (flag), "=r" (sum) \ 87 + : "1" (addr), "r" ((int)(size)), \ 88 + "r" (current_thread_info()->addr_limit.seg), "r" (0) \ 83 89 : "cbit" ); \ 84 90 flag; }) 85 91 ··· 107 113 #else 108 114 static inline int access_ok(int type, const void *addr, unsigned long size) 109 115 { 110 - extern unsigned long memory_start, memory_end; 111 - unsigned long val = (unsigned long)addr; 116 + extern unsigned long memory_start, memory_end; 117 + unsigned long val = (unsigned long)addr; 112 118 113 - return ((val >= memory_start) && ((val + size) < memory_end)); 119 + return ((val >= memory_start) && ((val + size) < memory_end)); 114 120 } 115 121 #endif /* CONFIG_MMU */ 116 122 ··· 149 155 * accesses to the same area of user memory). 150 156 */ 151 157 152 - extern void __get_user_1(void); 153 - extern void __get_user_2(void); 154 - extern void __get_user_4(void); 155 - 156 - #ifndef MODULE 157 - #define __get_user_x(size,ret,x,ptr) \ 158 - __asm__ __volatile__( \ 159 - " mv r0, %0\n" \ 160 - " mv r1, %1\n" \ 161 - " bl __get_user_" #size "\n" \ 162 - " mv %0, r0\n" \ 163 - " mv %1, r1\n" \ 164 - : "=r"(ret), "=r"(x) \ 165 - : "0"(ptr) \ 166 - : "r0", "r1", "r14" ) 167 - #else /* MODULE */ 168 - /* 169 - * Use "jl" instead of "bl" for MODULE 170 - */ 171 - #define __get_user_x(size,ret,x,ptr) \ 172 - __asm__ __volatile__( \ 173 - " mv r0, %0\n" \ 174 - " mv r1, %1\n" \ 175 - " seth lr, #high(__get_user_" #size ")\n" \ 176 - " or3 lr, lr, #low(__get_user_" #size ")\n" \ 177 - " jl lr\n" \ 178 - " mv %0, r0\n" \ 179 - " mv %1, r1\n" \ 180 - : "=r"(ret), "=r"(x) \ 181 - : "0"(ptr) \ 182 - : "r0", "r1", "r14" ) 183 - #endif 184 - 185 158 /* Careful: we have to cast the result to the type of the pointer for sign 186 159 reasons */ 187 160 /** ··· 169 208 * On error, the variable @x is set to zero. 170 209 */ 171 210 #define get_user(x,ptr) \ 172 - ({ int __ret_gu; \ 173 - unsigned long __val_gu; \ 174 - __chk_user_ptr(ptr); \ 175 - switch(sizeof (*(ptr))) { \ 176 - case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ 177 - case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ 178 - case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break; \ 179 - default: __get_user_x(X,__ret_gu,__val_gu,ptr); break; \ 180 - } \ 181 - (x) = (__typeof__(*(ptr)))__val_gu; \ 182 - __ret_gu; \ 183 - }) 184 - 185 - extern void __put_user_bad(void); 211 + __get_user_check((x),(ptr),sizeof(*(ptr))) 186 212 187 213 /** 188 214 * put_user: - Write a simple value into user space. ··· 188 240 * Returns zero on success, or -EFAULT on error. 189 241 */ 190 242 #define put_user(x,ptr) \ 191 - __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) 192 - 243 + __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) 193 244 194 245 /** 195 246 * __get_user: - Get a simple variable from user space, with less checking. ··· 211 264 * On error, the variable @x is set to zero. 212 265 */ 213 266 #define __get_user(x,ptr) \ 214 - __get_user_nocheck((x),(ptr),sizeof(*(ptr))) 267 + __get_user_nocheck((x),(ptr),sizeof(*(ptr))) 215 268 269 + #define __get_user_nocheck(x,ptr,size) \ 270 + ({ \ 271 + long __gu_err = 0; \ 272 + unsigned long __gu_val; \ 273 + might_sleep(); \ 274 + __get_user_size(__gu_val,(ptr),(size),__gu_err); \ 275 + (x) = (__typeof__(*(ptr)))__gu_val; \ 276 + __gu_err; \ 277 + }) 278 + 279 + #define __get_user_check(x,ptr,size) \ 280 + ({ \ 281 + long __gu_err = -EFAULT; \ 282 + unsigned long __gu_val = 0; \ 283 + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ 284 + might_sleep(); \ 285 + if (access_ok(VERIFY_READ,__gu_addr,size)) \ 286 + __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ 287 + (x) = (__typeof__(*(ptr)))__gu_val; \ 288 + __gu_err; \ 289 + }) 290 + 291 + extern long __get_user_bad(void); 292 + 293 + #define __get_user_size(x,ptr,size,retval) \ 294 + do { \ 295 + retval = 0; \ 296 + __chk_user_ptr(ptr); \ 297 + switch (size) { \ 298 + case 1: __get_user_asm(x,ptr,retval,"ub"); break; \ 299 + case 2: __get_user_asm(x,ptr,retval,"uh"); break; \ 300 + case 4: __get_user_asm(x,ptr,retval,""); break; \ 301 + default: (x) = __get_user_bad(); \ 302 + } \ 303 + } while (0) 304 + 305 + #define __get_user_asm(x, addr, err, itype) \ 306 + __asm__ __volatile__( \ 307 + " .fillinsn\n" \ 308 + "1: ld"itype" %1,@%2\n" \ 309 + " .fillinsn\n" \ 310 + "2:\n" \ 311 + ".section .fixup,\"ax\"\n" \ 312 + " .balign 4\n" \ 313 + "3: ldi %0,%3\n" \ 314 + " seth r14,#high(2b)\n" \ 315 + " or3 r14,r14,#low(2b)\n" \ 316 + " jmp r14\n" \ 317 + ".previous\n" \ 318 + ".section __ex_table,\"a\"\n" \ 319 + " .balign 4\n" \ 320 + " .long 1b,3b\n" \ 321 + ".previous" \ 322 + : "=&r" (err), "=&r" (x) \ 323 + : "r" (addr), "i" (-EFAULT), "0" (err) \ 324 + : "r14", "memory") 216 325 217 326 /** 218 327 * __put_user: - Write a simple value into user space, with less checking. ··· 290 287 * Returns zero on success, or -EFAULT on error. 291 288 */ 292 289 #define __put_user(x,ptr) \ 293 - __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) 290 + __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) 291 + 294 292 295 293 #define __put_user_nocheck(x,ptr,size) \ 296 294 ({ \ 297 295 long __pu_err; \ 296 + might_sleep(); \ 298 297 __put_user_size((x),(ptr),(size),__pu_err); \ 299 298 __pu_err; \ 300 299 }) ··· 313 308 }) 314 309 315 310 #if defined(__LITTLE_ENDIAN__) 316 - #define __put_user_u64(x, addr, err) \ 317 - __asm__ __volatile__( \ 318 - " .fillinsn\n" \ 319 - "1: st %L1,@%2\n" \ 320 - " .fillinsn\n" \ 321 - "2: st %H1,@(4,%2)\n" \ 322 - " .fillinsn\n" \ 323 - "3:\n" \ 324 - ".section .fixup,\"ax\"\n" \ 325 - " .balign 4\n" \ 326 - "4: ldi %0,%3\n" \ 327 - " seth r14,#high(3b)\n" \ 328 - " or3 r14,r14,#low(3b)\n" \ 329 - " jmp r14\n" \ 330 - ".previous\n" \ 331 - ".section __ex_table,\"a\"\n" \ 332 - " .balign 4\n" \ 333 - " .long 1b,4b\n" \ 334 - " .long 2b,4b\n" \ 335 - ".previous" \ 336 - : "=&r"(err) \ 337 - : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ 311 + #define __put_user_u64(x, addr, err) \ 312 + __asm__ __volatile__( \ 313 + " .fillinsn\n" \ 314 + "1: st %L1,@%2\n" \ 315 + " .fillinsn\n" \ 316 + "2: st %H1,@(4,%2)\n" \ 317 + " .fillinsn\n" \ 318 + "3:\n" \ 319 + ".section .fixup,\"ax\"\n" \ 320 + " .balign 4\n" \ 321 + "4: ldi %0,%3\n" \ 322 + " seth r14,#high(3b)\n" \ 323 + " or3 r14,r14,#low(3b)\n" \ 324 + " jmp r14\n" \ 325 + ".previous\n" \ 326 + ".section __ex_table,\"a\"\n" \ 327 + " .balign 4\n" \ 328 + " .long 1b,4b\n" \ 329 + " .long 2b,4b\n" \ 330 + ".previous" \ 331 + : "=&r" (err) \ 332 + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ 338 333 : "r14", "memory") 339 334 340 335 #elif defined(__BIG_ENDIAN__) ··· 358 353 " .long 1b,4b\n" \ 359 354 " .long 2b,4b\n" \ 360 355 ".previous" \ 361 - : "=&r"(err) \ 362 - : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ 356 + : "=&r" (err) \ 357 + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ 363 358 : "r14", "memory") 364 359 #else 365 360 #error no endian defined 366 361 #endif 362 + 363 + extern void __put_user_bad(void); 367 364 368 365 #define __put_user_size(x,ptr,size,retval) \ 369 366 do { \ ··· 405 398 " .balign 4\n" \ 406 399 " .long 1b,3b\n" \ 407 400 ".previous" \ 408 - : "=&r"(err) \ 409 - : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ 410 - : "r14", "memory") 411 - 412 - #define __get_user_nocheck(x,ptr,size) \ 413 - ({ \ 414 - long __gu_err; \ 415 - unsigned long __gu_val; \ 416 - __get_user_size(__gu_val,(ptr),(size),__gu_err); \ 417 - (x) = (__typeof__(*(ptr)))__gu_val; \ 418 - __gu_err; \ 419 - }) 420 - 421 - extern long __get_user_bad(void); 422 - 423 - #define __get_user_size(x,ptr,size,retval) \ 424 - do { \ 425 - retval = 0; \ 426 - __chk_user_ptr(ptr); \ 427 - switch (size) { \ 428 - case 1: __get_user_asm(x,ptr,retval,"ub"); break; \ 429 - case 2: __get_user_asm(x,ptr,retval,"uh"); break; \ 430 - case 4: __get_user_asm(x,ptr,retval,""); break; \ 431 - default: (x) = __get_user_bad(); \ 432 - } \ 433 - } while (0) 434 - 435 - #define __get_user_asm(x, addr, err, itype) \ 436 - __asm__ __volatile__( \ 437 - " .fillinsn\n" \ 438 - "1: ld"itype" %1,@%2\n" \ 439 - " .fillinsn\n" \ 440 - "2:\n" \ 441 - ".section .fixup,\"ax\"\n" \ 442 - " .balign 4\n" \ 443 - "3: ldi %0,%3\n" \ 444 - " seth r14,#high(2b)\n" \ 445 - " or3 r14,r14,#low(2b)\n" \ 446 - " jmp r14\n" \ 447 - ".previous\n" \ 448 - ".section __ex_table,\"a\"\n" \ 449 - " .balign 4\n" \ 450 - " .long 1b,3b\n" \ 451 - ".previous" \ 452 - : "=&r"(err), "=&r"(x) \ 453 - : "r"(addr), "i"(-EFAULT), "0"(err) \ 401 + : "=&r" (err) \ 402 + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ 454 403 : "r14", "memory") 455 404 456 405 /* ··· 415 452 * If a store crosses a page boundary and gets a fault, the m32r will not write 416 453 * anything, so this is accurate. 417 454 */ 418 - 419 455 420 456 /* 421 457 * Copy To/From Userspace ··· 473 511 " .long 2b,9b\n" \ 474 512 " .long 3b,9b\n" \ 475 513 ".previous\n" \ 476 - : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c) \ 477 - : "0"(to), "1"(from), "2"(size), "3"(size / 4) \ 514 + : "=&r" (__dst), "=&r" (__src), "=&r" (size), \ 515 + "=&r" (__c) \ 516 + : "0" (to), "1" (from), "2" (size), "3" (size / 4) \ 478 517 : "r14", "memory"); \ 479 518 } while (0) 480 519 ··· 536 573 " .long 2b,7b\n" \ 537 574 " .long 3b,7b\n" \ 538 575 ".previous\n" \ 539 - : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c) \ 540 - : "0"(to), "1"(from), "2"(size), "3"(size / 4) \ 576 + : "=&r" (__dst), "=&r" (__src), "=&r" (size), \ 577 + "=&r" (__c) \ 578 + : "0" (to), "1" (from), "2" (size), "3" (size / 4) \ 541 579 : "r14", "memory"); \ 542 580 } while (0) 543 581 ··· 640 676 #define copy_from_user(to,from,n) \ 641 677 ({ \ 642 678 might_sleep(); \ 643 - __generic_copy_from_user((to),(from),(n)); \ 679 + __generic_copy_from_user((to),(from),(n)); \ 644 680 }) 645 681 646 682 long __must_check strncpy_from_user(char *dst, const char __user *src,