From c59399ef27a3e432c6f791eb5b271d1b7d96b90e Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Tue, 16 Sep 2014 19:26:46 +0400 Subject: [PATCH] [FIX] use mem_text_write_kernel_word() Change-Id: Ieaabaf496f5ec1df67304c2ac310fc5ef1cf7bfe Signed-off-by: Vyacheslav Cherkashin --- kprobe/Kbuild | 10 +++- kprobe/arch/asm-arm/memory_rwx.c | 96 ++++++++++++++++++++++++++++++++++++++ kprobe/arch/asm-arm/memory_rwx.h | 35 ++++++++++++++ kprobe/arch/asm-arm/swap_kprobes.c | 29 ++++++------ 4 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 kprobe/arch/asm-arm/memory_rwx.c create mode 100644 kprobe/arch/asm-arm/memory_rwx.h diff --git a/kprobe/Kbuild b/kprobe/Kbuild index b5a9a09..4a71126 100644 --- a/kprobe/Kbuild +++ b/kprobe/Kbuild @@ -5,4 +5,12 @@ swap_kprobe-y := swap_kprobes.o \ swap_kprobes_deps.o \ arch/asm/swap_kprobes.o \ swap_slots.o -swap_kprobe-$(CONFIG_ARM) += arch/asm/trampoline_arm.o + +ifeq ($(CONFIG_ARM), y) +swap_kprobe-y += arch/asm/trampoline_arm.o + +ifeq ($(CONFIG_STRICT_MEMORY_RWX), y) +swap_kprobe-y += arch/asm/memory_rwx.o +endif # CONFIG_STRICT_MEMORY_RWX + +endif # CONFIG_ARM \ No newline at end of file diff --git a/kprobe/arch/asm-arm/memory_rwx.c b/kprobe/arch/asm-arm/memory_rwx.c new file mode 100644 index 0000000..d120872 --- /dev/null +++ b/kprobe/arch/asm-arm/memory_rwx.c @@ -0,0 +1,96 @@ +/* + * @author Vyacheslav Cherkashin new memory allocator for slots + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * @section COPYRIGHT + * + * Copyright (C) Samsung Electronics, 2014 + */ + + +#include +#include +#include + + +#include + + +static unsigned long get_init_mm(void) +{ + static unsigned long addr = 0; + + if (addr == 0) + addr = swap_ksyms("init_mm"); + + return addr; +} + +static int get_pte_cb(pte_t *ptep, pgtable_t token, + unsigned long addr, void *data) +{ + *(pte_t *)data = *ptep; + + return 1; +} + +static pte_t get_pte(unsigned long page_addr) +{ + struct mm_struct *mm = (struct mm_struct *)get_init_mm(); + pte_t pte = 0; + + apply_to_page_range(mm, page_addr, PAGE_SIZE, get_pte_cb, &pte); + + return pte; +} + +static void write_to_module(unsigned long addr, unsigned long val) +{ + unsigned long *maddr = (unsigned long *)addr; + unsigned long page_addr = addr & PAGE_MASK; + pte_t pte; + + pte = get_pte(page_addr); + if (pte_write(pte) == 0) { + unsigned long flags; + DEFINE_SPINLOCK(mem_lock); + + spin_lock_irqsave(&mem_lock, flags); + set_memory_rw(page_addr, 1); + *maddr = val; + set_memory_ro(page_addr, 1); + spin_unlock_irqrestore(&mem_lock, flags); + } else { + *maddr = val; + } + + flush_icache_range(addr, addr + sizeof(long)); +} + +void mem_rwx_write_u32(unsigned long addr, unsigned long val) +{ + if (addr < MODULES_VADDR || addr >= MODULES_END) { + /* + * if addr doesn't belongs kernel space, + * segmentation fault will occur + */ + mem_text_write_kernel_word((long *)addr, val); + } else { + write_to_module(addr, val); + } +} diff --git a/kprobe/arch/asm-arm/memory_rwx.h b/kprobe/arch/asm-arm/memory_rwx.h new file mode 100644 index 0000000..a083a3b --- /dev/null +++ b/kprobe/arch/asm-arm/memory_rwx.h @@ -0,0 +1,35 @@ +/** + * @file kprobe/arch/asm-arm/memory_rwx.h + * + * @author Vyacheslav Cherkashin new memory allocator for slots + * + * @section LICENSE + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * @section COPYRIGHT + * + * Copyright (C) Samsung Electronics, 2014 + */ + + +#ifndef _MEMORY_RWX_H +#define _MEMORY_RWX_H + + +void mem_rwx_write_u32(unsigned long addr, unsigned long val); + + +#endif /* _MEMORY_RWX_H */ diff --git a/kprobe/arch/asm-arm/swap_kprobes.c b/kprobe/arch/asm-arm/swap_kprobes.c index df1bfe4..9b22373 100644 --- a/kprobe/arch/asm-arm/swap_kprobes.c +++ b/kprobe/arch/asm-arm/swap_kprobes.c @@ -530,8 +530,19 @@ int swap_longjmp_break_handler (struct kprobe *p, struct pt_regs *regs) EXPORT_SYMBOL_GPL(swap_longjmp_break_handler); #ifdef CONFIG_STRICT_MEMORY_RWX -extern void mem_text_write_kernel_word(unsigned long *addr, unsigned long word); -#endif +#include "memory_rwx.h" + +static void write_u32(unsigned long addr, unsigned long val) +{ + mem_rwx_write_u32(addr, val); +} +#else /* CONFIG_STRICT_MEMORY_RWX */ +static void write_u32(unsigned long addr, unsigned long val) +{ + *(long *)addr = BREAKPOINT_INSTRUCTION; + flush_icache_range(addr, addr + sizeof(long)); +} +#endif /* CONFIG_STRICT_MEMORY_RWX */ /** * @brief Arms kprobe. @@ -541,12 +552,7 @@ extern void mem_text_write_kernel_word(unsigned long *addr, unsigned long word); */ void swap_arch_arm_kprobe(struct kprobe *p) { -#ifdef CONFIG_STRICT_MEMORY_RWX - mem_text_write_kernel_word(p->addr, BREAKPOINT_INSTRUCTION); -#else - *p->addr = BREAKPOINT_INSTRUCTION; - flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); -#endif + write_u32((long)p->addr, BREAKPOINT_INSTRUCTION); } /** @@ -557,12 +563,7 @@ void swap_arch_arm_kprobe(struct kprobe *p) */ void swap_arch_disarm_kprobe(struct kprobe *p) { -#ifdef CONFIG_STRICT_MEMORY_RWX - mem_text_write_kernel_word(p->addr, p->opcode); -#else - *p->addr = p->opcode; - flush_icache_range((unsigned long)p->addr, (unsigned long)p->addr + sizeof(kprobe_opcode_t)); -#endif + write_u32((long)p->addr, p->opcode); } /** -- 2.7.4