aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/uaccess.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/include/asm/uaccess.h')
-rw-r--r--arch/x86/include/asm/uaccess.h98
1 files changed, 98 insertions, 0 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