aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2017-03-31 08:35:01 -0400
committerJames Hogan <james.hogan@imgtec.com>2017-04-05 09:49:42 -0400
commitfb8ea062a8f2e85256e13f55696c5c5f0dfdcc8b (patch)
tree263488d227fe8bb0dea7749a07d45de104c62bd9
parent2257211942bbbf6c798ab70b487d7e62f7835a1a (diff)
metag/usercopy: Add early abort to copy_to_user
When copying to userland on Meta, if any faults are encountered immediately abort the copy instead of continuing on and repeatedly faulting, and worse potentially copying further bytes successfully to subsequent valid pages. 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
-rw-r--r--arch/metag/lib/usercopy.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/metag/lib/usercopy.c b/arch/metag/lib/usercopy.c
index a6ced9691ddb..714d8562aa20 100644
--- a/arch/metag/lib/usercopy.c
+++ b/arch/metag/lib/usercopy.c
@@ -538,23 +538,31 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
538 if ((unsigned long) src & 1) { 538 if ((unsigned long) src & 1) {
539 __asm_copy_to_user_1(dst, src, retn); 539 __asm_copy_to_user_1(dst, src, retn);
540 n--; 540 n--;
541 if (retn)
542 return retn + n;
541 } 543 }
542 if ((unsigned long) dst & 1) { 544 if ((unsigned long) dst & 1) {
543 /* Worst case - byte copy */ 545 /* Worst case - byte copy */
544 while (n > 0) { 546 while (n > 0) {
545 __asm_copy_to_user_1(dst, src, retn); 547 __asm_copy_to_user_1(dst, src, retn);
546 n--; 548 n--;
549 if (retn)
550 return retn + n;
547 } 551 }
548 } 552 }
549 if (((unsigned long) src & 2) && n >= 2) { 553 if (((unsigned long) src & 2) && n >= 2) {
550 __asm_copy_to_user_2(dst, src, retn); 554 __asm_copy_to_user_2(dst, src, retn);
551 n -= 2; 555 n -= 2;
556 if (retn)
557 return retn + n;
552 } 558 }
553 if ((unsigned long) dst & 2) { 559 if ((unsigned long) dst & 2) {
554 /* Second worst case - word copy */ 560 /* Second worst case - word copy */
555 while (n >= 2) { 561 while (n >= 2) {
556 __asm_copy_to_user_2(dst, src, retn); 562 __asm_copy_to_user_2(dst, src, retn);
557 n -= 2; 563 n -= 2;
564 if (retn)
565 return retn + n;
558 } 566 }
559 } 567 }
560 568
@@ -569,6 +577,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
569 while (n >= 8) { 577 while (n >= 8) {
570 __asm_copy_to_user_8x64(dst, src, retn); 578 __asm_copy_to_user_8x64(dst, src, retn);
571 n -= 8; 579 n -= 8;
580 if (retn)
581 return retn + n;
572 } 582 }
573 } 583 }
574 if (n >= RAPF_MIN_BUF_SIZE) { 584 if (n >= RAPF_MIN_BUF_SIZE) {
@@ -581,6 +591,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
581 while (n >= 8) { 591 while (n >= 8) {
582 __asm_copy_to_user_8x64(dst, src, retn); 592 __asm_copy_to_user_8x64(dst, src, retn);
583 n -= 8; 593 n -= 8;
594 if (retn)
595 return retn + n;
584 } 596 }
585 } 597 }
586#endif 598#endif
@@ -588,11 +600,15 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
588 while (n >= 16) { 600 while (n >= 16) {
589 __asm_copy_to_user_16(dst, src, retn); 601 __asm_copy_to_user_16(dst, src, retn);
590 n -= 16; 602 n -= 16;
603 if (retn)
604 return retn + n;
591 } 605 }
592 606
593 while (n >= 4) { 607 while (n >= 4) {
594 __asm_copy_to_user_4(dst, src, retn); 608 __asm_copy_to_user_4(dst, src, retn);
595 n -= 4; 609 n -= 4;
610 if (retn)
611 return retn + n;
596 } 612 }
597 613
598 switch (n) { 614 switch (n) {
@@ -609,6 +625,10 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
609 break; 625 break;
610 } 626 }
611 627
628 /*
629 * If we get here, retn correctly reflects the number of failing
630 * bytes.
631 */
612 return retn; 632 return retn;
613} 633}
614EXPORT_SYMBOL(__copy_user); 634EXPORT_SYMBOL(__copy_user);