aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2017-02-15 19:43:58 -0500
committerRussell King <rmk+kernel@armlinux.org.uk>2017-02-16 10:58:31 -0500
commit32b143637e8180f5d5cea54320c769210dea4f19 (patch)
tree636eec0a91ac1dfffdd9208539633cc8ccb0417a
parent228dbbfb5d77f8e047b2a1d78da14b7158433027 (diff)
ARM: 8657/1: uaccess: consistently check object sizes
In commit 76624175dcae ("arm64: uaccess: consistently check object sizes"), the object size checks are moved outside the access_ok() so that bad destinations are detected before hitting the "memset(dest, 0, size)" in the copy_from_user() failure path. This makes the same change for arm, with attention given to possibly extracting the uaccess routines into a common header file for all architectures in the future. Suggested-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/include/asm/uaccess.h44
1 files changed, 32 insertions, 12 deletions
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 1f59ea051bab..b7e0125c0bbf 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -478,11 +478,10 @@ extern unsigned long __must_check
478arm_copy_from_user(void *to, const void __user *from, unsigned long n); 478arm_copy_from_user(void *to, const void __user *from, unsigned long n);
479 479
480static inline unsigned long __must_check 480static inline unsigned long __must_check
481__copy_from_user(void *to, const void __user *from, unsigned long n) 481__arch_copy_from_user(void *to, const void __user *from, unsigned long n)
482{ 482{
483 unsigned int __ua_flags; 483 unsigned int __ua_flags;
484 484
485 check_object_size(to, n, false);
486 __ua_flags = uaccess_save_and_enable(); 485 __ua_flags = uaccess_save_and_enable();
487 n = arm_copy_from_user(to, from, n); 486 n = arm_copy_from_user(to, from, n);
488 uaccess_restore(__ua_flags); 487 uaccess_restore(__ua_flags);
@@ -495,18 +494,15 @@ extern unsigned long __must_check
495__copy_to_user_std(void __user *to, const void *from, unsigned long n); 494__copy_to_user_std(void __user *to, const void *from, unsigned long n);
496 495
497static inline unsigned long __must_check 496static inline unsigned long __must_check
498__copy_to_user(void __user *to, const void *from, unsigned long n) 497__arch_copy_to_user(void __user *to, const void *from, unsigned long n)
499{ 498{
500#ifndef CONFIG_UACCESS_WITH_MEMCPY 499#ifndef CONFIG_UACCESS_WITH_MEMCPY
501 unsigned int __ua_flags; 500 unsigned int __ua_flags;
502
503 check_object_size(from, n, true);
504 __ua_flags = uaccess_save_and_enable(); 501 __ua_flags = uaccess_save_and_enable();
505 n = arm_copy_to_user(to, from, n); 502 n = arm_copy_to_user(to, from, n);
506 uaccess_restore(__ua_flags); 503 uaccess_restore(__ua_flags);
507 return n; 504 return n;
508#else 505#else
509 check_object_size(from, n, true);
510 return arm_copy_to_user(to, from, n); 506 return arm_copy_to_user(to, from, n);
511#endif 507#endif
512} 508}
@@ -526,25 +522,49 @@ __clear_user(void __user *addr, unsigned long n)
526} 522}
527 523
528#else 524#else
529#define __copy_from_user(to, from, n) (memcpy(to, (void __force *)from, n), 0) 525#define __arch_copy_from_user(to, from, n) \
530#define __copy_to_user(to, from, n) (memcpy((void __force *)to, from, n), 0) 526 (memcpy(to, (void __force *)from, n), 0)
527#define __arch_copy_to_user(to, from, n) \
528 (memcpy((void __force *)to, from, n), 0)
531#define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0) 529#define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0)
532#endif 530#endif
533 531
534static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) 532static inline unsigned long __must_check
533__copy_from_user(void *to, const void __user *from, unsigned long n)
534{
535 check_object_size(to, n, false);
536 return __arch_copy_from_user(to, from, n);
537}
538
539static inline unsigned long __must_check
540copy_from_user(void *to, const void __user *from, unsigned long n)
535{ 541{
536 unsigned long res = n; 542 unsigned long res = n;
543
544 check_object_size(to, n, false);
545
537 if (likely(access_ok(VERIFY_READ, from, n))) 546 if (likely(access_ok(VERIFY_READ, from, n)))
538 res = __copy_from_user(to, from, n); 547 res = __arch_copy_from_user(to, from, n);
539 if (unlikely(res)) 548 if (unlikely(res))
540 memset(to + (n - res), 0, res); 549 memset(to + (n - res), 0, res);
541 return res; 550 return res;
542} 551}
543 552
544static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) 553static inline unsigned long __must_check
554__copy_to_user(void __user *to, const void *from, unsigned long n)
545{ 555{
556 check_object_size(from, n, true);
557
558 return __arch_copy_to_user(to, from, n);
559}
560
561static inline unsigned long __must_check
562copy_to_user(void __user *to, const void *from, unsigned long n)
563{
564 check_object_size(from, n, true);
565
546 if (access_ok(VERIFY_WRITE, to, n)) 566 if (access_ok(VERIFY_WRITE, to, n))
547 n = __copy_to_user(to, from, n); 567 n = __arch_copy_to_user(to, from, n);
548 return n; 568 return n;
549} 569}
550 570