* [patch 1/9] Kprobes - use a mutex to protect the instruction pages list.
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 2/9] Kprobes - do not use kprobes mutex in arch code Mathieu Desnoyers
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, hch, prasanna, ananth, anil.s.keshavamurthy,
davem
[-- Attachment #1: kprobes-use-mutex-for-insn-pages.patch --]
[-- Type: text/plain, Size: 3592 bytes --]
Protect the instruction pages list by a specific insn pages mutex, called in
get_insn_slot() and free_insn_slot(). It makes sure that architectures that does
not need to call arch_remove_kprobe() does not take an unneeded kprobes mutex.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: hch@infradead.org
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
kernel/kprobes.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
Index: linux-2.6-lttng/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/kernel/kprobes.c 2007-07-14 15:47:19.000000000 -0400
+++ linux-2.6-lttng/kernel/kprobes.c 2007-07-14 15:48:51.000000000 -0400
@@ -101,6 +101,10 @@ enum kprobe_slot_state {
SLOT_USED = 2,
};
+/*
+ * Protects the kprobe_insn_pages list. Can nest into kprobe_mutex.
+ */
+static DEFINE_MUTEX(kprobe_insn_mutex);
static struct hlist_head kprobe_insn_pages;
static int kprobe_garbage_slots;
static int collect_garbage_slots(void);
@@ -137,7 +141,9 @@ kprobe_opcode_t __kprobes *get_insn_slot
{
struct kprobe_insn_page *kip;
struct hlist_node *pos;
+ kprobe_opcode_t *ret;
+ mutex_lock(&kprobe_insn_mutex);
retry:
hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
if (kip->nused < INSNS_PER_PAGE) {
@@ -146,7 +152,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
if (kip->slot_used[i] == SLOT_CLEAN) {
kip->slot_used[i] = SLOT_USED;
kip->nused++;
- return kip->insns + (i * MAX_INSN_SIZE);
+ ret = kip->insns + (i * MAX_INSN_SIZE);
+ goto end;
}
}
/* Surprise! No unused slots. Fix kip->nused. */
@@ -160,8 +167,10 @@ kprobe_opcode_t __kprobes *get_insn_slot
}
/* All out of space. Need to allocate a new page. Use slot 0. */
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
- if (!kip)
- return NULL;
+ if (!kip) {
+ ret = NULL;
+ goto end;
+ }
/*
* Use module_alloc so this page is within +/- 2GB of where the
@@ -171,7 +180,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
kip->insns = module_alloc(PAGE_SIZE);
if (!kip->insns) {
kfree(kip);
- return NULL;
+ ret = NULL;
+ goto end;
}
INIT_HLIST_NODE(&kip->hlist);
hlist_add_head(&kip->hlist, &kprobe_insn_pages);
@@ -179,7 +189,10 @@ kprobe_opcode_t __kprobes *get_insn_slot
kip->slot_used[0] = SLOT_USED;
kip->nused = 1;
kip->ngarbage = 0;
- return kip->insns;
+ ret = kip->insns;
+end:
+ mutex_unlock(&kprobe_insn_mutex);
+ return ret;
}
/* Return 1 if all garbages are collected, otherwise 0. */
@@ -213,7 +226,7 @@ static int __kprobes collect_garbage_slo
struct kprobe_insn_page *kip;
struct hlist_node *pos, *next;
- /* Ensure no-one is preepmted on the garbages */
+ /* Ensure no-one is preempted on the garbages */
if (check_safety() != 0)
return -EAGAIN;
@@ -237,6 +250,7 @@ void __kprobes free_insn_slot(kprobe_opc
struct kprobe_insn_page *kip;
struct hlist_node *pos;
+ mutex_lock(&kprobe_insn_mutex);
hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
if (kip->insns <= slot &&
slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
@@ -253,6 +267,7 @@ void __kprobes free_insn_slot(kprobe_opc
if (dirty && ++kprobe_garbage_slots > INSNS_PER_PAGE)
collect_garbage_slots();
+ mutex_unlock(&kprobe_insn_mutex);
}
#endif
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 2/9] Kprobes - do not use kprobes mutex in arch code
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
2007-08-12 15:04 ` [patch 1/9] Kprobes - use a mutex to protect the instruction pages list Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 3/9] Kprobes - declare kprobe_mutex static Mathieu Desnoyers
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, prasanna, ananth, anil.s.keshavamurthy, davem
[-- Attachment #1: kprobes-dont-use-kprobes-mutex-in-arch-code.patch --]
[-- Type: text/plain, Size: 5101 bytes --]
Remove the kprobes mutex from kprobes.h, since it does not belong there. Also
remove all use of this mutex in the architecture specific code, replacing it by
a proper mutex lock/unlock in the architecture agnostic code.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
arch/i386/kernel/kprobes.c | 2 --
arch/ia64/kernel/kprobes.c | 2 --
arch/powerpc/kernel/kprobes.c | 2 --
arch/s390/kernel/kprobes.c | 2 --
arch/x86_64/kernel/kprobes.c | 2 --
include/linux/kprobes.h | 2 --
kernel/kprobes.c | 2 ++
7 files changed, 2 insertions(+), 12 deletions(-)
Index: linux-2.6-lttng/include/linux/kprobes.h
===================================================================
--- linux-2.6-lttng.orig/include/linux/kprobes.h 2007-08-07 15:28:05.000000000 -0400
+++ linux-2.6-lttng/include/linux/kprobes.h 2007-08-07 15:28:22.000000000 -0400
@@ -35,7 +35,6 @@
#include <linux/percpu.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
-#include <linux/mutex.h>
#ifdef CONFIG_KPROBES
#include <asm/kprobes.h>
@@ -177,7 +176,6 @@ static inline void kretprobe_assert(stru
}
extern spinlock_t kretprobe_lock;
-extern struct mutex kprobe_mutex;
extern int arch_prepare_kprobe(struct kprobe *p);
extern void arch_arm_kprobe(struct kprobe *p);
extern void arch_disarm_kprobe(struct kprobe *p);
Index: linux-2.6-lttng/arch/i386/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/kernel/kprobes.c 2007-08-07 15:28:05.000000000 -0400
+++ linux-2.6-lttng/arch/i386/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -180,9 +180,7 @@ void __kprobes arch_disarm_kprobe(struct
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- mutex_lock(&kprobe_mutex);
free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1));
- mutex_unlock(&kprobe_mutex);
}
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
Index: linux-2.6-lttng/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
+++ linux-2.6-lttng/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -656,7 +656,9 @@ valid_p:
list_del_rcu(&p->list);
kfree(old_p);
}
+ mutex_lock(&kprobe_mutex);
arch_remove_kprobe(p);
+ mutex_unlock(&kprobe_mutex);
} else {
mutex_lock(&kprobe_mutex);
if (p->break_handler)
Index: linux-2.6-lttng/arch/ia64/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/ia64/kernel/kprobes.c 2007-08-07 15:28:05.000000000 -0400
+++ linux-2.6-lttng/arch/ia64/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -565,9 +565,7 @@ void __kprobes arch_disarm_kprobe(struct
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- mutex_lock(&kprobe_mutex);
free_insn_slot(p->ainsn.insn, 0);
- mutex_unlock(&kprobe_mutex);
}
/*
* We are resuming execution after a single step fault, so the pt_regs
Index: linux-2.6-lttng/arch/powerpc/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/powerpc/kernel/kprobes.c 2007-08-07 15:28:05.000000000 -0400
+++ linux-2.6-lttng/arch/powerpc/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -86,9 +86,7 @@ void __kprobes arch_disarm_kprobe(struct
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- mutex_lock(&kprobe_mutex);
free_insn_slot(p->ainsn.insn, 0);
- mutex_unlock(&kprobe_mutex);
}
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
Index: linux-2.6-lttng/arch/s390/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/s390/kernel/kprobes.c 2007-08-07 15:28:05.000000000 -0400
+++ linux-2.6-lttng/arch/s390/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -218,9 +218,7 @@ void __kprobes arch_disarm_kprobe(struct
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- mutex_lock(&kprobe_mutex);
free_insn_slot(p->ainsn.insn, 0);
- mutex_unlock(&kprobe_mutex);
}
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
Index: linux-2.6-lttng/arch/x86_64/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/x86_64/kernel/kprobes.c 2007-08-07 15:28:06.000000000 -0400
+++ linux-2.6-lttng/arch/x86_64/kernel/kprobes.c 2007-08-07 15:28:22.000000000 -0400
@@ -219,9 +219,7 @@ void __kprobes arch_disarm_kprobe(struct
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- mutex_lock(&kprobe_mutex);
free_insn_slot(p->ainsn.insn, 0);
- mutex_unlock(&kprobe_mutex);
}
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 3/9] Kprobes - declare kprobe_mutex static
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
2007-08-12 15:04 ` [patch 1/9] Kprobes - use a mutex to protect the instruction pages list Mathieu Desnoyers
2007-08-12 15:04 ` [patch 2/9] Kprobes - do not use kprobes mutex in arch code Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 4/9] Text Edit Lock - Architecture Independent Code Mathieu Desnoyers
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, hch, prasanna, ananth, anil.s.keshavamurthy,
davem
[-- Attachment #1: kprobes-declare-kprobes-mutex-static.patch --]
[-- Type: text/plain, Size: 1183 bytes --]
Since it will not be used by other kernel objects, it makes sense to declare it
static.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: hch@infradead.org
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
kernel/kprobes.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6-lttng/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/kernel/kprobes.c 2007-07-14 15:49:17.000000000 -0400
+++ linux-2.6-lttng/kernel/kprobes.c 2007-07-14 15:49:27.000000000 -0400
@@ -69,7 +69,7 @@ static atomic_t kprobe_count;
/* NOTE: change this value only with kprobe_mutex held */
static bool kprobe_enabled;
-DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
+static DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 4/9] Text Edit Lock - Architecture Independent Code
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (2 preceding siblings ...)
2007-08-12 15:04 ` [patch 3/9] Kprobes - declare kprobe_mutex static Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 5/9] Text Edit Lock - i386 Mathieu Desnoyers
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers, Andi Kleen
[-- Attachment #1: text-edit-lock-architecture-independent-code.patch --]
[-- Type: text/plain, Size: 3160 bytes --]
This is an architecture independant synchronization around kernel text
modifications through use of a global mutex.
A mutex has been chosen so that kprobes, the main user of this, can sleep during
memory allocation between the memory read of the instructions it must replace
and the memory write of the breakpoint.
Other user of this interface: immediate values.
Paravirt and alternatives are always done when SMP is inactive, so there is no
need to use locks.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Andi Kleen <andi@firstfloor.org>
---
include/linux/memory.h | 7 +++++++
mm/memory.c | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
Index: linux-2.6-lttng/include/linux/memory.h
===================================================================
--- linux-2.6-lttng.orig/include/linux/memory.h 2007-08-09 14:52:47.000000000 -0400
+++ linux-2.6-lttng/include/linux/memory.h 2007-08-09 15:22:49.000000000 -0400
@@ -86,4 +86,11 @@ extern int remove_memory_block(unsigned
register_memory_notifier(&fn##_mem_nb); \
}
+/*
+ * Take and release the kernel text modification lock, used for code patching.
+ * Users of this lock can sleep.
+ */
+extern void kernel_text_lock(void);
+extern void kernel_text_unlock(void);
+
#endif /* _LINUX_MEMORY_H_ */
Index: linux-2.6-lttng/mm/memory.c
===================================================================
--- linux-2.6-lttng.orig/mm/memory.c 2007-08-09 15:21:10.000000000 -0400
+++ linux-2.6-lttng/mm/memory.c 2007-08-09 16:38:51.000000000 -0400
@@ -50,6 +50,8 @@
#include <linux/delayacct.h>
#include <linux/init.h>
#include <linux/writeback.h>
+#include <linux/kprobes.h>
+#include <linux/mutex.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
@@ -84,6 +86,12 @@ EXPORT_SYMBOL(high_memory);
int randomize_va_space __read_mostly = 1;
+/*
+ * mutex protecting text section modification (dynamic code patching).
+ * some users need to sleep (allocating memory...) while they hold this lock.
+ */
+static DEFINE_MUTEX(text_mutex);
+
static int __init disable_randmaps(char *s)
{
randomize_va_space = 0;
@@ -2758,3 +2766,29 @@ int access_process_vm(struct task_struct
return buf - old_buf;
}
EXPORT_SYMBOL_GPL(access_process_vm);
+
+/**
+ * kernel_text_lock - Take the kernel text modification lock
+ *
+ * Insures mutual write exclusion of kernel and modules text live text
+ * modification. Should be used for code patching.
+ * Users of this lock can sleep.
+ */
+void __kprobes kernel_text_lock(void)
+{
+ mutex_lock(&text_mutex);
+}
+EXPORT_SYMBOL_GPL(kernel_text_lock);
+
+/**
+ * kernel_text_unlock - Release the kernel text modification lock
+ *
+ * Insures mutual write exclusion of kernel and modules text live text
+ * modification. Should be used for code patching.
+ * Users of this lock can sleep.
+ */
+void __kprobes kernel_text_unlock(void)
+{
+ mutex_unlock(&text_mutex);
+}
+EXPORT_SYMBOL_GPL(kernel_text_unlock);
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 5/9] Text Edit Lock - i386
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (3 preceding siblings ...)
2007-08-12 15:04 ` [patch 4/9] Text Edit Lock - Architecture Independent Code Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 6/9] Text Edit Lock - x86_64 Mathieu Desnoyers
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers, Andi Kleen
[-- Attachment #1: text-edit-lock-i386.patch --]
[-- Type: text/plain, Size: 4122 bytes --]
Interface to use for code patching : makes sure the page is writable
between calls to kernel_text_mark_rw() and kernel_text_unmark().
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Andi Kleen <andi@firstfloor.org>
---
arch/i386/mm/init.c | 65 ++++++++++++++++++++++++++++++++++--------
include/asm-i386/cacheflush.h | 7 ++++
2 files changed, 60 insertions(+), 12 deletions(-)
Index: linux-2.6-lttng/arch/i386/mm/init.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/mm/init.c 2007-08-10 16:44:23.000000000 -0400
+++ linux-2.6-lttng/arch/i386/mm/init.c 2007-08-10 16:47:14.000000000 -0400
@@ -31,6 +31,7 @@
#include <linux/memory_hotplug.h>
#include <linux/initrd.h>
#include <linux/cpumask.h>
+#include <linux/kprobes.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -794,23 +795,15 @@ static int noinline do_test_wp_bit(void)
}
#ifdef CONFIG_DEBUG_RODATA
-
void mark_rodata_ro(void)
{
unsigned long start = PFN_ALIGN(_text);
unsigned long size = PFN_ALIGN(_etext) - start;
-#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
+ change_page_attr(virt_to_page(start),
+ size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+ printk("Write protecting the kernel text: %luk\n", size >> 10);
+
start += size;
size = (unsigned long)__end_rodata - start;
change_page_attr(virt_to_page(start),
@@ -826,6 +819,54 @@ void mark_rodata_ro(void)
*/
global_flush_tlb();
}
+
+/**
+ * kernel_text_mark_rw - Change kernel core text flags to RW
+ * @address: location of the code
+ * @len: size of code to mark
+ *
+ * Change kernel text flags to RW. Useful for code patching.
+ */
+
+void __kprobes kernel_text_mark_rw(unsigned long address, size_t len)
+{
+ if (address >= PFN_ALIGN(_text)
+ && (address + len) <= PFN_ALIGN(_etext)) {
+ unsigned long nr_pages;
+ nr_pages = ((address + len) >> PAGE_SHIFT)
+ - (address >> PAGE_SHIFT) + 1;
+ change_page_attr(virt_to_page(address), nr_pages,
+ PAGE_KERNEL_EXEC);
+ mb();
+ global_flush_tlb();
+ mb();
+ }
+}
+EXPORT_SYMBOL_GPL(kernel_text_mark_rw);
+
+/**
+ * kernel_text_unmark - Unmap a kernel text rw mapping.
+ * @address: location of the mapping
+ * @len: size of code to mark
+ *
+ * Remove RW flag from kernel text.
+ */
+
+void __kprobes kernel_text_unmark(unsigned long address, size_t len)
+{
+ if (address >= PFN_ALIGN(_text)
+ && (address + len) <= PFN_ALIGN(_etext)) {
+ unsigned long nr_pages;
+ nr_pages = ((address + len) >> PAGE_SHIFT)
+ - (address >> PAGE_SHIFT) + 1;
+ change_page_attr(virt_to_page(address), nr_pages,
+ PAGE_KERNEL_RX);
+ mb();
+ global_flush_tlb();
+ mb();
+ }
+}
+EXPORT_SYMBOL_GPL(kernel_text_unmark);
#endif
void free_init_pages(char *what, unsigned long begin, unsigned long end)
Index: linux-2.6-lttng/include/asm-i386/cacheflush.h
===================================================================
--- linux-2.6-lttng.orig/include/asm-i386/cacheflush.h 2007-08-10 16:44:23.000000000 -0400
+++ linux-2.6-lttng/include/asm-i386/cacheflush.h 2007-08-10 16:44:46.000000000 -0400
@@ -34,6 +34,13 @@ void kernel_map_pages(struct page *page,
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
+
+/* mark kernel text pages writable */
+extern void kernel_text_mark_rw(unsigned long address, size_t len);
+extern void kernel_text_unmark(unsigned long address, size_t len);
+#else
+void kernel_text_mark_rw(unsigned long address, size_t len) { }
+void kernel_text_unmark(unsigned long address, size_t len) { }
#endif
#endif /* _I386_CACHEFLUSH_H */
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 6/9] Text Edit Lock - x86_64
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (4 preceding siblings ...)
2007-08-12 15:04 ` [patch 5/9] Text Edit Lock - i386 Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 7/9] Text Edit Lock - kprobes architecture independent support Mathieu Desnoyers
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers, Andi Kleen
[-- Attachment #1: text-edit-lock-x86_64.patch --]
[-- Type: text/plain, Size: 4210 bytes --]
Interface to use for code patching : makes sure the page is writable
between calls to kernel_text_mark_rw() and kernel_text_unmark().
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Andi Kleen <andi@firstfloor.org>
---
arch/x86_64/mm/init.c | 72 +++++++++++++++++++++++++++++-----------
include/asm-x86_64/cacheflush.h | 7 +++
2 files changed, 60 insertions(+), 19 deletions(-)
Index: linux-2.6-lttng/arch/x86_64/mm/init.c
===================================================================
--- linux-2.6-lttng.orig/arch/x86_64/mm/init.c 2007-08-12 09:33:55.000000000 -0400
+++ linux-2.6-lttng/arch/x86_64/mm/init.c 2007-08-12 10:04:13.000000000 -0400
@@ -103,7 +103,7 @@ static __init void *spp_getpage(void)
{
void *ptr;
if (after_bootmem)
- ptr = (void *) get_zeroed_page(GFP_ATOMIC);
+ ptr = (void *) get_zeroed_page(GFP_KERNEL);
else
ptr = alloc_bootmem_pages(PAGE_SIZE);
if (!ptr || ((unsigned long)ptr & ~PAGE_MASK))
@@ -598,25 +598,11 @@ void free_initmem(void)
void mark_rodata_ro(void)
{
- unsigned long start = (unsigned long)_stext, end;
+ unsigned long start = PFN_ALIGN(_stext);
+ unsigned long end = PFN_ALIGN(__end_rodata);
-#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;
- if (end <= start)
- return;
-
- change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO);
+ change_page_attr_addr(start, (end - start) >> PAGE_SHIFT,
+ PAGE_KERNEL_RO);
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
@@ -629,6 +615,54 @@ void mark_rodata_ro(void)
*/
global_flush_tlb();
}
+
+/**
+ * kernel_text_mark_rw - Change kernel core text flags to RW
+ * @address: location of the code
+ * @len: size of code to mark
+ *
+ * Change kernel text flags to RW. Useful for code patching.
+ */
+
+void kernel_text_mark_rw(unsigned long address, size_t len)
+{
+ if (address >= PFN_ALIGN(_text)
+ && (address + len) <= PFN_ALIGN(_etext)) {
+ unsigned long nr_pages;
+ nr_pages = ((address + len) >> PAGE_SHIFT)
+ - (address >> PAGE_SHIFT) + 1;
+ change_page_attr(virt_to_page(address), nr_pages,
+ PAGE_KERNEL_EXEC);
+ mb();
+ global_flush_tlb();
+ mb();
+ }
+}
+EXPORT_SYMBOL_GPL(kernel_text_mark_rw);
+
+/**
+ * kernel_text_unmark - Unmap a kernel text rw mapping.
+ * @address: location of the mapping
+ * @len: size of code to mark
+ *
+ * Remove RW flag from kernel text.
+ */
+
+void kernel_text_unmark(unsigned long address, size_t len)
+{
+ if (address >= PFN_ALIGN(_text)
+ && (address + len) <= PFN_ALIGN(_etext)) {
+ unsigned long nr_pages;
+ nr_pages = ((address + len) >> PAGE_SHIFT)
+ - (address >> PAGE_SHIFT) + 1;
+ mb();
+ change_page_attr(virt_to_page(address), nr_pages,
+ PAGE_KERNEL_RO);
+ mb();
+ global_flush_tlb();
+ }
+}
+EXPORT_SYMBOL_GPL(kernel_text_unmark);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
Index: linux-2.6-lttng/include/asm-x86_64/cacheflush.h
===================================================================
--- linux-2.6-lttng.orig/include/asm-x86_64/cacheflush.h 2007-08-12 09:33:55.000000000 -0400
+++ linux-2.6-lttng/include/asm-x86_64/cacheflush.h 2007-08-12 09:34:07.000000000 -0400
@@ -31,6 +31,13 @@ void clflush_cache_range(void *addr, int
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
+
+/* mark kernel text pages writable */
+extern void kernel_text_mark_rw(unsigned long address, size_t len);
+extern void kernel_text_unmark(unsigned long address, size_t len);
+#else
+void kernel_text_mark_rw(unsigned long address, size_t len) { }
+void kernel_text_unmark(unsigned long address, size_t len) { }
#endif
#endif /* _X8664_CACHEFLUSH_H */
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 7/9] Text Edit Lock - kprobes architecture independent support
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (5 preceding siblings ...)
2007-08-12 15:04 ` [patch 6/9] Text Edit Lock - x86_64 Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 8/9] Text Edit Lock - kprobes i386 Mathieu Desnoyers
2007-08-12 15:04 ` [patch 9/9] Text Edit Lock - kprobes x86_64 Mathieu Desnoyers
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, prasanna, ananth, anil.s.keshavamurthy, davem
[-- Attachment #1: text-edit-lock-kprobes-architecture-independent.patch --]
[-- Type: text/plain, Size: 3099 bytes --]
Use the mutual exclusion provided by the text edit lock in the kprobes code. It
allows coherent manipulation of the kernel code by other subsystems.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
kernel/kprobes.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
Index: linux-2.6-lttng/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/kernel/kprobes.c 2007-08-09 15:22:49.000000000 -0400
+++ linux-2.6-lttng/kernel/kprobes.c 2007-08-09 15:25:00.000000000 -0400
@@ -43,6 +43,7 @@
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/kdebug.h>
+#include <linux/memory.h>
#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
@@ -568,9 +569,10 @@ static int __kprobes __register_kprobe(s
goto out;
}
+ kernel_text_lock();
ret = arch_prepare_kprobe(p);
if (ret)
- goto out;
+ goto out_unlock_text;
INIT_HLIST_NODE(&p->hlist);
hlist_add_head_rcu(&p->hlist,
@@ -578,7 +580,8 @@ static int __kprobes __register_kprobe(s
if (kprobe_enabled)
arch_arm_kprobe(p);
-
+out_unlock_text:
+ kernel_text_unlock();
out:
mutex_unlock(&kprobe_mutex);
@@ -621,8 +624,11 @@ valid_p:
* enabled - otherwise, the breakpoint would already have
* been removed. We save on flushing icache.
*/
- if (kprobe_enabled)
+ if (kprobe_enabled) {
+ kernel_text_lock();
arch_disarm_kprobe(p);
+ kernel_text_unlock();
+ }
hlist_del_rcu(&old_p->hlist);
cleanup_p = 1;
} else {
@@ -644,9 +650,7 @@ valid_p:
list_del_rcu(&p->list);
kfree(old_p);
}
- mutex_lock(&kprobe_mutex);
arch_remove_kprobe(p);
- mutex_unlock(&kprobe_mutex);
} else {
mutex_lock(&kprobe_mutex);
if (p->break_handler)
@@ -716,8 +720,9 @@ static int __kprobes pre_handler_kretpro
struct kretprobe_instance, uflist);
ri->rp = rp;
ri->task = current;
+ kernel_text_lock();
arch_prepare_kretprobe(ri, regs);
-
+ kernel_text_unlock();
/* XXX(hch): why is there no hlist_move_head? */
hlist_del(&ri->uflist);
hlist_add_head(&ri->uflist, &ri->rp->used_instances);
@@ -917,8 +922,10 @@ static void __kprobes enable_all_kprobes
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
head = &kprobe_table[i];
+ kernel_text_lock();
hlist_for_each_entry_rcu(p, node, head, hlist)
arch_arm_kprobe(p);
+ kernel_text_unlock();
}
kprobe_enabled = true;
@@ -946,10 +953,12 @@ static void __kprobes disable_all_kprobe
printk(KERN_INFO "Kprobes globally disabled\n");
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
head = &kprobe_table[i];
+ kernel_text_lock();
hlist_for_each_entry_rcu(p, node, head, hlist) {
if (!arch_trampoline_kprobe(p))
arch_disarm_kprobe(p);
}
+ kernel_text_unlock();
}
mutex_unlock(&kprobe_mutex);
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 8/9] Text Edit Lock - kprobes i386
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (6 preceding siblings ...)
2007-08-12 15:04 ` [patch 7/9] Text Edit Lock - kprobes architecture independent support Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
2007-08-12 15:04 ` [patch 9/9] Text Edit Lock - kprobes x86_64 Mathieu Desnoyers
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, Andi Kleen, prasanna, ananth,
anil.s.keshavamurthy, davem
[-- Attachment #1: text-edit-lock-kprobes-i386.patch --]
[-- Type: text/plain, Size: 1542 bytes --]
Kprobes can use the text edit lock to insure mutual exclusion when editing the
code.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Andi Kleen <andi@firstfloor.org>
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
arch/i386/kernel/kprobes.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
Index: linux-2.6-lttng/arch/i386/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/kernel/kprobes.c 2007-08-10 13:47:25.000000000 -0400
+++ linux-2.6-lttng/arch/i386/kernel/kprobes.c 2007-08-10 13:49:21.000000000 -0400
@@ -170,12 +170,16 @@ int __kprobes arch_prepare_kprobe(struct
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
+ kernel_text_mark_rw((unsigned long) p->addr, sizeof(kprobe_opcode_t));
+ *p->addr = BREAKPOINT_INSTRUCTION;
+ kernel_text_unmark((unsigned long) p->addr, sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- text_poke(p->addr, &p->opcode, 1);
+ kernel_text_mark_rw((unsigned long) p->addr, sizeof(kprobe_opcode_t));
+ *p->addr = p->opcode;
+ kernel_text_unmark((unsigned long) p->addr, sizeof(kprobe_opcode_t));
}
void __kprobes arch_remove_kprobe(struct kprobe *p)
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread* [patch 9/9] Text Edit Lock - kprobes x86_64
2007-08-12 15:04 [patch 0/9] Text Edit Lock Mathieu Desnoyers
` (7 preceding siblings ...)
2007-08-12 15:04 ` [patch 8/9] Text Edit Lock - kprobes i386 Mathieu Desnoyers
@ 2007-08-12 15:04 ` Mathieu Desnoyers
8 siblings, 0 replies; 10+ messages in thread
From: Mathieu Desnoyers @ 2007-08-12 15:04 UTC (permalink / raw)
To: akpm, linux-kernel
Cc: Mathieu Desnoyers, Andi Kleen, prasanna, ananth,
anil.s.keshavamurthy, davem
[-- Attachment #1: text-edit-lock-kprobes-x86_64.patch --]
[-- Type: text/plain, Size: 1772 bytes --]
Kprobes can use the text edit lock to insure mutual exclusion when editing the
code.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Andi Kleen <andi@firstfloor.org>
CC: prasanna@in.ibm.com
CC: ananth@in.ibm.com
CC: anil.s.keshavamurthy@intel.com
CC: davem@davemloft.net
---
arch/x86_64/kernel/kprobes.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
Index: linux-2.6-lttng/arch/x86_64/kernel/kprobes.c
===================================================================
--- linux-2.6-lttng.orig/arch/x86_64/kernel/kprobes.c 2007-08-10 16:44:23.000000000 -0400
+++ linux-2.6-lttng/arch/x86_64/kernel/kprobes.c 2007-08-10 17:21:07.000000000 -0400
@@ -42,6 +42,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/alternative.h>
+#include <asm/cacheflush.h>
void jprobe_return_end(void);
static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -209,12 +210,16 @@ static void __kprobes arch_copy_kprobe(s
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
+ kernel_text_mark_rw((unsigned long) p->addr, sizeof(kprobe_opcode_t));
+ *p->addr = BREAKPOINT_INSTRUCTION;
+ kernel_text_unmark((unsigned long) p->addr, sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- text_poke(p->addr, &p->opcode, 1);
+ kernel_text_mark_rw((unsigned long) p->addr, sizeof(kprobe_opcode_t));
+ *p->addr = p->opcode;
+ kernel_text_unmark((unsigned long) p->addr, sizeof(kprobe_opcode_t));
}
void __kprobes arch_remove_kprobe(struct kprobe *p)
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 10+ messages in thread