diff options
Diffstat (limited to 'arch/x86/include/asm/uaccess.h')
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 124 |
1 files changed, 112 insertions, 12 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 8ec57c07b125..0d592e0a5b84 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -40,22 +40,30 @@ | |||
40 | /* | 40 | /* |
41 | * Test whether a block of memory is a valid user space address. | 41 | * Test whether a block of memory is a valid user space address. |
42 | * Returns 0 if the range is valid, nonzero otherwise. | 42 | * Returns 0 if the range is valid, nonzero otherwise. |
43 | * | ||
44 | * This is equivalent to the following test: | ||
45 | * (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64) | ||
46 | * | ||
47 | * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... | ||
48 | */ | 43 | */ |
44 | static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, unsigned long limit) | ||
45 | { | ||
46 | /* | ||
47 | * If we have used "sizeof()" for the size, | ||
48 | * we know it won't overflow the limit (but | ||
49 | * it might overflow the 'addr', so it's | ||
50 | * important to subtract the size from the | ||
51 | * limit, not add it to the address). | ||
52 | */ | ||
53 | if (__builtin_constant_p(size)) | ||
54 | return addr > limit - size; | ||
55 | |||
56 | /* Arbitrary sizes? Be careful about overflow */ | ||
57 | addr += size; | ||
58 | if (addr < size) | ||
59 | return true; | ||
60 | return addr > limit; | ||
61 | } | ||
49 | 62 | ||
50 | #define __range_not_ok(addr, size, limit) \ | 63 | #define __range_not_ok(addr, size, limit) \ |
51 | ({ \ | 64 | ({ \ |
52 | unsigned long flag, roksum; \ | ||
53 | __chk_user_ptr(addr); \ | 65 | __chk_user_ptr(addr); \ |
54 | asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ | 66 | __chk_range_not_ok((unsigned long __force)(addr), size, limit); \ |
55 | : "=&r" (flag), "=r" (roksum) \ | ||
56 | : "1" (addr), "g" ((long)(size)), \ | ||
57 | "rm" (limit)); \ | ||
58 | flag; \ | ||
59 | }) | 67 | }) |
60 | 68 | ||
61 | /** | 69 | /** |
@@ -78,7 +86,7 @@ | |||
78 | * this function, memory access functions may still return -EFAULT. | 86 | * this function, memory access functions may still return -EFAULT. |
79 | */ | 87 | */ |
80 | #define access_ok(type, addr, size) \ | 88 | #define access_ok(type, addr, size) \ |
81 | (likely(__range_not_ok(addr, size, user_addr_max()) == 0)) | 89 | likely(!__range_not_ok(addr, size, user_addr_max())) |
82 | 90 | ||
83 | /* | 91 | /* |
84 | * The exception table consists of pairs of addresses relative to the | 92 | * The exception table consists of pairs of addresses relative to the |
@@ -525,6 +533,98 @@ extern __must_check long strnlen_user(const char __user *str, long n); | |||
525 | unsigned long __must_check clear_user(void __user *mem, unsigned long len); | 533 | unsigned long __must_check clear_user(void __user *mem, unsigned long len); |
526 | unsigned long __must_check __clear_user(void __user *mem, unsigned long len); | 534 | unsigned long __must_check __clear_user(void __user *mem, unsigned long len); |
527 | 535 | ||
536 | extern void __cmpxchg_wrong_size(void) | ||
537 | __compiletime_error("Bad argument size for cmpxchg"); | ||
538 | |||
539 | #define __user_atomic_cmpxchg_inatomic(uval, ptr, old, new, size) \ | ||
540 | ({ \ | ||
541 | int __ret = 0; \ | ||
542 | __typeof__(ptr) __uval = (uval); \ | ||
543 | __typeof__(*(ptr)) __old = (old); \ | ||
544 | __typeof__(*(ptr)) __new = (new); \ | ||
545 | switch (size) { \ | ||
546 | case 1: \ | ||
547 | { \ | ||
548 | asm volatile("\t" ASM_STAC "\n" \ | ||
549 | "1:\t" LOCK_PREFIX "cmpxchgb %4, %2\n" \ | ||
550 | "2:\t" ASM_CLAC "\n" \ | ||
551 | "\t.section .fixup, \"ax\"\n" \ | ||
552 | "3:\tmov %3, %0\n" \ | ||
553 | "\tjmp 2b\n" \ | ||
554 | "\t.previous\n" \ | ||
555 | _ASM_EXTABLE(1b, 3b) \ | ||
556 | : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ | ||
557 | : "i" (-EFAULT), "q" (__new), "1" (__old) \ | ||
558 | : "memory" \ | ||
559 | ); \ | ||
560 | break; \ | ||
561 | } \ | ||
562 | case 2: \ | ||
563 | { \ | ||
564 | asm volatile("\t" ASM_STAC "\n" \ | ||
565 | "1:\t" LOCK_PREFIX "cmpxchgw %4, %2\n" \ | ||
566 | "2:\t" ASM_CLAC "\n" \ | ||
567 | "\t.section .fixup, \"ax\"\n" \ | ||
568 | "3:\tmov %3, %0\n" \ | ||
569 | "\tjmp 2b\n" \ | ||
570 | "\t.previous\n" \ | ||
571 | _ASM_EXTABLE(1b, 3b) \ | ||
572 | : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ | ||
573 | : "i" (-EFAULT), "r" (__new), "1" (__old) \ | ||
574 | : "memory" \ | ||
575 | ); \ | ||
576 | break; \ | ||
577 | } \ | ||
578 | case 4: \ | ||
579 | { \ | ||
580 | asm volatile("\t" ASM_STAC "\n" \ | ||
581 | "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n" \ | ||
582 | "2:\t" ASM_CLAC "\n" \ | ||
583 | "\t.section .fixup, \"ax\"\n" \ | ||
584 | "3:\tmov %3, %0\n" \ | ||
585 | "\tjmp 2b\n" \ | ||
586 | "\t.previous\n" \ | ||
587 | _ASM_EXTABLE(1b, 3b) \ | ||
588 | : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ | ||
589 | : "i" (-EFAULT), "r" (__new), "1" (__old) \ | ||
590 | : "memory" \ | ||
591 | ); \ | ||
592 | break; \ | ||
593 | } \ | ||
594 | case 8: \ | ||
595 | { \ | ||
596 | if (!IS_ENABLED(CONFIG_X86_64)) \ | ||
597 | __cmpxchg_wrong_size(); \ | ||
598 | \ | ||
599 | asm volatile("\t" ASM_STAC "\n" \ | ||
600 | "1:\t" LOCK_PREFIX "cmpxchgq %4, %2\n" \ | ||
601 | "2:\t" ASM_CLAC "\n" \ | ||
602 | "\t.section .fixup, \"ax\"\n" \ | ||
603 | "3:\tmov %3, %0\n" \ | ||
604 | "\tjmp 2b\n" \ | ||
605 | "\t.previous\n" \ | ||
606 | _ASM_EXTABLE(1b, 3b) \ | ||
607 | : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ | ||
608 | : "i" (-EFAULT), "r" (__new), "1" (__old) \ | ||
609 | : "memory" \ | ||
610 | ); \ | ||
611 | break; \ | ||
612 | } \ | ||
613 | default: \ | ||
614 | __cmpxchg_wrong_size(); \ | ||
615 | } \ | ||
616 | *__uval = __old; \ | ||
617 | __ret; \ | ||
618 | }) | ||
619 | |||
620 | #define user_atomic_cmpxchg_inatomic(uval, ptr, old, new) \ | ||
621 | ({ \ | ||
622 | access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ? \ | ||
623 | __user_atomic_cmpxchg_inatomic((uval), (ptr), \ | ||
624 | (old), (new), sizeof(*(ptr))) : \ | ||
625 | -EFAULT; \ | ||
626 | }) | ||
627 | |||
528 | /* | 628 | /* |
529 | * movsl can be slow when source and dest are not both 8-byte aligned | 629 | * movsl can be slow when source and dest are not both 8-byte aligned |
530 | */ | 630 | */ |