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

[PATCH] Make copy_from_user_inatomic NOT zero the tail on i386

As described in a previous patch and documented in mm/filemap.h,
copy_from_user_inatomic* shouldn't zero out the tail of the buffer after an
incomplete copy.

This patch implements that change for i386.

For the _nocache version, a new __copy_user_intel_nocache is defined similar
to copy_user_zeroio_intel_nocache, and this is ultimately used for the copy.

For the regular version, __copy_from_user_ll_nozero is defined which uses
__copy_user and __copy_user_intel - the later needs casts to reposition the
__user annotations.

If copy_from_user_atomic is given a constant length of 1, 2, or 4, then we do
still zero the destintion on failure. This didn't seem worth the effort of
fixing as the places where it is used really don't care.

Signed-off-by: Neil Brown <neilb@suse.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: William Lee Irwin III <wli@holomorphy.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

NeilBrown and committed by
Linus Torvalds
7c12d811 01408c49

+153 -12
+119
arch/i386/lib/usercopy.c
··· 528 528 return size; 529 529 } 530 530 531 + static unsigned long __copy_user_intel_nocache(void *to, 532 + const void __user *from, unsigned long size) 533 + { 534 + int d0, d1; 535 + 536 + __asm__ __volatile__( 537 + " .align 2,0x90\n" 538 + "0: movl 32(%4), %%eax\n" 539 + " cmpl $67, %0\n" 540 + " jbe 2f\n" 541 + "1: movl 64(%4), %%eax\n" 542 + " .align 2,0x90\n" 543 + "2: movl 0(%4), %%eax\n" 544 + "21: movl 4(%4), %%edx\n" 545 + " movnti %%eax, 0(%3)\n" 546 + " movnti %%edx, 4(%3)\n" 547 + "3: movl 8(%4), %%eax\n" 548 + "31: movl 12(%4),%%edx\n" 549 + " movnti %%eax, 8(%3)\n" 550 + " movnti %%edx, 12(%3)\n" 551 + "4: movl 16(%4), %%eax\n" 552 + "41: movl 20(%4), %%edx\n" 553 + " movnti %%eax, 16(%3)\n" 554 + " movnti %%edx, 20(%3)\n" 555 + "10: movl 24(%4), %%eax\n" 556 + "51: movl 28(%4), %%edx\n" 557 + " movnti %%eax, 24(%3)\n" 558 + " movnti %%edx, 28(%3)\n" 559 + "11: movl 32(%4), %%eax\n" 560 + "61: movl 36(%4), %%edx\n" 561 + " movnti %%eax, 32(%3)\n" 562 + " movnti %%edx, 36(%3)\n" 563 + "12: movl 40(%4), %%eax\n" 564 + "71: movl 44(%4), %%edx\n" 565 + " movnti %%eax, 40(%3)\n" 566 + " movnti %%edx, 44(%3)\n" 567 + "13: movl 48(%4), %%eax\n" 568 + "81: movl 52(%4), %%edx\n" 569 + " movnti %%eax, 48(%3)\n" 570 + " movnti %%edx, 52(%3)\n" 571 + "14: movl 56(%4), %%eax\n" 572 + "91: movl 60(%4), %%edx\n" 573 + " movnti %%eax, 56(%3)\n" 574 + " movnti %%edx, 60(%3)\n" 575 + " addl $-64, %0\n" 576 + " addl $64, %4\n" 577 + " addl $64, %3\n" 578 + " cmpl $63, %0\n" 579 + " ja 0b\n" 580 + " sfence \n" 581 + "5: movl %0, %%eax\n" 582 + " shrl $2, %0\n" 583 + " andl $3, %%eax\n" 584 + " cld\n" 585 + "6: rep; movsl\n" 586 + " movl %%eax,%0\n" 587 + "7: rep; movsb\n" 588 + "8:\n" 589 + ".section .fixup,\"ax\"\n" 590 + "9: lea 0(%%eax,%0,4),%0\n" 591 + "16: jmp 8b\n" 592 + ".previous\n" 593 + ".section __ex_table,\"a\"\n" 594 + " .align 4\n" 595 + " .long 0b,16b\n" 596 + " .long 1b,16b\n" 597 + " .long 2b,16b\n" 598 + " .long 21b,16b\n" 599 + " .long 3b,16b\n" 600 + " .long 31b,16b\n" 601 + " .long 4b,16b\n" 602 + " .long 41b,16b\n" 603 + " .long 10b,16b\n" 604 + " .long 51b,16b\n" 605 + " .long 11b,16b\n" 606 + " .long 61b,16b\n" 607 + " .long 12b,16b\n" 608 + " .long 71b,16b\n" 609 + " .long 13b,16b\n" 610 + " .long 81b,16b\n" 611 + " .long 14b,16b\n" 612 + " .long 91b,16b\n" 613 + " .long 6b,9b\n" 614 + " .long 7b,16b\n" 615 + ".previous" 616 + : "=&c"(size), "=&D" (d0), "=&S" (d1) 617 + : "1"(to), "2"(from), "0"(size) 618 + : "eax", "edx", "memory"); 619 + return size; 620 + } 621 + 531 622 #else 532 623 533 624 /* ··· 785 694 } 786 695 EXPORT_SYMBOL(__copy_from_user_ll); 787 696 697 + unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from, 698 + unsigned long n) 699 + { 700 + BUG_ON((long)n < 0); 701 + if (movsl_is_ok(to, from, n)) 702 + __copy_user(to, from, n); 703 + else 704 + n = __copy_user_intel((void __user *)to, 705 + (const void *)from, n); 706 + return n; 707 + } 708 + EXPORT_SYMBOL(__copy_from_user_ll_nozero); 709 + 788 710 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from, 789 711 unsigned long n) 790 712 { ··· 809 705 __copy_user_zeroing(to, from, n); 810 706 #else 811 707 __copy_user_zeroing(to, from, n); 708 + #endif 709 + return n; 710 + } 711 + 712 + unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, 713 + unsigned long n) 714 + { 715 + BUG_ON((long)n < 0); 716 + #ifdef CONFIG_X86_INTEL_USERCOPY 717 + if ( n > 64 && cpu_has_xmm2) 718 + n = __copy_user_intel_nocache(to, from, n); 719 + else 720 + __copy_user(to, from, n); 721 + #else 722 + __copy_user(to, from, n); 812 723 #endif 813 724 return n; 814 725 }
+34 -12
include/asm-i386/uaccess.h
··· 390 390 const void *from, unsigned long n); 391 391 unsigned long __must_check __copy_from_user_ll(void *to, 392 392 const void __user *from, unsigned long n); 393 + unsigned long __must_check __copy_from_user_ll_nozero(void *to, 394 + const void __user *from, unsigned long n); 393 395 unsigned long __must_check __copy_from_user_ll_nocache(void *to, 396 + const void __user *from, unsigned long n); 397 + unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to, 394 398 const void __user *from, unsigned long n); 395 399 396 400 /* ··· 467 463 * atomic context and will fail rather than sleep. In this case the 468 464 * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h 469 465 * for explanation of why this is needed. 470 - * FIXME this isn't implimented yet EMXIF 471 466 */ 472 467 static __always_inline unsigned long 473 468 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) 474 469 { 470 + /* Avoid zeroing the tail if the copy fails.. 471 + * If 'n' is constant and 1, 2, or 4, we do still zero on a failure, 472 + * but as the zeroing behaviour is only significant when n is not 473 + * constant, that shouldn't be a problem. 474 + */ 475 + if (__builtin_constant_p(n)) { 476 + unsigned long ret; 477 + 478 + switch (n) { 479 + case 1: 480 + __get_user_size(*(u8 *)to, from, 1, ret, 1); 481 + return ret; 482 + case 2: 483 + __get_user_size(*(u16 *)to, from, 2, ret, 2); 484 + return ret; 485 + case 4: 486 + __get_user_size(*(u32 *)to, from, 4, ret, 4); 487 + return ret; 488 + } 489 + } 490 + return __copy_from_user_ll_nozero(to, from, n); 491 + } 492 + static __always_inline unsigned long 493 + __copy_from_user(void *to, const void __user *from, unsigned long n) 494 + { 495 + might_sleep(); 475 496 if (__builtin_constant_p(n)) { 476 497 unsigned long ret; 477 498 ··· 517 488 518 489 #define ARCH_HAS_NOCACHE_UACCESS 519 490 520 - static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to, 491 + static __always_inline unsigned long __copy_from_user_nocache(void *to, 521 492 const void __user *from, unsigned long n) 522 493 { 494 + might_sleep(); 523 495 if (__builtin_constant_p(n)) { 524 496 unsigned long ret; 525 497 ··· 540 510 } 541 511 542 512 static __always_inline unsigned long 543 - __copy_from_user(void *to, const void __user *from, unsigned long n) 513 + __copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n) 544 514 { 545 - might_sleep(); 546 - return __copy_from_user_inatomic(to, from, n); 547 - } 548 - 549 - static __always_inline unsigned long 550 - __copy_from_user_nocache(void *to, const void __user *from, unsigned long n) 551 - { 552 - might_sleep(); 553 - return __copy_from_user_inatomic_nocache(to, from, n); 515 + return __copy_from_user_ll_nocache_nozero(to, from, n); 554 516 } 555 517 556 518 unsigned long __must_check copy_to_user(void __user *to,