Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

metag/usercopy: Zero rest of buffer from copy_from_user

Currently we try to zero the destination for a failed read from userland
in fixup code in the usercopy.c macros. The rest of the destination
buffer is then zeroed from __copy_user_zeroing(), which is used for both
copy_from_user() and __copy_from_user().

Unfortunately we fail to zero in the fixup code as D1Ar1 is set to 0
before the fixup code entry labels, and __copy_from_user() shouldn't even
be zeroing the rest of the buffer.

Move the zeroing out into copy_from_user() and rename
__copy_user_zeroing() to raw_copy_from_user() since it no longer does
any zeroing. This also conveniently matches the name needed for
RAW_COPY_USER support in a later patch.

Fixes: 373cd784d0fc ("metag: Memory handling")
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: linux-metag@vger.kernel.org
Cc: stable@vger.kernel.org

+26 -46
+8 -7
arch/metag/include/asm/uaccess.h
··· 197 197 198 198 #define strlen_user(str) strnlen_user(str, 32767) 199 199 200 - extern unsigned long __must_check __copy_user_zeroing(void *to, 201 - const void __user *from, 202 - unsigned long n); 200 + extern unsigned long raw_copy_from_user(void *to, const void __user *from, 201 + unsigned long n); 203 202 204 203 static inline unsigned long 205 204 copy_from_user(void *to, const void __user *from, unsigned long n) 206 205 { 206 + unsigned long res = n; 207 207 if (likely(access_ok(VERIFY_READ, from, n))) 208 - return __copy_user_zeroing(to, from, n); 209 - memset(to, 0, n); 210 - return n; 208 + res = raw_copy_from_user(to, from, n); 209 + if (unlikely(res)) 210 + memset(to + (n - res), 0, res); 211 + return res; 211 212 } 212 213 213 - #define __copy_from_user(to, from, n) __copy_user_zeroing(to, from, n) 214 + #define __copy_from_user(to, from, n) raw_copy_from_user(to, from, n) 214 215 #define __copy_from_user_inatomic __copy_from_user 215 216 216 217 extern unsigned long __must_check __copy_user(void __user *to,
+18 -39
arch/metag/lib/usercopy.c
··· 29 29 COPY \ 30 30 "1:\n" \ 31 31 " .section .fixup,\"ax\"\n" \ 32 - " MOV D1Ar1,#0\n" \ 33 32 FIXUP \ 34 33 " MOVT D1Ar1,#HI(1b)\n" \ 35 34 " JUMP D1Ar1,#LO(1b)\n" \ ··· 636 637 __asm_copy_user_cont(to, from, ret, \ 637 638 " GETB D1Ar1,[%1++]\n" \ 638 639 "2: SETB [%0++],D1Ar1\n", \ 639 - "3: ADD %2,%2,#1\n" \ 640 - " SETB [%0++],D1Ar1\n", \ 640 + "3: ADD %2,%2,#1\n", \ 641 641 " .long 2b,3b\n") 642 642 643 643 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 644 644 __asm_copy_user_cont(to, from, ret, \ 645 645 " GETW D1Ar1,[%1++]\n" \ 646 646 "2: SETW [%0++],D1Ar1\n" COPY, \ 647 - "3: ADD %2,%2,#2\n" \ 648 - " SETW [%0++],D1Ar1\n" FIXUP, \ 647 + "3: ADD %2,%2,#2\n" FIXUP, \ 649 648 " .long 2b,3b\n" TENTRY) 650 649 651 650 #define __asm_copy_from_user_2(to, from, ret) \ ··· 653 656 __asm_copy_from_user_2x_cont(to, from, ret, \ 654 657 " GETB D1Ar1,[%1++]\n" \ 655 658 "4: SETB [%0++],D1Ar1\n", \ 656 - "5: ADD %2,%2,#1\n" \ 657 - " SETB [%0++],D1Ar1\n", \ 659 + "5: ADD %2,%2,#1\n", \ 658 660 " .long 4b,5b\n") 659 661 660 662 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 661 663 __asm_copy_user_cont(to, from, ret, \ 662 664 " GETD D1Ar1,[%1++]\n" \ 663 665 "2: SETD [%0++],D1Ar1\n" COPY, \ 664 - "3: ADD %2,%2,#4\n" \ 665 - " SETD [%0++],D1Ar1\n" FIXUP, \ 666 + "3: ADD %2,%2,#4\n" FIXUP, \ 666 667 " .long 2b,3b\n" TENTRY) 667 668 668 669 #define __asm_copy_from_user_4(to, from, ret) \ 669 670 __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") 670 - 671 671 672 672 #define __asm_copy_from_user_8x64(to, from, ret) \ 673 673 asm volatile ( \ ··· 672 678 "2: SETL [%0++],D0Ar2,D1Ar1\n" \ 673 679 "1:\n" \ 674 680 " .section .fixup,\"ax\"\n" \ 675 - " MOV D1Ar1,#0\n" \ 676 - " MOV D0Ar2,#0\n" \ 677 681 "3: ADD %2,%2,#8\n" \ 678 - " SETL [%0++],D0Ar2,D1Ar1\n" \ 679 682 " MOVT D0Ar2,#HI(1b)\n" \ 680 683 " JUMP D0Ar2,#LO(1b)\n" \ 681 684 " .previous\n" \ ··· 712 721 "SUB %1, %1, #4\n") 713 722 714 723 715 - /* Copy from user to kernel, zeroing the bytes that were inaccessible in 716 - userland. The return-value is the number of bytes that were 717 - inaccessible. */ 718 - unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc, 719 - unsigned long n) 724 + /* 725 + * Copy from user to kernel. The return-value is the number of bytes that were 726 + * inaccessible. 727 + */ 728 + unsigned long raw_copy_from_user(void *pdst, const void __user *psrc, 729 + unsigned long n) 720 730 { 721 731 register char *dst asm ("A0.2") = pdst; 722 732 register const char __user *src asm ("A1.2") = psrc; ··· 730 738 __asm_copy_from_user_1(dst, src, retn); 731 739 n--; 732 740 if (retn) 733 - goto copy_exception_bytes; 741 + return retn + n; 734 742 } 735 743 if ((unsigned long) dst & 1) { 736 744 /* Worst case - byte copy */ ··· 738 746 __asm_copy_from_user_1(dst, src, retn); 739 747 n--; 740 748 if (retn) 741 - goto copy_exception_bytes; 749 + return retn + n; 742 750 } 743 751 } 744 752 if (((unsigned long) src & 2) && n >= 2) { 745 753 __asm_copy_from_user_2(dst, src, retn); 746 754 n -= 2; 747 755 if (retn) 748 - goto copy_exception_bytes; 756 + return retn + n; 749 757 } 750 758 if ((unsigned long) dst & 2) { 751 759 /* Second worst case - word copy */ ··· 753 761 __asm_copy_from_user_2(dst, src, retn); 754 762 n -= 2; 755 763 if (retn) 756 - goto copy_exception_bytes; 764 + return retn + n; 757 765 } 758 766 } 759 767 ··· 769 777 __asm_copy_from_user_8x64(dst, src, retn); 770 778 n -= 8; 771 779 if (retn) 772 - goto copy_exception_bytes; 780 + return retn + n; 773 781 } 774 782 } 775 783 ··· 785 793 __asm_copy_from_user_8x64(dst, src, retn); 786 794 n -= 8; 787 795 if (retn) 788 - goto copy_exception_bytes; 796 + return retn + n; 789 797 } 790 798 } 791 799 #endif ··· 795 803 n -= 4; 796 804 797 805 if (retn) 798 - goto copy_exception_bytes; 806 + return retn + n; 799 807 } 800 808 801 809 /* If we get here, there were no memory read faults. */ ··· 821 829 /* If we get here, retn correctly reflects the number of failing 822 830 bytes. */ 823 831 return retn; 824 - 825 - copy_exception_bytes: 826 - /* We already have "retn" bytes cleared, and need to clear the 827 - remaining "n" bytes. A non-optimized simple byte-for-byte in-line 828 - memset is preferred here, since this isn't speed-critical code and 829 - we'd rather have this a leaf-function than calling memset. */ 830 - { 831 - char *endp; 832 - for (endp = dst + n; dst < endp; dst++) 833 - *dst = 0; 834 - } 835 - 836 - return retn + n; 837 832 } 838 - EXPORT_SYMBOL(__copy_user_zeroing); 833 + EXPORT_SYMBOL(raw_copy_from_user); 839 834 840 835 #define __asm_clear_8x64(to, ret) \ 841 836 asm volatile ( \