Text Edit Lock
Subsystems (5)
cover Text Edit Lock
Hi Andrew,
Here is the the text edit lock.
It consists in an architecture independent mutex that protects live kernel text modification and architecture specific RX/RWX remapping functions (for i386 and x86_64) to support the DEBUG_RODATA config option.
It applies on 2.6.23-rc2-mm2.
Series files:
kprobes-use-mutex-for-insn-pages.patch kprobes-dont-use-kprobes-mutex-in-arch-code.patch kprobes-declare-kprobes-mutex-static.patch text-edit-lock-architecture-independent-code.patch text-edit-lock-i386.patch text-edit-lock-x86_64.patch text-edit-lock-kprobes-architecture-independent.patch text-edit-lock-kprobes-i386.patch text-edit-lock-kprobes-x86_64.patch
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 1/9 Kprobes - use a mutex to protect the instruction pages list.
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.
--- kernel/kprobes.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-)
kernel/kprobes.c +21 -6
@@ -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_slotif (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_slostruct 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_opcstruct 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_opcif (dirty && ++kprobe_garbage_slots >INSNS_PER_PAGE )collect_garbage_slots (); + mutex_unlock(&kprobe_insn_mutex); }#endif
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 2/9 Kprobes - do not use kprobes mutex in arch code
In reply to Mathieu DesnoyersRemove 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.
--- 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(-)
include/linux/kprobes.h +0 -2
@@ -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);
arch/i386/kernel/kprobes.c +0 -2
@@ -180,9 +180,7 @@ void __kprobes arch_disarm_kprobe(structvoid __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)
kernel/kprobes.c +2 -0
@@ -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)
arch/ia64/kernel/kprobes.c +0 -2
@@ -565,9 +565,7 @@ void __kprobes arch_disarm_kprobe(structvoid __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
arch/powerpc/kernel/kprobes.c +0 -2
@@ -86,9 +86,7 @@ void __kprobes arch_disarm_kprobe(structvoid __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)
arch/s390/kernel/kprobes.c +0 -2
@@ -218,9 +218,7 @@ void __kprobes arch_disarm_kprobe(structvoid __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)
arch/x86_64/kernel/kprobes.c +0 -2
@@ -219,9 +219,7 @@ void __kprobes arch_disarm_kprobe(structvoid __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)
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 3/9 Kprobes - declare kprobe_mutex static
In reply to Mathieu DesnoyersSince it will not be used by other kernel objects, it makes sense to declare it static.
--- kernel/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/kprobes.c +1 -1
@@ -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;
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 4/9 Text Edit Lock - Architecture Independent Code
In reply to Mathieu DesnoyersThis 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.
--- include/linux/memory.h | 7 +++++++ mm/memory.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
include/linux/memory.h +7 -0
@@ -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_ */
mm/memory.c +34 -0
@@ -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_structreturn 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);
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 5/9 Text Edit Lock - i386
In reply to Mathieu DesnoyersInterface to use for code patching : makes sure the page is writable between calls to kernel_text_mark_rw() and kernel_text_unmark().
--- arch/i386/mm/init.c | 65 ++++++++++++++++++++++++++++++++++-------- include/asm-i386/cacheflush.h | 7 ++++ 2 files changed, 60 insertions(+), 12 deletions(-)
arch/i386/mm/init.c +53 -12
@@ -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)
include/asm-i386/cacheflush.h +7 -0
@@ -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 */
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 6/9 Text Edit Lock - x86_64
In reply to Mathieu DesnoyersInterface to use for code patching : makes sure the page is writable between calls to kernel_text_mark_rw() and kernel_text_unmark().
--- arch/x86_64/mm/init.c | 72 +++++++++++++++++++++++++++++----------- include/asm-x86_64/cacheflush.h | 7 +++ 2 files changed, 60 insertions(+), 19 deletions(-)
arch/x86_64/mm/init.c +53 -19
@@ -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
include/asm-x86_64/cacheflush.h +7 -0
@@ -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 */
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 7/9 Text Edit Lock - kprobes architecture independent support
In reply to Mathieu DesnoyersUse the mutual exclusion provided by the text edit lock in the kprobes code. It allows coherent manipulation of the kernel code by other subsystems.
--- kernel/kprobes.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
kernel/kprobes.c +15 -6
@@ -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(sif (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_kprobesfor (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_kprobeprintk (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);
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 8/9 Text Edit Lock - kprobes i386
In reply to Mathieu DesnoyersKprobes can use the text edit lock to insure mutual exclusion when editing the code.
--- arch/i386/kernel/kprobes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/i386/kernel/kprobes.c +6 -2
@@ -170,12 +170,16 @@ int __kprobes arch_prepare_kprobe(structvoid __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)
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
PATCH 9/9 Text Edit Lock - kprobes x86_64
In reply to Mathieu DesnoyersKprobes can use the text edit lock to insure mutual exclusion when editing the code.
--- arch/x86_64/kernel/kprobes.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
arch/x86_64/kernel/kprobes.c +7 -2
@@ -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(svoid __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)
Signature · 3 lines
Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68