⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kprobes_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			"	popl %esi\n"			"	popl %edi\n"			"	popl %ebp\n"			"	popl %eax\n"			/* skip eip, orig_eax, es, ds, fs */			"	addl $20, %esp\n"			"	popf\n"			"	ret\n");}/* * Called from kretprobe_trampoline */fastcall void *__kprobes trampoline_handler(struct pt_regs *regs){	struct kretprobe_instance *ri = NULL;	struct hlist_head *head, empty_rp;	struct hlist_node *node, *tmp;	unsigned long flags, orig_ret_address = 0;	unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;	INIT_HLIST_HEAD(&empty_rp);	spin_lock_irqsave(&kretprobe_lock, flags);	head = kretprobe_inst_table_head(current);	/* fixup registers */	regs->xcs = __KERNEL_CS | get_kernel_rpl();	regs->eip = trampoline_address;	regs->orig_eax = 0xffffffff;	/*	 * It is possible to have multiple instances associated with a given	 * task either because an multiple functions in the call path	 * have a return probe installed on them, and/or more then one return	 * return probe was registered for a target function.	 *	 * We can handle this because:	 *     - instances are always inserted at the head of the list	 *     - when multiple return probes are registered for the same	 *       function, the first instance's ret_addr will point to the	 *       real return address, and all the rest will point to	 *       kretprobe_trampoline	 */	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {		if (ri->task != current)			/* another task is sharing our hash bucket */			continue;		if (ri->rp && ri->rp->handler){			__get_cpu_var(current_kprobe) = &ri->rp->kp;			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;			ri->rp->handler(ri, regs);			__get_cpu_var(current_kprobe) = NULL;		}		orig_ret_address = (unsigned long)ri->ret_addr;		recycle_rp_inst(ri, &empty_rp);		if (orig_ret_address != trampoline_address)			/*			 * This is the real return address. Any other			 * instances associated with this task are for			 * other calls deeper on the call stack			 */			break;	}	kretprobe_assert(ri, orig_ret_address, trampoline_address);	spin_unlock_irqrestore(&kretprobe_lock, flags);	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {		hlist_del(&ri->hlist);		kfree(ri);	}	return (void*)orig_ret_address;}/* * Called after single-stepping.  p->addr is the address of the * instruction whose first byte has been replaced by the "int 3" * instruction.  To avoid the SMP problems that can occur when we * temporarily put back the original opcode to single-step, we * single-stepped a copy of the instruction.  The address of this * copy is p->ainsn.insn. * * This function prepares to return from the post-single-step * interrupt.  We have to fix up the stack as follows: * * 0) Except in the case of absolute or indirect jump or call instructions, * the new eip is relative to the copied instruction.  We need to make * it relative to the original instruction. * * 1) If the single-stepped instruction was pushfl, then the TF and IF * flags are set in the just-pushed eflags, and may need to be cleared. * * 2) If the single-stepped instruction was a call, the return address * that is atop the stack is the address following the copied instruction. * We need to make it the address following the original instruction. * * This function also checks instruction size for preparing direct execution. */static void __kprobes resume_execution(struct kprobe *p,		struct pt_regs *regs, struct kprobe_ctlblk *kcb){	unsigned long *tos = (unsigned long *)&regs->esp;	unsigned long copy_eip = (unsigned long)p->ainsn.insn;	unsigned long orig_eip = (unsigned long)p->addr;	regs->eflags &= ~TF_MASK;	switch (p->ainsn.insn[0]) {	case 0x9c:		/* pushfl */		*tos &= ~(TF_MASK | IF_MASK);		*tos |= kcb->kprobe_old_eflags;		break;	case 0xc2:		/* iret/ret/lret */	case 0xc3:	case 0xca:	case 0xcb:	case 0xcf:	case 0xea:		/* jmp absolute -- eip is correct */		/* eip is already adjusted, no more changes required */		p->ainsn.boostable = 1;		goto no_change;	case 0xe8:		/* call relative - Fix return addr */		*tos = orig_eip + (*tos - copy_eip);		break;	case 0x9a:		/* call absolute -- same as call absolute, indirect */		*tos = orig_eip + (*tos - copy_eip);		goto no_change;	case 0xff:		if ((p->ainsn.insn[1] & 0x30) == 0x10) {			/*			 * call absolute, indirect			 * Fix return addr; eip is correct.			 * But this is not boostable			 */			*tos = orig_eip + (*tos - copy_eip);			goto no_change;		} else if (((p->ainsn.insn[1] & 0x31) == 0x20) ||	/* jmp near, absolute indirect */			   ((p->ainsn.insn[1] & 0x31) == 0x21)) {	/* jmp far, absolute indirect */			/* eip is correct. And this is boostable */			p->ainsn.boostable = 1;			goto no_change;		}	default:		break;	}	if (p->ainsn.boostable == 0) {		if ((regs->eip > copy_eip) &&		    (regs->eip - copy_eip) + 5 < MAX_INSN_SIZE) {			/*			 * These instructions can be executed directly if it			 * jumps back to correct address.			 */			set_jmp_op((void *)regs->eip,				   (void *)orig_eip + (regs->eip - copy_eip));			p->ainsn.boostable = 1;		} else {			p->ainsn.boostable = -1;		}	}	regs->eip = orig_eip + (regs->eip - copy_eip);no_change:	return;}/* * Interrupts are disabled on entry as trap1 is an interrupt gate and they * remain disabled thoroughout this function. */static int __kprobes post_kprobe_handler(struct pt_regs *regs){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	if (!cur)		return 0;	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {		kcb->kprobe_status = KPROBE_HIT_SSDONE;		cur->post_handler(cur, regs, 0);	}	resume_execution(cur, regs, kcb);	regs->eflags |= kcb->kprobe_saved_eflags;	trace_hardirqs_fixup_flags(regs->eflags);	/*Restore back the original saved kprobes variables and continue. */	if (kcb->kprobe_status == KPROBE_REENTER) {		restore_previous_kprobe(kcb);		goto out;	}	reset_current_kprobe();out:	preempt_enable_no_resched();	/*	 * if somebody else is singlestepping across a probe point, eflags	 * will have TF set, in which case, continue the remaining processing	 * of do_debug, as if this is not a probe hit.	 */	if (regs->eflags & TF_MASK)		return 0;	return 1;}int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	switch(kcb->kprobe_status) {	case KPROBE_HIT_SS:	case KPROBE_REENTER:		/*		 * We are here because the instruction being single		 * stepped caused a page fault. We reset the current		 * kprobe and the eip points back to the probe address		 * and allow the page fault handler to continue as a		 * normal page fault.		 */		regs->eip = (unsigned long)cur->addr;		regs->eflags |= kcb->kprobe_old_eflags;		if (kcb->kprobe_status == KPROBE_REENTER)			restore_previous_kprobe(kcb);		else			reset_current_kprobe();		preempt_enable_no_resched();		break;	case KPROBE_HIT_ACTIVE:	case KPROBE_HIT_SSDONE:		/*		 * We increment the nmissed count for accounting,		 * we can also use npre/npostfault count for accouting		 * these specific fault cases.		 */		kprobes_inc_nmissed_count(cur);		/*		 * We come here because instructions in the pre/post		 * handler caused the page_fault, this could happen		 * if handler tries to access user space by		 * copy_from_user(), get_user() etc. Let the		 * user-specified handler try to fix it first.		 */		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))			return 1;		/*		 * In case the user-specified fault handler returned		 * zero, try to fix up.		 */		if (fixup_exception(regs))			return 1;		/*		 * fixup_exception() could not handle it,		 * Let do_page_fault() fix it.		 */		break;	default:		break;	}	return 0;}/* * Wrapper routine to for handling exceptions. */int __kprobes kprobe_exceptions_notify(struct notifier_block *self,				       unsigned long val, void *data){	struct die_args *args = (struct die_args *)data;	int ret = NOTIFY_DONE;	if (args->regs && user_mode_vm(args->regs))		return ret;	switch (val) {	case DIE_INT3:		if (kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_DEBUG:		if (post_kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_GPF:		/* kprobe_running() needs smp_processor_id() */		preempt_disable();		if (kprobe_running() &&		    kprobe_fault_handler(args->regs, args->trapnr))			ret = NOTIFY_STOP;		preempt_enable();		break;	default:		break;	}	return ret;}int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs){	struct jprobe *jp = container_of(p, struct jprobe, kp);	unsigned long addr;	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	kcb->jprobe_saved_regs = *regs;	kcb->jprobe_saved_esp = &regs->esp;	addr = (unsigned long)(kcb->jprobe_saved_esp);	/*	 * TBD: As Linus pointed out, gcc assumes that the callee	 * owns the argument space and could overwrite it, e.g.	 * tailcall optimization. So, to be absolutely safe	 * we also save and restore enough stack bytes to cover	 * the argument area.	 */	memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,			MIN_STACK_SIZE(addr));	regs->eflags &= ~IF_MASK;	trace_hardirqs_off();	regs->eip = (unsigned long)(jp->entry);	return 1;}void __kprobes jprobe_return(void){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	asm volatile ("       xchgl   %%ebx,%%esp     \n"		      "       int3			\n"		      "       .globl jprobe_return_end	\n"		      "       jprobe_return_end:	\n"		      "       nop			\n"::"b"		      (kcb->jprobe_saved_esp):"memory");}int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	u8 *addr = (u8 *) (regs->eip - 1);	unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_esp);	struct jprobe *jp = container_of(p, struct jprobe, kp);	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {		if (&regs->esp != kcb->jprobe_saved_esp) {			struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;			printk("current esp %p does not match saved esp %p\n",			       &regs->esp, kcb->jprobe_saved_esp);			printk("Saved registers for jprobe %p\n", jp);			show_registers(saved_regs);			printk("Current registers\n");			show_registers(regs);			BUG();		}		*regs = kcb->jprobe_saved_regs;		memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,		       MIN_STACK_SIZE(stack_addr));		preempt_enable_no_resched();		return 1;	}	return 0;}int __kprobes arch_trampoline_kprobe(struct kprobe *p){	return 0;}int __init arch_init_kprobes(void){	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -