23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/ptrace.h>
30 #include <asm/processor.h>
36 #define UPROBE_FIX_NONE 0x0
39 #define UPROBE_FIX_IP 0x1
42 #define UPROBE_FIX_CALL 0x2
45 #define UPROBE_FIX_SETF 0x4
47 #define UPROBE_FIX_RIP_AX 0x8000
48 #define UPROBE_FIX_RIP_CX 0x4000
50 #define UPROBE_TRAP_NR UINT_MAX
53 #define OPCODE1(insn) ((insn)->opcode.bytes[0])
54 #define OPCODE2(insn) ((insn)->opcode.bytes[1])
55 #define OPCODE3(insn) ((insn)->opcode.bytes[2])
56 #define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value)
58 #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
59 (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \
60 (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \
61 (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \
62 (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \
70 static volatile u32 good_insns_32[256 / 32] = {
73 W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) |
74 W(0x10, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) ,
75 W(0x20, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) |
76 W(0x30, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) ,
77 W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
78 W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
79 W(0x60, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) |
80 W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
81 W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
82 W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
83 W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
84 W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
85 W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) |
86 W(0xd0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
87 W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) |
88 W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1)
94 static volatile u32 good_2byte_insns[256 / 32] = {
97 W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) |
98 W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) ,
99 W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) |
100 W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ,
101 W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
102 W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
103 W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
104 W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) ,
105 W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
106 W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
107 W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) |
108 W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) ,
109 W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
110 W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
111 W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
112 W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
119 static volatile u32 good_insns_64[256 / 32] = {
122 W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) |
123 W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) ,
124 W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) |
125 W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) ,
126 W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
127 W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
128 W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) |
129 W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
130 W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
131 W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
132 W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
133 W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
134 W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) |
135 W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) ,
136 W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) |
137 W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1)
195 static bool is_prefix_bad(
struct insn *
insn)
199 for (i = 0; i < insn->
prefixes.nbytes; i++) {
212 static int validate_insn_32bits(
struct arch_uprobe *auprobe,
struct insn *insn)
218 if (is_prefix_bad(insn))
224 if (insn->
opcode.nbytes == 2) {
237 static void prepare_fixups(
struct arch_uprobe *auprobe,
struct insn *insn)
239 bool fix_ip =
true, fix_call =
false;
266 if (reg == 2 || reg == 3) {
271 }
else if (reg == 4 || reg == 5) {
321 auprobe->rip_rela_target_address = 0x0;
331 cursor = auprobe->
insn + insn_offset_rex_prefix(insn);
340 cursor = auprobe->
insn + insn_offset_modrm(insn);
364 *cursor = (reg << 3);
378 static int validate_insn_64bits(
struct arch_uprobe *auprobe,
struct insn *insn)
384 if (is_prefix_bad(insn))
390 if (insn->
opcode.nbytes == 2) {
397 static int validate_insn_bits(
struct arch_uprobe *auprobe,
struct mm_struct *mm,
struct insn *insn)
400 return validate_insn_32bits(auprobe, insn);
401 return validate_insn_64bits(auprobe, insn);
404 static void handle_riprel_insn(
struct arch_uprobe *auprobe,
struct mm_struct *mm,
struct insn *insn)
409 static int validate_insn_bits(
struct arch_uprobe *auprobe,
struct mm_struct *mm,
struct insn *insn)
411 return validate_insn_32bits(auprobe, insn);
428 ret = validate_insn_bits(auprobe, mm, &insn);
432 handle_riprel_insn(auprobe, mm, &insn);
433 prepare_fixups(auprobe, &insn);
448 autask->saved_scratch_register = regs->ax;
449 regs->ax =
current->utask->vaddr;
450 regs->ax += auprobe->rip_rela_target_address;
452 autask->saved_scratch_register = regs->cx;
453 regs->cx =
current->utask->vaddr;
454 regs->cx += auprobe->rip_rela_target_address;
475 autask = &
current->utask->autask;
478 regs->ip =
current->utask->xol_vaddr;
479 pre_xol_rip_insn(auprobe, regs, autask);
488 static int adjust_ret_addr(
unsigned long sp,
long correction)
511 static bool is_riprel_insn(
struct arch_uprobe *auprobe)
517 handle_riprel_post_xol(
struct arch_uprobe *auprobe,
struct pt_regs *regs,
long *correction)
519 if (is_riprel_insn(auprobe)) {
522 autask = &
current->utask->autask;
524 regs->ax = autask->saved_scratch_register;
526 regs->cx = autask->saved_scratch_register;
540 handle_riprel_post_xol(
struct arch_uprobe *auprobe,
struct pt_regs *regs,
long *correction)
590 struct uprobe_task *utask;
597 current->thread.trap_nr = utask->autask.saved_trap_nr;
598 correction = (
long)(utask->vaddr - utask->xol_vaddr);
599 handle_riprel_post_xol(auprobe, regs, &correction);
601 regs->ip += correction;
604 result = adjust_ret_addr(regs->
sp, correction);
614 int ret = NOTIFY_DONE;
617 if (regs && !user_mode_vm(regs))
645 struct uprobe_task *utask =
current->utask;
647 current->thread.trap_nr = utask->autask.saved_trap_nr;
648 handle_riprel_post_xol(auprobe, regs,
NULL);
649 instruction_pointer_set(regs, utask->vaddr);
661 if (auprobe->
insn[i] == 0x66)
664 if (auprobe->
insn[i] == 0x90)
674 bool ret = __skip_sstep(auprobe, regs);
697 bool trapped = (task->utask->
state == UTASK_SSTEP_TRAPPED);