diff options
author | Andi Kleen <ak@suse.de> | 2007-07-22 05:12:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-22 14:03:37 -0400 |
commit | 19d36ccdc34f5ed444f8a6af0cbfdb6790eb1177 (patch) | |
tree | 39942efb826f2793692da60b04fc0e7b015fa23d /arch/x86_64 | |
parent | f51c94528a9bc73504928926ca4d791a2b7ddd7c (diff) |
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 <jbeulich@novell.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Mathieu Desnoyers <compudj@krystal.dyndns.org>
Cc: Zach Amsden <zach@vmware.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/kprobes.c | 10 | ||||
-rw-r--r-- | arch/x86_64/mm/init.c | 10 | ||||
-rw-r--r-- | arch/x86_64/mm/pageattr.c | 2 |
3 files changed, 4 insertions, 18 deletions
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index d4a0d0ac9935..a30e004682e2 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c | |||
@@ -39,9 +39,9 @@ | |||
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/kdebug.h> | 40 | #include <linux/kdebug.h> |
41 | 41 | ||
42 | #include <asm/cacheflush.h> | ||
43 | #include <asm/pgtable.h> | 42 | #include <asm/pgtable.h> |
44 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/alternative.h> | ||
45 | 45 | ||
46 | void jprobe_return_end(void); | 46 | void jprobe_return_end(void); |
47 | static void __kprobes arch_copy_kprobe(struct kprobe *p); | 47 | static void __kprobes arch_copy_kprobe(struct kprobe *p); |
@@ -209,16 +209,12 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p) | |||
209 | 209 | ||
210 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 210 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
211 | { | 211 | { |
212 | *p->addr = BREAKPOINT_INSTRUCTION; | 212 | text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1); |
213 | flush_icache_range((unsigned long) p->addr, | ||
214 | (unsigned long) p->addr + sizeof(kprobe_opcode_t)); | ||
215 | } | 213 | } |
216 | 214 | ||
217 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 215 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
218 | { | 216 | { |
219 | *p->addr = p->opcode; | 217 | text_poke(p->addr, &p->opcode, 1); |
220 | flush_icache_range((unsigned long) p->addr, | ||
221 | (unsigned long) p->addr + sizeof(kprobe_opcode_t)); | ||
222 | } | 218 | } |
223 | 219 | ||
224 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 220 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 2044fa961c07..314e12b2209f 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c | |||
@@ -600,16 +600,6 @@ void mark_rodata_ro(void) | |||
600 | { | 600 | { |
601 | unsigned long start = (unsigned long)_stext, end; | 601 | unsigned long start = (unsigned long)_stext, end; |
602 | 602 | ||
603 | #ifdef CONFIG_HOTPLUG_CPU | ||
604 | /* It must still be possible to apply SMP alternatives. */ | ||
605 | if (num_possible_cpus() > 1) | ||
606 | start = (unsigned long)_etext; | ||
607 | #endif | ||
608 | |||
609 | #ifdef CONFIG_KPROBES | ||
610 | start = (unsigned long)__start_rodata; | ||
611 | #endif | ||
612 | |||
613 | end = (unsigned long)__end_rodata; | 603 | end = (unsigned long)__end_rodata; |
614 | start = (start + PAGE_SIZE - 1) & PAGE_MASK; | 604 | start = (start + PAGE_SIZE - 1) & PAGE_MASK; |
615 | end &= PAGE_MASK; | 605 | end &= PAGE_MASK; |
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c index 36377b6b8efe..7e161c698af4 100644 --- a/arch/x86_64/mm/pageattr.c +++ b/arch/x86_64/mm/pageattr.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <asm/tlbflush.h> | 13 | #include <asm/tlbflush.h> |
14 | #include <asm/io.h> | 14 | #include <asm/io.h> |
15 | 15 | ||
16 | static inline pte_t *lookup_address(unsigned long address) | 16 | pte_t *lookup_address(unsigned long address) |
17 | { | 17 | { |
18 | pgd_t *pgd = pgd_offset_k(address); | 18 | pgd_t *pgd = pgd_offset_k(address); |
19 | pud_t *pud; | 19 | pud_t *pud; |