--- linux-2.6.27.orig/arch/x86/kernel/alternative.c +++ linux-2.6.27/arch/x86/kernel/alternative.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #define MAX_PATCH_LEN (255-1) @@ -179,7 +177,7 @@ #endif /* CONFIG_X86_64 */ /* Use this to add nops to a buffer, then text_poke the whole buffer. */ -void add_nops(void *insns, unsigned int len) +static void add_nops(void *insns, unsigned int len) { const unsigned char *const *noptable = find_nop_table(); @@ -192,7 +190,6 @@ len -= noplen; } } -EXPORT_SYMBOL_GPL(add_nops); extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern u8 *__smp_locks[], *__smp_locks_end[]; @@ -226,7 +223,7 @@ memcpy(insnbuf, a->replacement, a->replacementlen); add_nops(insnbuf + a->replacementlen, a->instrlen - a->replacementlen); - text_poke_early(instr, insnbuf, a->instrlen); + text_poke(instr, insnbuf, a->instrlen); } } @@ -287,6 +284,7 @@ void *text, void *text_end) { struct smp_alt_module *smp; + unsigned long flags; if (noreplace_smp) return; @@ -411,7 +409,7 @@ /* Pad the rest with nops */ add_nops(insnbuf + used, p->len - used); - text_poke_early(p->instr, insnbuf, p->len); + text_poke(p->instr, insnbuf, p->len); } } extern struct paravirt_patch_site __start_parainstructions[], @@ -420,6 +418,8 @@ void __init alternative_instructions(void) { + unsigned long flags; + /* The patching is not fully atomic, so try to avoid local interruptions that might execute the to be patched code. Other CPUs are not running. */ @@ -428,6 +428,7 @@ stop_mce(); #endif + local_irq_save(flags); apply_alternatives(__alt_instructions, __alt_instructions_end); /* switch to patch-once-at-boottime-only mode and free the @@ -459,6 +460,7 @@ } #endif apply_paravirt(__parainstructions, __parainstructions_end); + local_irq_restore(flags); if (smp_alt_once) free_init_pages("SMP alternatives", @@ -483,58 +485,11 @@ * instructions. And on the local CPU you need to be protected again NMI or MCE * handlers seeing an inconsistent instruction while you patch. */ -void *text_poke_early(void *addr, const void *opcode, size_t len) +void __kprobes text_poke(void *addr, unsigned char *opcode, int len) { - unsigned long flags; - local_irq_save(flags); memcpy(addr, opcode, len); - local_irq_restore(flags); - sync_core(); - /* Could also do a CLFLUSH here to speed up CPU recovery; but - that causes hangs on some VIA CPUs. */ - return addr; -} - -/** - * text_poke - Update instructions on a live kernel - * @addr: address to modify - * @opcode: source of the copy - * @len: length to copy - * - * Only atomic text poke/set should be allowed when not doing early patching. - * It means the size must be writable atomically and the address must be aligned - * in a way that permits an atomic write. It also makes sure we fit on a single - * page. - */ -void *__kprobes text_poke(void *addr, const void *opcode, size_t len) -{ - unsigned long flags; - char *vaddr; - int nr_pages = 2; - struct page *pages[2]; - int i; - if (!core_kernel_text((unsigned long)addr)) { - pages[0] = vmalloc_to_page(addr); - pages[1] = vmalloc_to_page(addr + PAGE_SIZE); - } else { - pages[0] = virt_to_page(addr); - WARN_ON(!PageReserved(pages[0])); - pages[1] = virt_to_page(addr + PAGE_SIZE); - } - BUG_ON(!pages[0]); - if (!pages[1]) - nr_pages = 1; - vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); - BUG_ON(!vaddr); - local_irq_save(flags); - memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); - local_irq_restore(flags); - vunmap(vaddr); sync_core(); /* Could also do a CLFLUSH here to speed up CPU recovery; but that causes hangs on some VIA CPUs. */ - for (i = 0; i < len; i++) - BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]); - return addr; } --- linux-2.6.27.orig/debian/changelog +++ linux-2.6.27/debian/changelog @@ -1,5 +1,12 @@ linux (2.6.27-1.2) intrepid; urgency=low + * Revert e587cadd8f47e202a30712e2906a65a0606d5865 + https://bugs.launchpad.net/ubuntu/+source/linux/+bug/246067 + + -- Christoph Korn Thu, 28 Aug 2008 21:25:21 +0200 + +linux (2.6.27-1.2) intrepid; urgency=low + [ Amit Kucheria ] * SAUCE: make fc transport removal of target configurable --- linux-2.6.27.orig/include/asm-x86/alternative.h +++ linux-2.6.27/include/asm-x86/alternative.h @@ -157,27 +157,6 @@ #define __parainstructions_end NULL #endif -extern void add_nops(void *insns, unsigned int len); - -/* - * Clear and restore the kernel write-protection flag on the local CPU. - * Allows the kernel to edit read-only pages. - * Side-effect: any interrupt handler running between save and restore will have - * the ability to write to read-only pages. - * - * Warning: - * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and - * no thread can be preempted in the instructions being modified (no iret to an - * invalid instruction possible) or if the instructions are changed from a - * consistent state to another consistent state atomically. - * More care must be taken when modifying code in the SMP case because of - * Intel's errata. - * On the local CPU you need to be protected again NMI or MCE handlers seeing an - * inconsistent instruction while you patch. - * The _early version expects the memory to already be RW. - */ - -extern void *text_poke(void *addr, const void *opcode, size_t len); -extern void *text_poke_early(void *addr, const void *opcode, size_t len); +extern void text_poke(void *addr, unsigned char *opcode, int len); #endif /* _ASM_X86_ALTERNATIVE_H */