diff options
author | Jan Beulich <JBeulich@suse.com> | 2013-10-21 04:44:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-10-26 06:27:37 -0400 |
commit | 7a3d9b0f3abbea957b829cdfff8169872c575642 (patch) | |
tree | 905bb8d2f62b5bee5b1523ed6dff08dc81551763 /arch/x86/include/asm/uaccess.h | |
parent | 3df7b41aa5e7797f391d0a41f8b0dce1fe366a09 (diff) |
x86: Unify copy_to_user() and add size checking to it
Similarly to copy_from_user(), where the range check is to
protect against kernel memory corruption, copy_to_user() can
benefit from such checking too: Here it protects against kernel
information leaks.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Cc: <arjan@linux.intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/5265059502000078000FC4F6@nat28.tlf.novell.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Diffstat (limited to 'arch/x86/include/asm/uaccess.h')
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index c9799ed208a8..8ec57c07b125 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -544,6 +544,8 @@ extern struct movsl_mask { | |||
544 | 544 | ||
545 | unsigned long __must_check _copy_from_user(void *to, const void __user *from, | 545 | unsigned long __must_check _copy_from_user(void *to, const void __user *from, |
546 | unsigned n); | 546 | unsigned n); |
547 | unsigned long __must_check _copy_to_user(void __user *to, const void *from, | ||
548 | unsigned n); | ||
547 | 549 | ||
548 | #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS | 550 | #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS |
549 | # define copy_user_diag __compiletime_error | 551 | # define copy_user_diag __compiletime_error |
@@ -553,6 +555,8 @@ unsigned long __must_check _copy_from_user(void *to, const void __user *from, | |||
553 | 555 | ||
554 | extern void copy_user_diag("copy_from_user() buffer size is too small") | 556 | extern void copy_user_diag("copy_from_user() buffer size is too small") |
555 | copy_from_user_overflow(void); | 557 | copy_from_user_overflow(void); |
558 | extern void copy_user_diag("copy_to_user() buffer size is too small") | ||
559 | copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); | ||
556 | 560 | ||
557 | #undef copy_user_diag | 561 | #undef copy_user_diag |
558 | 562 | ||
@@ -563,6 +567,11 @@ __compiletime_warning("copy_from_user() buffer size is not provably correct") | |||
563 | __copy_from_user_overflow(void) __asm__("copy_from_user_overflow"); | 567 | __copy_from_user_overflow(void) __asm__("copy_from_user_overflow"); |
564 | #define __copy_from_user_overflow(size, count) __copy_from_user_overflow() | 568 | #define __copy_from_user_overflow(size, count) __copy_from_user_overflow() |
565 | 569 | ||
570 | extern void | ||
571 | __compiletime_warning("copy_to_user() buffer size is not provably correct") | ||
572 | __copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); | ||
573 | #define __copy_to_user_overflow(size, count) __copy_to_user_overflow() | ||
574 | |||
566 | #else | 575 | #else |
567 | 576 | ||
568 | static inline void | 577 | static inline void |
@@ -571,6 +580,8 @@ __copy_from_user_overflow(int size, unsigned long count) | |||
571 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); | 580 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); |
572 | } | 581 | } |
573 | 582 | ||
583 | #define __copy_to_user_overflow __copy_from_user_overflow | ||
584 | |||
574 | #endif | 585 | #endif |
575 | 586 | ||
576 | static inline unsigned long __must_check | 587 | static inline unsigned long __must_check |
@@ -608,7 +619,26 @@ copy_from_user(void *to, const void __user *from, unsigned long n) | |||
608 | return n; | 619 | return n; |
609 | } | 620 | } |
610 | 621 | ||
622 | static inline unsigned long __must_check | ||
623 | copy_to_user(void __user *to, const void *from, unsigned long n) | ||
624 | { | ||
625 | int sz = __compiletime_object_size(from); | ||
626 | |||
627 | might_fault(); | ||
628 | |||
629 | /* See the comment in copy_from_user() above. */ | ||
630 | if (likely(sz < 0 || sz >= n)) | ||
631 | n = _copy_to_user(to, from, n); | ||
632 | else if(__builtin_constant_p(n)) | ||
633 | copy_to_user_overflow(); | ||
634 | else | ||
635 | __copy_to_user_overflow(sz, n); | ||
636 | |||
637 | return n; | ||
638 | } | ||
639 | |||
611 | #undef __copy_from_user_overflow | 640 | #undef __copy_from_user_overflow |
641 | #undef __copy_to_user_overflow | ||
612 | 642 | ||
613 | #endif /* _ASM_X86_UACCESS_H */ | 643 | #endif /* _ASM_X86_UACCESS_H */ |
614 | 644 | ||