Revert most of x86: Fix alternatives and kprobes to remap write-protected kernel text

2007-07-26 Thread Linux Kernel Mailing List
Gitweb: 
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=602033ed5907a59ce86f709082a35be047743a86
Commit: 602033ed5907a59ce86f709082a35be047743a86
Parent: 07d4e9af109221ab731c5aaf832e89776c64b013
Author: Linus Torvalds [EMAIL PROTECTED]
AuthorDate: Thu Jul 26 12:07:21 2007 -0700
Committer:  Linus Torvalds [EMAIL PROTECTED]
CommitDate: Thu Jul 26 12:07:21 2007 -0700

Revert most of x86: Fix alternatives and kprobes to remap write-protected 
kernel text

This reverts most of commit 19d36ccdc34f5ed444f8a6af0cbfdb6790eb1177.

The way to DEBUG_RODATA interactions with KPROBES and CPU hotplug is to
just not mark the text as being write-protected in the first place.
Both of those facilities depend on rewriting instructions.

Having helpful debug facilities that just cause more problem is not
being helpful.  It just adds complexity and bugs. Not worth it.

Reported-by: Rafael J. Wysocki [EMAIL PROTECTED]
Cc: Andi Kleen [EMAIL PROTECTED]
Cc: Andrew Morton [EMAIL PROTECTED]
Signed-off-by: Linus Torvalds [EMAIL PROTECTED]
---
 arch/i386/kernel/alternative.c |   14 ++
 arch/i386/mm/init.c|   14 +++---
 arch/x86_64/mm/init.c  |   10 ++
 3 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index c3750c2..c85598a 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -430,22 +430,12 @@ void __init alternative_instructions(void)
  * And on the local CPU you need to be protected again NMI or MCE handlers
  * seeing an inconsistent instruction while you patch.
  */
-void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+void __kprobes text_poke(void *addr, unsigned char *opcode, int len)
 {
-u8 *addr = oaddr;
-   if (!pte_write(*lookup_address((unsigned long)addr))) {
-   struct page *p[2] = { virt_to_page(addr), 
virt_to_page(addr+PAGE_SIZE) };
-   addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
-   if (!addr)
-   return;
-   addr += ((unsigned long)oaddr) % PAGE_SIZE;
-   }
memcpy(addr, opcode, len);
sync_core();
/* Not strictly needed, but can speed CPU recovery up. Ignore cross 
cacheline
   case. */
if (cpu_has_clflush)
-   asm(clflush (%0)  :: r (oaddr) : memory);
-   if (addr != oaddr)
-   vunmap(addr);
+   asm(clflush (%0)  :: r (addr) : memory);
 }
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 1b1a1e6..4c4809f 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -800,9 +800,17 @@ void mark_rodata_ro(void)
unsigned long start = PFN_ALIGN(_text);
unsigned long size = PFN_ALIGN(_etext) - start;
 
-   change_page_attr(virt_to_page(start),
-size  PAGE_SHIFT, PAGE_KERNEL_RX);
-   printk(Write protecting the kernel text: %luk\n, size  10);
+#ifndef CONFIG_KPROBES
+#ifdef CONFIG_HOTPLUG_CPU
+   /* It must still be possible to apply SMP alternatives. */
+   if (num_possible_cpus() = 1)
+#endif
+   {
+   change_page_attr(virt_to_page(start),
+size  PAGE_SHIFT, PAGE_KERNEL_RX);
+   printk(Write protecting the kernel text: %luk\n, size  10);
+   }
+#endif
start += size;
size = (unsigned long)__end_rodata - start;
change_page_attr(virt_to_page(start),
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 38f5d63..458893b 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -600,6 +600,16 @@ void mark_rodata_ro(void)
 {
unsigned long start = (unsigned long)_stext, end;
 
+#ifdef CONFIG_HOTPLUG_CPU
+   /* It must still be possible to apply SMP alternatives. */
+   if (num_possible_cpus()  1)
+   start = (unsigned long)_etext;
+#endif
+
+#ifdef CONFIG_KPROBES
+   start = (unsigned long)__start_rodata;
+#endif
+   
end = (unsigned long)__end_rodata;
start = (start + PAGE_SIZE - 1)  PAGE_MASK;
end = PAGE_MASK;
-
To unsubscribe from this list: send the line unsubscribe git-commits-head in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


x86: Fix alternatives and kprobes to remap write-protected kernel text

2007-07-22 Thread Linux Kernel Mailing List
Gitweb: 
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=19d36ccdc34f5ed444f8a6af0cbfdb6790eb1177
Commit: 19d36ccdc34f5ed444f8a6af0cbfdb6790eb1177
Parent: f51c94528a9bc73504928926ca4d791a2b7ddd7c
Author: Andi Kleen [EMAIL PROTECTED]
AuthorDate: Sun Jul 22 11:12:31 2007 +0200
Committer:  Linus Torvalds [EMAIL PROTECTED]
CommitDate: Sun Jul 22 11:03:37 2007 -0700

x86: Fix alternatives and kprobes to remap write-protected kernel text

Reenable kprobes and alternative patching when the kernel text is write
protected by DEBUG_RODATA

Add a general utility function to change write protected text.  The new
function remaps the code using vmap to write it and takes care of CPU
synchronization.  It also does CLFLUSH to make icache recovery faster.

There are some limitations on when the function can be used, see the
comment.

This is a newer version that also changes the paravirt_ops code.
text_poke also supports multi byte patching now.

Contains bug fixes from Zach Amsden and suggestions from Mathieu
Desnoyers.

Cc: Jan Beulich [EMAIL PROTECTED]
Cc: Jeremy Fitzhardinge [EMAIL PROTECTED]
Cc: Mathieu Desnoyers [EMAIL PROTECTED]
Cc: Zach Amsden [EMAIL PROTECTED]
Signed-off-by: Andi Kleen [EMAIL PROTECTED]
Signed-off-by: Linus Torvalds [EMAIL PROTECTED]
---
 arch/i386/kernel/alternative.c   |   40 -
 arch/i386/kernel/kprobes.c   |9 ++-
 arch/i386/kernel/paravirt.c  |   17 ---
 arch/i386/mm/init.c  |   14 ++--
 arch/x86_64/kernel/kprobes.c |   10 ++--
 arch/x86_64/mm/init.c|   10 -
 arch/x86_64/mm/pageattr.c|2 +-
 include/asm-i386/alternative.h   |2 +
 include/asm-x86_64/alternative.h |2 +
 include/asm-x86_64/pgtable.h |2 +
 10 files changed, 63 insertions(+), 45 deletions(-)

diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index 0695be5..206ea2c 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -2,8 +2,12 @@
 #include linux/sched.h
 #include linux/spinlock.h
 #include linux/list.h
+#include linux/kprobes.h
+#include linux/mm.h
+#include linux/vmalloc.h
 #include asm/alternative.h
 #include asm/sections.h
+#include asm/pgtable.h
 
 #ifdef CONFIG_HOTPLUG_CPU
 static int smp_alt_once;
@@ -150,7 +154,7 @@ static void nop_out(void *insns, unsigned int len)
unsigned int noplen = len;
if (noplen  ASM_NOP_MAX)
noplen = ASM_NOP_MAX;
-   memcpy(insns, noptable[noplen], noplen);
+   text_poke(insns, noptable[noplen], noplen);
insns += noplen;
len -= noplen;
}
@@ -202,7 +206,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 
*text, u8 *text_end)
continue;
if (*ptr  text_end)
continue;
-   **ptr = 0xf0; /* lock prefix */
+   text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock 
prefix */
};
 }
 
@@ -360,10 +364,6 @@ void apply_paravirt(struct paravirt_patch_site *start,
/* Pad the rest with nops */
nop_out(p-instr + used, p-len - used);
}
-
-   /* Sync to be conservative, in case we patched following
-* instructions */
-   sync_core();
 }
 extern struct paravirt_patch_site __start_parainstructions[],
__stop_parainstructions[];
@@ -406,3 +406,31 @@ void __init alternative_instructions(void)
apply_paravirt(__parainstructions, __parainstructions_end);
local_irq_restore(flags);
 }
+
+/*
+ * Warning:
+ * When you use this code to patch more than one byte of an instruction
+ * you need to make sure that other CPUs cannot execute this code in parallel.
+ * Also no thread must be currently preempted in the middle of these 
instructions.
+ * And on the local CPU you need to be protected again NMI or MCE handlers
+ * seeing an inconsistent instruction while you patch.
+ */
+void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+{
+u8 *addr = oaddr;
+   if (!pte_write(*lookup_address((unsigned long)addr))) {
+   struct page *p[2] = { virt_to_page(addr), 
virt_to_page(addr+PAGE_SIZE) };
+   addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
+   if (!addr)
+   return;
+   addr += ((unsigned long)oaddr) % PAGE_SIZE;
+   }
+   memcpy(addr, opcode, len);
+   sync_core();
+   /* Not strictly needed, but can speed CPU recovery up. Ignore cross 
cacheline
+  case. */
+   if (cpu_has_clflush)
+   asm(clflush (%0)  :: r (oaddr) : memory);
+   if (addr != oaddr)
+   vunmap(addr);
+}
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index