aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/uaccess.h98
-rw-r--r--arch/x86/include/asm/uaccess_32.h29
-rw-r--r--arch/x86/include/asm/uaccess_64.h28
-rw-r--r--arch/x86/lib/usercopy_32.c8
4 files changed, 101 insertions, 62 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 5838fa911aa0..8ec57c07b125 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -542,5 +542,103 @@ extern struct movsl_mask {
542# include <asm/uaccess_64.h> 542# include <asm/uaccess_64.h>
543#endif 543#endif
544 544
545unsigned long __must_check _copy_from_user(void *to, const void __user *from,
546 unsigned n);
547unsigned long __must_check _copy_to_user(void __user *to, const void *from,
548 unsigned n);
549
550#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
551# define copy_user_diag __compiletime_error
552#else
553# define copy_user_diag __compiletime_warning
554#endif
555
556extern void copy_user_diag("copy_from_user() buffer size is too small")
557copy_from_user_overflow(void);
558extern void copy_user_diag("copy_to_user() buffer size is too small")
559copy_to_user_overflow(void) __asm__("copy_from_user_overflow");
560
561#undef copy_user_diag
562
563#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
564
565extern void
566__compiletime_warning("copy_from_user() buffer size is not provably correct")
567__copy_from_user_overflow(void) __asm__("copy_from_user_overflow");
568#define __copy_from_user_overflow(size, count) __copy_from_user_overflow()
569
570extern 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
575#else
576
577static inline void
578__copy_from_user_overflow(int size, unsigned long count)
579{
580 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
581}
582
583#define __copy_to_user_overflow __copy_from_user_overflow
584
585#endif
586
587static inline unsigned long __must_check
588copy_from_user(void *to, const void __user *from, unsigned long n)
589{
590 int sz = __compiletime_object_size(to);
591
592 might_fault();
593
594 /*
595 * While we would like to have the compiler do the checking for us
596 * even in the non-constant size case, any false positives there are
597 * a problem (especially when DEBUG_STRICT_USER_COPY_CHECKS, but even
598 * without - the [hopefully] dangerous looking nature of the warning
599 * would make people go look at the respecitive call sites over and
600 * over again just to find that there's no problem).
601 *
602 * And there are cases where it's just not realistic for the compiler
603 * to prove the count to be in range. For example when multiple call
604 * sites of a helper function - perhaps in different source files -
605 * all doing proper range checking, yet the helper function not doing
606 * so again.
607 *
608 * Therefore limit the compile time checking to the constant size
609 * case, and do only runtime checking for non-constant sizes.
610 */
611
612 if (likely(sz < 0 || sz >= n))
613 n = _copy_from_user(to, from, n);
614 else if(__builtin_constant_p(n))
615 copy_from_user_overflow();
616 else
617 __copy_from_user_overflow(sz, n);
618
619 return n;
620}
621
622static inline unsigned long __must_check
623copy_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
640#undef __copy_from_user_overflow
641#undef __copy_to_user_overflow
642
545#endif /* _ASM_X86_UACCESS_H */ 643#endif /* _ASM_X86_UACCESS_H */
546 644
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 7f760a9f1f61..3c03a5de64d3 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -184,33 +184,4 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from,
184 return __copy_from_user_ll_nocache_nozero(to, from, n); 184 return __copy_from_user_ll_nocache_nozero(to, from, n);
185} 185}
186 186
187unsigned long __must_check copy_to_user(void __user *to,
188 const void *from, unsigned long n);
189unsigned long __must_check _copy_from_user(void *to,
190 const void __user *from,
191 unsigned long n);
192
193
194extern void copy_from_user_overflow(void)
195#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
196 __compiletime_error("copy_from_user() buffer size is not provably correct")
197#else
198 __compiletime_warning("copy_from_user() buffer size is not provably correct")
199#endif
200;
201
202static inline unsigned long __must_check copy_from_user(void *to,
203 const void __user *from,
204 unsigned long n)
205{
206 int sz = __compiletime_object_size(to);
207
208 if (likely(sz == -1 || sz >= n))
209 n = _copy_from_user(to, from, n);
210 else
211 copy_from_user_overflow();
212
213 return n;
214}
215
216#endif /* _ASM_X86_UACCESS_32_H */ 187#endif /* _ASM_X86_UACCESS_32_H */
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 4f7923dd0007..0acae710fa00 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -46,36 +46,8 @@ copy_user_generic(void *to, const void *from, unsigned len)
46} 46}
47 47
48__must_check unsigned long 48__must_check unsigned long
49_copy_to_user(void __user *to, const void *from, unsigned len);
50__must_check unsigned long
51_copy_from_user(void *to, const void __user *from, unsigned len);
52__must_check unsigned long
53copy_in_user(void __user *to, const void __user *from, unsigned len); 49copy_in_user(void __user *to, const void __user *from, unsigned len);
54 50
55static inline unsigned long __must_check copy_from_user(void *to,
56 const void __user *from,
57 unsigned long n)
58{
59 int sz = __compiletime_object_size(to);
60
61 might_fault();
62 if (likely(sz == -1 || sz >= n))
63 n = _copy_from_user(to, from, n);
64#ifdef CONFIG_DEBUG_VM
65 else
66 WARN(1, "Buffer overflow detected!\n");
67#endif
68 return n;
69}
70
71static __always_inline __must_check
72int copy_to_user(void __user *dst, const void *src, unsigned size)
73{
74 might_fault();
75
76 return _copy_to_user(dst, src, size);
77}
78
79static __always_inline __must_check 51static __always_inline __must_check
80int __copy_from_user(void *dst, const void __user *src, unsigned size) 52int __copy_from_user(void *dst, const void __user *src, unsigned size)
81{ 53{
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 3eb18acd0e40..e2f5e21c03b3 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -654,14 +654,13 @@ EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
654 * Returns number of bytes that could not be copied. 654 * Returns number of bytes that could not be copied.
655 * On success, this will be zero. 655 * On success, this will be zero.
656 */ 656 */
657unsigned long 657unsigned long _copy_to_user(void __user *to, const void *from, unsigned n)
658copy_to_user(void __user *to, const void *from, unsigned long n)
659{ 658{
660 if (access_ok(VERIFY_WRITE, to, n)) 659 if (access_ok(VERIFY_WRITE, to, n))
661 n = __copy_to_user(to, from, n); 660 n = __copy_to_user(to, from, n);
662 return n; 661 return n;
663} 662}
664EXPORT_SYMBOL(copy_to_user); 663EXPORT_SYMBOL(_copy_to_user);
665 664
666/** 665/**
667 * copy_from_user: - Copy a block of data from user space. 666 * copy_from_user: - Copy a block of data from user space.
@@ -679,8 +678,7 @@ EXPORT_SYMBOL(copy_to_user);
679 * If some data could not be copied, this function will pad the copied 678 * If some data could not be copied, this function will pad the copied
680 * data to the requested size using zero bytes. 679 * data to the requested size using zero bytes.
681 */ 680 */
682unsigned long 681unsigned long _copy_from_user(void *to, const void __user *from, unsigned n)
683_copy_from_user(void *to, const void __user *from, unsigned long n)
684{ 682{
685 if (access_ok(VERIFY_READ, from, n)) 683 if (access_ok(VERIFY_READ, from, n))
686 n = __copy_from_user(to, from, n); 684 n = __copy_from_user(to, from, n);