diff options
author | Satoshi Oshima <soshima@redhat.com> | 2006-05-20 18:00:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-21 15:59:21 -0400 |
commit | dc49e3445aa703eb7fd33c7ddb7e4a7bbcf06d30 (patch) | |
tree | eb164ad61b92f2df2ffab9628adffe06e635c8e2 | |
parent | be0d03f1c3d3612fe2b6aa451ae87a89382c9231 (diff) |
[PATCH] kprobes: bad manipulation of 2 byte opcode on x86_64
Problem:
If we put a probe onto a callq instruction and the probe is executed,
kernel panic of Bad RIP value occurs.
Root cause:
If resume_execution() found 0xff at first byte of p->ainsn.insn, it must
check the _second_ byte. But current resume_execution check _first_ byte
again.
I changed it checks second byte of p->ainsn.insn.
Kprobes on i386 don't have this problem, because the implementation is a
little bit different from x86_64.
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Satoshi Oshima <soshima@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/x86_64/kernel/kprobes.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index 1eaa5dae6174..fa1d19ca700a 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c | |||
@@ -514,13 +514,13 @@ static void __kprobes resume_execution(struct kprobe *p, | |||
514 | *tos = orig_rip + (*tos - copy_rip); | 514 | *tos = orig_rip + (*tos - copy_rip); |
515 | break; | 515 | break; |
516 | case 0xff: | 516 | case 0xff: |
517 | if ((*insn & 0x30) == 0x10) { | 517 | if ((insn[1] & 0x30) == 0x10) { |
518 | /* call absolute, indirect */ | 518 | /* call absolute, indirect */ |
519 | /* Fix return addr; rip is correct. */ | 519 | /* Fix return addr; rip is correct. */ |
520 | next_rip = regs->rip; | 520 | next_rip = regs->rip; |
521 | *tos = orig_rip + (*tos - copy_rip); | 521 | *tos = orig_rip + (*tos - copy_rip); |
522 | } else if (((*insn & 0x31) == 0x20) || /* jmp near, absolute indirect */ | 522 | } else if (((insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */ |
523 | ((*insn & 0x31) == 0x21)) { /* jmp far, absolute indirect */ | 523 | ((insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */ |
524 | /* rip is correct. */ | 524 | /* rip is correct. */ |
525 | next_rip = regs->rip; | 525 | next_rip = regs->rip; |
526 | } | 526 | } |