diff options
| -rw-r--r-- | arch/x86/include/asm/uprobes.h | 12 | ||||
| -rw-r--r-- | arch/x86/kernel/uprobes.c | 43 |
2 files changed, 28 insertions, 27 deletions
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 93bee7b93854..72caff7afbde 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
| @@ -41,18 +41,20 @@ struct arch_uprobe { | |||
| 41 | u8 ixol[MAX_UINSN_BYTES]; | 41 | u8 ixol[MAX_UINSN_BYTES]; |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | u16 fixups; | ||
| 45 | const struct uprobe_xol_ops *ops; | 44 | const struct uprobe_xol_ops *ops; |
| 46 | 45 | ||
| 47 | union { | 46 | union { |
| 48 | #ifdef CONFIG_X86_64 | ||
| 49 | unsigned long rip_rela_target_address; | ||
| 50 | #endif | ||
| 51 | struct { | 47 | struct { |
| 52 | s32 offs; | 48 | s32 offs; |
| 53 | u8 ilen; | 49 | u8 ilen; |
| 54 | u8 opc1; | 50 | u8 opc1; |
| 55 | } branch; | 51 | } branch; |
| 52 | struct { | ||
| 53 | #ifdef CONFIG_X86_64 | ||
| 54 | long riprel_target; | ||
| 55 | #endif | ||
| 56 | u16 fixups; | ||
| 57 | } def; | ||
| 56 | }; | 58 | }; |
| 57 | }; | 59 | }; |
| 58 | 60 | ||
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index b2bca293fc57..7824ce248f8f 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
| @@ -251,10 +251,9 @@ static inline bool is_64bit_mm(struct mm_struct *mm) | |||
| 251 | * If arch_uprobe->insn doesn't use rip-relative addressing, return | 251 | * If arch_uprobe->insn doesn't use rip-relative addressing, return |
| 252 | * immediately. Otherwise, rewrite the instruction so that it accesses | 252 | * immediately. Otherwise, rewrite the instruction so that it accesses |
| 253 | * its memory operand indirectly through a scratch register. Set | 253 | * its memory operand indirectly through a scratch register. Set |
| 254 | * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address | 254 | * def->fixups and def->riprel_target accordingly. (The contents of the |
| 255 | * accordingly. (The contents of the scratch register will be saved | 255 | * scratch register will be saved before we single-step the modified |
| 256 | * before we single-step the modified instruction, and restored | 256 | * instruction, and restored afterward). |
| 257 | * afterward.) | ||
| 258 | * | 257 | * |
| 259 | * We do this because a rip-relative instruction can access only a | 258 | * We do this because a rip-relative instruction can access only a |
| 260 | * relatively small area (+/- 2 GB from the instruction), and the XOL | 259 | * relatively small area (+/- 2 GB from the instruction), and the XOL |
| @@ -308,18 +307,18 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct insn *insn) | |||
| 308 | * is NOT the register operand, so we use %rcx (register | 307 | * is NOT the register operand, so we use %rcx (register |
| 309 | * #1) for the scratch register. | 308 | * #1) for the scratch register. |
| 310 | */ | 309 | */ |
| 311 | auprobe->fixups = UPROBE_FIX_RIP_CX; | 310 | auprobe->def.fixups = UPROBE_FIX_RIP_CX; |
| 312 | /* Change modrm from 00 000 101 to 00 000 001. */ | 311 | /* Change modrm from 00 000 101 to 00 000 001. */ |
| 313 | *cursor = 0x1; | 312 | *cursor = 0x1; |
| 314 | } else { | 313 | } else { |
| 315 | /* Use %rax (register #0) for the scratch register. */ | 314 | /* Use %rax (register #0) for the scratch register. */ |
| 316 | auprobe->fixups = UPROBE_FIX_RIP_AX; | 315 | auprobe->def.fixups = UPROBE_FIX_RIP_AX; |
| 317 | /* Change modrm from 00 xxx 101 to 00 xxx 000 */ | 316 | /* Change modrm from 00 xxx 101 to 00 xxx 000 */ |
| 318 | *cursor = (reg << 3); | 317 | *cursor = (reg << 3); |
| 319 | } | 318 | } |
| 320 | 319 | ||
| 321 | /* Target address = address of next instruction + (signed) offset */ | 320 | /* Target address = address of next instruction + (signed) offset */ |
| 322 | auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value; | 321 | auprobe->def.riprel_target = (long)insn->length + insn->displacement.value; |
| 323 | 322 | ||
| 324 | /* Displacement field is gone; slide immediate field (if any) over. */ | 323 | /* Displacement field is gone; slide immediate field (if any) over. */ |
| 325 | if (insn->immediate.nbytes) { | 324 | if (insn->immediate.nbytes) { |
| @@ -336,25 +335,25 @@ static void | |||
| 336 | pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, | 335 | pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, |
| 337 | struct arch_uprobe_task *autask) | 336 | struct arch_uprobe_task *autask) |
| 338 | { | 337 | { |
| 339 | if (auprobe->fixups & UPROBE_FIX_RIP_AX) { | 338 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) { |
| 340 | autask->saved_scratch_register = regs->ax; | 339 | autask->saved_scratch_register = regs->ax; |
| 341 | regs->ax = current->utask->vaddr; | 340 | regs->ax = current->utask->vaddr; |
| 342 | regs->ax += auprobe->rip_rela_target_address; | 341 | regs->ax += auprobe->def.riprel_target; |
| 343 | } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { | 342 | } else if (auprobe->def.fixups & UPROBE_FIX_RIP_CX) { |
| 344 | autask->saved_scratch_register = regs->cx; | 343 | autask->saved_scratch_register = regs->cx; |
| 345 | regs->cx = current->utask->vaddr; | 344 | regs->cx = current->utask->vaddr; |
| 346 | regs->cx += auprobe->rip_rela_target_address; | 345 | regs->cx += auprobe->def.riprel_target; |
| 347 | } | 346 | } |
| 348 | } | 347 | } |
| 349 | 348 | ||
| 350 | static void | 349 | static void |
| 351 | handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) | 350 | handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) |
| 352 | { | 351 | { |
| 353 | if (auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { | 352 | if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { |
| 354 | struct arch_uprobe_task *autask; | 353 | struct arch_uprobe_task *autask; |
| 355 | 354 | ||
| 356 | autask = ¤t->utask->autask; | 355 | autask = ¤t->utask->autask; |
| 357 | if (auprobe->fixups & UPROBE_FIX_RIP_AX) | 356 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) |
| 358 | regs->ax = autask->saved_scratch_register; | 357 | regs->ax = autask->saved_scratch_register; |
| 359 | else | 358 | else |
| 360 | regs->cx = autask->saved_scratch_register; | 359 | regs->cx = autask->saved_scratch_register; |
| @@ -432,17 +431,17 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs | |||
| 432 | long correction = (long)(utask->vaddr - utask->xol_vaddr); | 431 | long correction = (long)(utask->vaddr - utask->xol_vaddr); |
| 433 | 432 | ||
| 434 | handle_riprel_post_xol(auprobe, regs, &correction); | 433 | handle_riprel_post_xol(auprobe, regs, &correction); |
| 435 | if (auprobe->fixups & UPROBE_FIX_IP) | 434 | if (auprobe->def.fixups & UPROBE_FIX_IP) |
| 436 | regs->ip += correction; | 435 | regs->ip += correction; |
| 437 | 436 | ||
| 438 | if (auprobe->fixups & UPROBE_FIX_CALL) { | 437 | if (auprobe->def.fixups & UPROBE_FIX_CALL) { |
| 439 | if (adjust_ret_addr(regs->sp, correction)) { | 438 | if (adjust_ret_addr(regs->sp, correction)) { |
| 440 | regs->sp += sizeof_long(); | 439 | regs->sp += sizeof_long(); |
| 441 | return -ERESTART; | 440 | return -ERESTART; |
| 442 | } | 441 | } |
| 443 | } | 442 | } |
| 444 | /* popf; tell the caller to not touch TF */ | 443 | /* popf; tell the caller to not touch TF */ |
| 445 | if (auprobe->fixups & UPROBE_FIX_SETF) | 444 | if (auprobe->def.fixups & UPROBE_FIX_SETF) |
| 446 | utask->autask.saved_tf = true; | 445 | utask->autask.saved_tf = true; |
| 447 | 446 | ||
| 448 | return 0; | 447 | return 0; |
| @@ -646,13 +645,13 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
| 646 | return ret; | 645 | return ret; |
| 647 | 646 | ||
| 648 | /* | 647 | /* |
| 649 | * Figure out which fixups arch_uprobe_post_xol() will need to perform, | 648 | * Figure out which fixups default_post_xol_op() will need to perform, |
| 650 | * and annotate arch_uprobe->fixups accordingly. To start with, ->fixups | 649 | * and annotate def->fixups accordingly. To start with, ->fixups is |
| 651 | * is either zero or it reflects rip-related fixups. | 650 | * either zero or it reflects rip-related fixups. |
| 652 | */ | 651 | */ |
| 653 | switch (OPCODE1(&insn)) { | 652 | switch (OPCODE1(&insn)) { |
| 654 | case 0x9d: /* popf */ | 653 | case 0x9d: /* popf */ |
| 655 | auprobe->fixups |= UPROBE_FIX_SETF; | 654 | auprobe->def.fixups |= UPROBE_FIX_SETF; |
| 656 | break; | 655 | break; |
| 657 | case 0xc3: /* ret or lret -- ip is correct */ | 656 | case 0xc3: /* ret or lret -- ip is correct */ |
| 658 | case 0xcb: | 657 | case 0xcb: |
| @@ -680,9 +679,9 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
| 680 | } | 679 | } |
| 681 | 680 | ||
| 682 | if (fix_ip) | 681 | if (fix_ip) |
| 683 | auprobe->fixups |= UPROBE_FIX_IP; | 682 | auprobe->def.fixups |= UPROBE_FIX_IP; |
| 684 | if (fix_call) | 683 | if (fix_call) |
| 685 | auprobe->fixups |= UPROBE_FIX_CALL; | 684 | auprobe->def.fixups |= UPROBE_FIX_CALL; |
| 686 | 685 | ||
| 687 | auprobe->ops = &default_xol_ops; | 686 | auprobe->ops = &default_xol_ops; |
| 688 | return 0; | 687 | return 0; |
