From e374dd10ba18a8e500f907a83736d173ee550c92 Mon Sep 17 00:00:00 2001 From: Alexander Shirshikov Date: Tue, 8 Feb 2011 15:05:13 +0300 Subject: [PATCH] Recursive calls fixed, thumb functions odd address modifications, etc... --- driver/us_proc_inst.c | 20 ++++++ kprobe/arch/asm-arm/dbi_kprobes.c | 123 ++++++++++++++++++++++++-------- kprobe/arch/asm-arm/dbi_kprobes.h | 3 + kprobe/arch/asm-arm/dbi_kprobes_thumb.S | 31 ++++++-- kprobe/arch/asm-arm/dbi_kprobes_thumb.h | 1 + kprobe/dbi_uprobes.c | 8 +++ 6 files changed, 153 insertions(+), 33 deletions(-) diff --git a/driver/us_proc_inst.c b/driver/us_proc_inst.c index cde8e3c..d232421 100644 --- a/driver/us_proc_inst.c +++ b/driver/us_proc_inst.c @@ -889,14 +889,34 @@ unsigned long ujprobe_event_pre_handler (us_proc_ip_t * ip, struct pt_regs *regs void ujprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6) { us_proc_ip_t *ip = __get_cpu_var (gpCurIp); + +#if defined(CONFIG_ARM) + if (ip->offset & 0x01) + { + pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ((unsigned long)ip->jprobe.kp.addr | 0x01), arg1, arg2, arg3, arg4, arg5, arg6); + }else{ + pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ip->jprobe.kp.addr, arg1, arg2, arg3, arg4, arg5, arg6); + } +#else pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ip->jprobe.kp.addr, arg1, arg2, arg3, arg4, arg5, arg6); +#endif uprobe_return (); } int uretprobe_event_handler (struct kretprobe_instance *probe, struct pt_regs *regs, us_proc_ip_t * ip) { int retval = regs_return_value(regs); + +#if defined(CONFIG_ARM) + if (ip->offset & 0x01) + { + pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ((unsigned long)ip->retprobe.kp.addr | 0x01), retval); + }else{ + pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ip->retprobe.kp.addr, retval); + } +#else pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ip->retprobe.kp.addr, retval); +#endif return 0; } diff --git a/kprobe/arch/asm-arm/dbi_kprobes.c b/kprobe/arch/asm-arm/dbi_kprobes.c index 4a75b35..1015e52 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@ -151,6 +151,47 @@ int prep_pc_dep_insn_execbuf (kprobe_opcode_t * insns, kprobe_opcode_t insn, int } + +int prep_pc_dep_insn_execbuf_thumb (kprobe_opcode_t * insns, kprobe_opcode_t insn, int uregs) +{ + unsigned char mreg = 0; + unsigned char reg = ((insn & 0xffff) & uregs) >> 8; + + printk ("prep_pc_dep_insn_execbuf_thumb: using PC, changing Rd = R%x\n", reg); + + if (reg == 6 || reg == 7) + { + printk(" >>>>> R%d in use!\n", reg); + + mreg = reg - 2; + printk(" >>>>> remap to R%d\n", mreg); + + *((unsigned short*)insns + 0) = (*((unsigned short*)insns + 0) & 0x00ff) | (mreg | (mreg + 1)); + *((unsigned short*)insns + 1) = (*((unsigned short*)insns + 1) & 0xf8ff) | (mreg << 8); + *((unsigned short*)insns + 2) = (*((unsigned short*)insns + 2) & 0xfff8) | (mreg + 1); + *((unsigned short*)insns + 3) = (*((unsigned short*)insns + 3) & 0xffc7) | (mreg << 3); + *((unsigned short*)insns + 5) = (*((unsigned short*)insns + 5) & 0xf8ff) | (mreg << 8); + *((unsigned short*)insns + 6) = (*((unsigned short*)insns + 6) & 0xffc7) | ((mreg + 1) << 3); + *((unsigned short*)insns + 7) = (*((unsigned short*)insns + 7) & 0xffc7) | ((mreg + 1) << 3); + *((unsigned short*)insns + 8) = (*((unsigned short*)insns + 0) & 0x00ff) | (mreg | (mreg + 1)); + } + + if (THUMB_INSN_MATCH (APC, insn)) + { +// ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4 + *((unsigned short*)insns + 4) = ((insn & 0xffff) | 0x800); // ADD Rd, SP, #immed_8*4 + }else{ + if (THUMB_INSN_MATCH (LRO3, insn)) + { +// LDR Rd, [PC, #immed_8*4] -> LDR Rd, [SP, #immed_8*4] + *((unsigned short*)insns + 4) = ((insn & 0xffff) + 0x5000); // LDR Rd, [SP, #immed_8*4] + } + } + return 0; +} + + + int arch_check_insn_arm (struct arch_specific_insn *ainsn) { int ret = 0; @@ -210,8 +251,7 @@ int arch_check_insn_thumb (struct arch_specific_insn *ainsn) THUMB2_INSN_MATCH (BLX1, ainsn->insn[0]) || THUMB_INSN_MATCH (BLX2, ainsn->insn[0]) || THUMB_INSN_MATCH (BX, ainsn->insn[0]) || - THUMB2_INSN_MATCH (BXJ, ainsn->insn[0]) || - THUMB_INSN_MATCH (LRO3, ainsn->insn[0])) // LDR Rd, [PC, # * 4] + THUMB2_INSN_MATCH (BXJ, ainsn->insn[0])) { DBPRINTF ("Bad insn arch_check_insn_thumb: %lx\n", ainsn->insn[0]); ret = -EFAULT; @@ -368,12 +408,6 @@ int arch_prepare_uprobe (struct kprobe *p, struct task_struct *task, int atomic) { int ret = 0; - my_p[my_probe] = p; - my_task[my_probe] = task; - my_atomic[my_probe] = atomic; - - my_probe++; - if ((unsigned long) p->addr & 0x01) { DBPRINTF ("Attempt to register kprobe at an unaligned address"); @@ -381,6 +415,12 @@ int arch_prepare_uprobe (struct kprobe *p, struct task_struct *task, int atomic) } if (!ret) { + my_p[my_probe] = p; + my_task[my_probe] = task; + my_atomic[my_probe] = atomic; + + my_probe++; + kprobe_opcode_t insn[MAX_INSN_SIZE]; if (!read_proc_vm_atomic (task, (unsigned long) p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) panic ("failed to read memory %p!\n", p->addr); @@ -454,13 +494,14 @@ int arch_copy_trampoline_arm_uprobe (struct kprobe *p, struct task_struct *task, kprobe_opcode_t insn[MAX_INSN_SIZE]; struct arch_specific_insn ainsn; - *p->addr = p->opcode; - flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); - +// *p->addr = p->opcode; +// flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); if (!read_proc_vm_atomic (task, (unsigned long) p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) panic ("failed to read memory %p!\n", p->addr); + insn[0] = p->opcode; + ainsn.insn = insn; ret = arch_check_insn_arm (&ainsn); @@ -561,6 +602,7 @@ int arch_copy_trampoline_arm_uprobe (struct kprobe *p, struct task_struct *task, } } } + return ret; } @@ -569,8 +611,9 @@ int arch_copy_trampoline_arm_uprobe (struct kprobe *p, struct task_struct *task, int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *task, int atomic) { int ret = 0; + int uregs; - kprobe_opcode_t insns[UPROBES_TRAMP_LEN]; + kprobe_opcode_t insns[UPROBES_TRAMP_LEN * 2]; if ((unsigned long) p->addr & 0x01) { @@ -582,12 +625,14 @@ int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *tas kprobe_opcode_t insn[MAX_INSN_SIZE]; struct arch_specific_insn ainsn; - *p->addr = p->opcode; - flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); +// *p->addr = p->opcode; +// flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t)); if (!read_proc_vm_atomic (task, (unsigned long) p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) panic ("failed to read memory %p!\n", p->addr); + insn[0] = p->opcode; + ainsn.insn = insn; ret = arch_check_insn_thumb (&ainsn); @@ -596,11 +641,31 @@ int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *tas if (!p->ainsn.insn) return -ENOMEM; - memcpy (insns, gen_insn_execbuf_thumb, 14*2); - *((unsigned short*)insns + 2) = insn[0]; - *((unsigned short*)insns + 9) = 0xffff; - *((unsigned short*)insns + 12) = ((unsigned short) (p->addr) + 2) & 0x0000ffff; - *((unsigned short*)insns + 13) = ((unsigned short) (p->addr) + 2) >> 16; + if (THUMB_INSN_MATCH (APC, insn[0]) || THUMB_INSN_MATCH (LRO3, insn[0])) + { + uregs = 0x0700;// Rd 8-10 + + memcpy (insns, pc_dep_insn_execbuf_thumb, 16 * 2); + if (prep_pc_dep_insn_execbuf_thumb (insns, insn[0], uregs) != 0) + { + DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]); + free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn, 0); + return -EINVAL; + } + *((unsigned short*)insns + 11) = 0xffff; + + *((unsigned short*)insns + 12) = ((unsigned short) (p->addr) + 4) & 0x0000ffff; + *((unsigned short*)insns + 13) = ((unsigned short) (p->addr) + 4) >> 16; + + *((unsigned short*)insns + 14) = ((unsigned short) (p->addr) + 2) & 0x0000ffff; + *((unsigned short*)insns + 15) = ((unsigned short) (p->addr) + 2) >> 16; + }else{ + memcpy (insns, gen_insn_execbuf_thumb, 16 * 2); + *((unsigned short*)insns + 2) = insn[0]; + *((unsigned short*)insns + 11) = 0xffff; + *((unsigned short*)insns + 14) = ((unsigned short) (p->addr) + 2) & 0x0000ffff; + *((unsigned short*)insns + 15) = ((unsigned short) (p->addr) + 2) >> 16; + } if (!write_proc_vm_atomic (task, (unsigned long) p->ainsn.insn, insns, sizeof (insns))) { @@ -612,6 +677,7 @@ int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *tas } } } + return ret; } @@ -623,13 +689,13 @@ int kprobe_handler (struct pt_regs *regs) kprobe_opcode_t *addr = NULL, *ssaddr = 0; struct kprobe_ctlblk *kcb; int my_pr = 0; + int i = 0; if (user_mode(regs)) { if (!thumb_mode ( regs )) addr = (kprobe_opcode_t *) (regs->uregs[15] - 4); else addr = (kprobe_opcode_t *) (regs->uregs[15] - 2); - int i; for(i = 0; i < my_probe; i++) { if (my_p[i]->addr == addr) @@ -641,11 +707,8 @@ int kprobe_handler (struct pt_regs *regs) my_handler_lock = 1; } } - } - if (0 == my_handler_lock) - { - if (user_mode(regs)) + if (0 == my_handler_lock) { my_handler_lock = 1; @@ -728,7 +791,7 @@ int kprobe_handler (struct pt_regs *regs) if (!thumb_mode ( regs )) p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current); else - p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x12, pid, current); + p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x16, pid, current); if (p) { save_previous_kprobe (kcb, p); @@ -785,7 +848,7 @@ int kprobe_handler (struct pt_regs *regs) if (!thumb_mode ( regs )) p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current); else - p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x12, pid, current); + p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x16, pid, current); if (!p) { /* Not one of ours: let kernel handle it */ @@ -802,12 +865,14 @@ int kprobe_handler (struct pt_regs *regs) } } + // restore second opcode for thumb app if (user_mode( regs ) && thumb_mode( regs )) { *((unsigned short*)p->addr + 1) = p->opcode >> 16; flush_icache_range ((unsigned int) p->addr, (unsigned int) (((unsigned int) p->addr) + (sizeof (kprobe_opcode_t) * 2))); } + set_current_kprobe (p, regs, kcb); if(!reenter) @@ -1021,7 +1086,7 @@ int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs) if (!thumb_mode( regs )) trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX); else - trampoline_address = (unsigned long)(p->ainsn.insn + 0x13); + trampoline_address = (unsigned long)(p->ainsn.insn + 0x17); } INIT_HLIST_HEAD (&empty_rp); @@ -1093,7 +1158,7 @@ int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs) if (thumb_mode( regs ) && !(regs->uregs[14] & 0x01)) { - regs->ARM_cpsr ^= 0x20; + regs->ARM_cpsr &= 0xFFFFFFDF; }else{ if (user_mode( regs ) && (regs->uregs[14] & 0x01)) { @@ -1169,7 +1234,7 @@ void __arch_prepare_kretprobe (struct kretprobe *rp, struct pt_regs *regs) if (!thumb_mode( regs )) regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX); else - regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn) + 0x13; + regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn) + 0x17; else /* Replace the return addr with trampoline addr */ regs->uregs[14] = (unsigned long) &kretprobe_trampoline; diff --git a/kprobe/arch/asm-arm/dbi_kprobes.h b/kprobe/arch/asm-arm/dbi_kprobes.h index 2d0b459..c34383a 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.h +++ b/kprobe/arch/asm-arm/dbi_kprobes.h @@ -164,6 +164,9 @@ typedef unsigned long kprobe_opcode_t; # define MASK_THUMB_INSN_DP 0xFC00 // 111111xxxxxxxxxx # define PTRN_THUMB_INSN_DP 0x4000 // 010000xxxxxxxxxx +# define MASK_THUMB_INSN_APC 0xF800 // 11111xxxxxxxxxxx +# define PTRN_THUMB_INSN_APC 0xA000 // 10100xxxxxxxxxxx ADD Rd, [PC, # * 4] + # define MASK_THUMB2_INSN_DPI 0xFBE08000 // 11111x11111xxxxx1xxxxxxxxxxxxxxx //# define PTRN_THUMB2_INSN_DPI 0xF0000000 // 11110x0xxxxxxxxx0xxxxxxxxxxxxxxx /? A6-19 ARM DDI 0406B # define PTRN_THUMB2_INSN_DPI 0xF2000000 // 11110x1xxxxxxxxx0xxxxxxxxxxxxxxx /? A6-19 ARM DDI 0406B diff --git a/kprobe/arch/asm-arm/dbi_kprobes_thumb.S b/kprobe/arch/asm-arm/dbi_kprobes_thumb.S index 8debc2c..159bde6 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes_thumb.S +++ b/kprobe/arch/asm-arm/dbi_kprobes_thumb.S @@ -4,8 +4,8 @@ * - When the probed function returns, this probe * causes the handlers to fire */ - .thumb + .thumb .global gen_insn_execbuf_thumb @@ -14,13 +14,36 @@ gen_insn_execbuf_thumb: nop nop // original instruction nop + nop + nop push {r7} - ldr r7, [pc, #12] // ssbreak - mov lr, r7 + ldr r7, [pc, #12] + mov ip, r7 pop {r7} - mov pc, lr + mov pc, ip // ssbreak nop // retbreak nop nop nop // stored PC-4(next insn addr) hi nop // stored PC-4(next insn addr) lo + + nop + + .global pc_dep_insn_execbuf_thumb +pc_dep_insn_execbuf_thumb: + push {r6, r7} + ldr r6, i1 + mov r7, sp + mov sp, r6 + nop // PC -> SP + ldr r6, i2 + mov ip, r6 + mov sp, r7 + pop {r6, r7} + nop + mov pc, ip // ssbreak + nop // retbreak + nop // stored PC hi +i1: nop // stored PC lo + nop // stored PC-4(next insn addr) hi +i2: nop // stored PC-4(next insn addr) lo diff --git a/kprobe/arch/asm-arm/dbi_kprobes_thumb.h b/kprobe/arch/asm-arm/dbi_kprobes_thumb.h index afc8842..3859f9c 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes_thumb.h +++ b/kprobe/arch/asm-arm/dbi_kprobes_thumb.h @@ -1 +1,2 @@ void gen_insn_execbuf_thumb(void); +void pc_dep_insn_execbuf_thumb(void); diff --git a/kprobe/dbi_uprobes.c b/kprobe/dbi_uprobes.c index 9931740..fc124b3 100644 --- a/kprobe/dbi_uprobes.c +++ b/kprobe/dbi_uprobes.c @@ -55,6 +55,14 @@ int __register_uprobe (struct kprobe *p, struct task_struct *task, int atomic, u DBPRINTF ("p->addr = 0x%p p = 0x%p\n", p->addr, p); +// thumb address = address-1; +#if defined(CONFIG_ARM) + if ((unsigned long) p->addr & 0x01) + { + p->addr = (unsigned long)p->addr & 0xfffffffe; + } +#endif + p->mod_refcounted = 0; p->nmissed = 0; #ifdef KPROBES_PROFILE -- 2.7.4