Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29b6cd79 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar
Browse files

x86: jprobe bugfix



jprobe for x86-64 may cause kernel page fault when the jprobe_return()
is called from incorrect function.

- Use jprobe_saved_regs instead getting it from stack.
  (Especially on x86-64, it may get incorrect data, because
   pt_regs can not be get by using container_of(rsp))
- Change the type of stack pointer to unsigned long *.

Signed-off-by: default avatarMasami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent b4be6258
Loading
Loading
Loading
Loading
+1 −3
Original line number Original line Diff line number Diff line
@@ -727,9 +727,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)


	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
		if (&regs->esp != kcb->jprobe_saved_esp) {
		if (&regs->esp != kcb->jprobe_saved_esp) {
			struct pt_regs *saved_regs =
			struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
			    container_of(kcb->jprobe_saved_esp,
					    struct pt_regs, esp);
			printk("current esp %p does not match saved esp %p\n",
			printk("current esp %p does not match saved esp %p\n",
			       &regs->esp, kcb->jprobe_saved_esp);
			       &regs->esp, kcb->jprobe_saved_esp);
			printk("Saved registers for jprobe %p\n", jp);
			printk("Saved registers for jprobe %p\n", jp);
+2 −4
Original line number Original line Diff line number Diff line
@@ -716,10 +716,8 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
	struct jprobe *jp = container_of(p, struct jprobe, kp);
	struct jprobe *jp = container_of(p, struct jprobe, kp);


	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
		if ((long *)regs->rsp != kcb->jprobe_saved_rsp) {
		if ((unsigned long *)regs->rsp != kcb->jprobe_saved_rsp) {
			struct pt_regs *saved_regs =
			struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
			    container_of(kcb->jprobe_saved_rsp,
					    struct pt_regs, rsp);
			printk("current rsp %p does not match saved rsp %p\n",
			printk("current rsp %p does not match saved rsp %p\n",
			       (long *)regs->rsp, kcb->jprobe_saved_rsp);
			       (long *)regs->rsp, kcb->jprobe_saved_rsp);
			printk("Saved registers for jprobe %p\n", jp);
			printk("Saved registers for jprobe %p\n", jp);
+1 −1
Original line number Original line Diff line number Diff line
@@ -73,7 +73,7 @@ struct kprobe_ctlblk {
	unsigned long kprobe_status;
	unsigned long kprobe_status;
	unsigned long kprobe_old_eflags;
	unsigned long kprobe_old_eflags;
	unsigned long kprobe_saved_eflags;
	unsigned long kprobe_saved_eflags;
	long *jprobe_saved_esp;
	unsigned long *jprobe_saved_esp;
	struct pt_regs jprobe_saved_regs;
	struct pt_regs jprobe_saved_regs;
	kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
	kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
	struct prev_kprobe prev_kprobe;
	struct prev_kprobe prev_kprobe;
+1 −1
Original line number Original line Diff line number Diff line
@@ -66,7 +66,7 @@ struct kprobe_ctlblk {
	unsigned long kprobe_status;
	unsigned long kprobe_status;
	unsigned long kprobe_old_rflags;
	unsigned long kprobe_old_rflags;
	unsigned long kprobe_saved_rflags;
	unsigned long kprobe_saved_rflags;
	long *jprobe_saved_rsp;
	unsigned long *jprobe_saved_rsp;
	struct pt_regs jprobe_saved_regs;
	struct pt_regs jprobe_saved_regs;
	kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
	kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
	struct prev_kprobe prev_kprobe;
	struct prev_kprobe prev_kprobe;