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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'x86_alternatives_for_v7.0_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 alternatives update from Borislav Petkov:

- Reorganize the alternatives patching mechanism to patch a single
location only once instead of multiple times as it was the case with
the two or three alternative options macros

* tag 'x86_alternatives_for_v7.0_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/alternative: Patch a single alternative location only once
x86/alternative: Use helper functions for patching alternatives

+91 -56
+91 -56
arch/x86/kernel/alternative.c
··· 586 586 return (u8 *)&i->instr_offset + i->instr_offset; 587 587 } 588 588 589 + struct patch_site { 590 + u8 *instr; 591 + struct alt_instr *alt; 592 + u8 buff[MAX_PATCH_LEN]; 593 + u8 len; 594 + }; 595 + 596 + static struct alt_instr * __init_or_module analyze_patch_site(struct patch_site *ps, 597 + struct alt_instr *start, 598 + struct alt_instr *end) 599 + { 600 + struct alt_instr *alt = start; 601 + 602 + ps->instr = instr_va(start); 603 + 604 + /* 605 + * In case of nested ALTERNATIVE()s the outer alternative might add 606 + * more padding. To ensure consistent patching find the max padding for 607 + * all alt_instr entries for this site (nested alternatives result in 608 + * consecutive entries). 609 + * Find the last alt_instr eligible for patching at the site. 610 + */ 611 + for (; alt < end && instr_va(alt) == ps->instr; alt++) { 612 + ps->len = max(ps->len, alt->instrlen); 613 + 614 + BUG_ON(alt->cpuid >= (NCAPINTS + NBUGINTS) * 32); 615 + /* 616 + * Patch if either: 617 + * - feature is present 618 + * - feature not present but ALT_FLAG_NOT is set to mean, 619 + * patch if feature is *NOT* present. 620 + */ 621 + if (!boot_cpu_has(alt->cpuid) != !(alt->flags & ALT_FLAG_NOT)) 622 + ps->alt = alt; 623 + } 624 + 625 + BUG_ON(ps->len > sizeof(ps->buff)); 626 + 627 + return alt; 628 + } 629 + 630 + static void __init_or_module prep_patch_site(struct patch_site *ps) 631 + { 632 + struct alt_instr *alt = ps->alt; 633 + u8 buff_sz; 634 + u8 *repl; 635 + 636 + if (!alt) { 637 + /* Nothing to patch, use original instruction. */ 638 + memcpy(ps->buff, ps->instr, ps->len); 639 + return; 640 + } 641 + 642 + repl = (u8 *)&alt->repl_offset + alt->repl_offset; 643 + DPRINTK(ALT, "feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d) flags: 0x%x", 644 + alt->cpuid >> 5, alt->cpuid & 0x1f, 645 + ps->instr, ps->instr, ps->len, 646 + repl, alt->replacementlen, alt->flags); 647 + 648 + memcpy(ps->buff, repl, alt->replacementlen); 649 + buff_sz = alt->replacementlen; 650 + 651 + if (alt->flags & ALT_FLAG_DIRECT_CALL) 652 + buff_sz = alt_replace_call(ps->instr, ps->buff, alt); 653 + 654 + for (; buff_sz < ps->len; buff_sz++) 655 + ps->buff[buff_sz] = 0x90; 656 + 657 + __apply_relocation(ps->buff, ps->instr, ps->len, repl, alt->replacementlen); 658 + 659 + DUMP_BYTES(ALT, ps->instr, ps->len, "%px: old_insn: ", ps->instr); 660 + DUMP_BYTES(ALT, repl, alt->replacementlen, "%px: rpl_insn: ", repl); 661 + DUMP_BYTES(ALT, ps->buff, ps->len, "%px: final_insn: ", ps->instr); 662 + } 663 + 664 + static void __init_or_module patch_site(struct patch_site *ps) 665 + { 666 + optimize_nops(ps->instr, ps->buff, ps->len); 667 + text_poke_early(ps->instr, ps->buff, ps->len); 668 + } 669 + 589 670 /* 590 671 * Replace instructions with better alternatives for this CPU type. This runs 591 672 * before SMP is initialized to avoid SMP problems with self modifying code. ··· 680 599 void __init_or_module noinline apply_alternatives(struct alt_instr *start, 681 600 struct alt_instr *end) 682 601 { 683 - u8 insn_buff[MAX_PATCH_LEN]; 684 - u8 *instr, *replacement; 685 - struct alt_instr *a, *b; 602 + struct alt_instr *a; 686 603 687 604 DPRINTK(ALT, "alt table %px, -> %px", start, end); 688 605 ··· 703 624 * So be careful if you want to change the scan order to any other 704 625 * order. 705 626 */ 706 - for (a = start; a < end; a++) { 707 - unsigned int insn_buff_sz = 0; 627 + a = start; 628 + while (a < end) { 629 + struct patch_site ps = { 630 + .alt = NULL, 631 + .len = 0 632 + }; 708 633 709 - /* 710 - * In case of nested ALTERNATIVE()s the outer alternative might 711 - * add more padding. To ensure consistent patching find the max 712 - * padding for all alt_instr entries for this site (nested 713 - * alternatives result in consecutive entries). 714 - */ 715 - for (b = a+1; b < end && instr_va(b) == instr_va(a); b++) { 716 - u8 len = max(a->instrlen, b->instrlen); 717 - a->instrlen = b->instrlen = len; 718 - } 719 - 720 - instr = instr_va(a); 721 - replacement = (u8 *)&a->repl_offset + a->repl_offset; 722 - BUG_ON(a->instrlen > sizeof(insn_buff)); 723 - BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32); 724 - 725 - /* 726 - * Patch if either: 727 - * - feature is present 728 - * - feature not present but ALT_FLAG_NOT is set to mean, 729 - * patch if feature is *NOT* present. 730 - */ 731 - if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) { 732 - memcpy(insn_buff, instr, a->instrlen); 733 - optimize_nops(instr, insn_buff, a->instrlen); 734 - text_poke_early(instr, insn_buff, a->instrlen); 735 - continue; 736 - } 737 - 738 - DPRINTK(ALT, "feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d) flags: 0x%x", 739 - a->cpuid >> 5, 740 - a->cpuid & 0x1f, 741 - instr, instr, a->instrlen, 742 - replacement, a->replacementlen, a->flags); 743 - 744 - memcpy(insn_buff, replacement, a->replacementlen); 745 - insn_buff_sz = a->replacementlen; 746 - 747 - if (a->flags & ALT_FLAG_DIRECT_CALL) 748 - insn_buff_sz = alt_replace_call(instr, insn_buff, a); 749 - 750 - for (; insn_buff_sz < a->instrlen; insn_buff_sz++) 751 - insn_buff[insn_buff_sz] = 0x90; 752 - 753 - text_poke_apply_relocation(insn_buff, instr, a->instrlen, replacement, a->replacementlen); 754 - 755 - DUMP_BYTES(ALT, instr, a->instrlen, "%px: old_insn: ", instr); 756 - DUMP_BYTES(ALT, replacement, a->replacementlen, "%px: rpl_insn: ", replacement); 757 - DUMP_BYTES(ALT, insn_buff, insn_buff_sz, "%px: final_insn: ", instr); 758 - 759 - text_poke_early(instr, insn_buff, insn_buff_sz); 634 + a = analyze_patch_site(&ps, a, end); 635 + prep_patch_site(&ps); 636 + patch_site(&ps); 760 637 } 761 638 762 639 kasan_enable_current();