@@ -132,26 +132,6 @@ void synthesize_relcall(void *dest, void *from, void *to)
132132}
133133NOKPROBE_SYMBOL (synthesize_relcall );
134134
135- /*
136- * Skip the prefixes of the instruction.
137- */
138- static kprobe_opcode_t * skip_prefixes (kprobe_opcode_t * insn )
139- {
140- insn_attr_t attr ;
141-
142- attr = inat_get_opcode_attribute ((insn_byte_t )* insn );
143- while (inat_is_legacy_prefix (attr )) {
144- insn ++ ;
145- attr = inat_get_opcode_attribute ((insn_byte_t )* insn );
146- }
147- #ifdef CONFIG_X86_64
148- if (inat_is_rex_prefix (attr ))
149- insn ++ ;
150- #endif
151- return insn ;
152- }
153- NOKPROBE_SYMBOL (skip_prefixes );
154-
155135/*
156136 * Returns non-zero if INSN is boostable.
157137 * RIP relative instructions are adjusted at copying time in 64 bits mode
@@ -311,25 +291,6 @@ static int can_probe(unsigned long paddr)
311291 return (addr == paddr );
312292}
313293
314- /*
315- * Returns non-zero if opcode modifies the interrupt flag.
316- */
317- static int is_IF_modifier (kprobe_opcode_t * insn )
318- {
319- /* Skip prefixes */
320- insn = skip_prefixes (insn );
321-
322- switch (* insn ) {
323- case 0xfa : /* cli */
324- case 0xfb : /* sti */
325- case 0xcf : /* iret/iretd */
326- case 0x9d : /* popf/popfd */
327- return 1 ;
328- }
329-
330- return 0 ;
331- }
332-
333294/*
334295 * Copy an instruction with recovering modified instruction by kprobes
335296 * and adjust the displacement if the instruction uses the %rip-relative
@@ -411,9 +372,9 @@ static int prepare_boost(kprobe_opcode_t *buf, struct kprobe *p,
411372 synthesize_reljump (buf + len , p -> ainsn .insn + len ,
412373 p -> addr + insn -> length );
413374 len += JMP32_INSN_SIZE ;
414- p -> ainsn .boostable = true ;
375+ p -> ainsn .boostable = 1 ;
415376 } else {
416- p -> ainsn .boostable = false ;
377+ p -> ainsn .boostable = 0 ;
417378 }
418379
419380 return len ;
@@ -450,6 +411,67 @@ void free_insn_page(void *page)
450411 module_memfree (page );
451412}
452413
414+ static void set_resume_flags (struct kprobe * p , struct insn * insn )
415+ {
416+ insn_byte_t opcode = insn -> opcode .bytes [0 ];
417+
418+ switch (opcode ) {
419+ case 0xfa : /* cli */
420+ case 0xfb : /* sti */
421+ case 0x9d : /* popf/popfd */
422+ /* Check whether the instruction modifies Interrupt Flag or not */
423+ p -> ainsn .if_modifier = 1 ;
424+ break ;
425+ case 0x9c : /* pushfl */
426+ p -> ainsn .is_pushf = 1 ;
427+ break ;
428+ case 0xcf : /* iret */
429+ p -> ainsn .if_modifier = 1 ;
430+ fallthrough ;
431+ case 0xc2 : /* ret/lret */
432+ case 0xc3 :
433+ case 0xca :
434+ case 0xcb :
435+ case 0xea : /* jmp absolute -- ip is correct */
436+ /* ip is already adjusted, no more changes required */
437+ p -> ainsn .is_abs_ip = 1 ;
438+ /* Without resume jump, this is boostable */
439+ p -> ainsn .boostable = 1 ;
440+ break ;
441+ case 0xe8 : /* call relative - Fix return addr */
442+ p -> ainsn .is_call = 1 ;
443+ break ;
444+ #ifdef CONFIG_X86_32
445+ case 0x9a : /* call absolute -- same as call absolute, indirect */
446+ p -> ainsn .is_call = 1 ;
447+ p -> ainsn .is_abs_ip = 1 ;
448+ break ;
449+ #endif
450+ case 0xff :
451+ opcode = insn -> opcode .bytes [1 ];
452+ if ((opcode & 0x30 ) == 0x10 ) {
453+ /*
454+ * call absolute, indirect
455+ * Fix return addr; ip is correct.
456+ * But this is not boostable
457+ */
458+ p -> ainsn .is_call = 1 ;
459+ p -> ainsn .is_abs_ip = 1 ;
460+ break ;
461+ } else if (((opcode & 0x31 ) == 0x20 ) ||
462+ ((opcode & 0x31 ) == 0x21 )) {
463+ /*
464+ * jmp near and far, absolute indirect
465+ * ip is correct.
466+ */
467+ p -> ainsn .is_abs_ip = 1 ;
468+ /* Without resume jump, this is boostable */
469+ p -> ainsn .boostable = 1 ;
470+ }
471+ break ;
472+ }
473+ }
474+
453475static int arch_copy_kprobe (struct kprobe * p )
454476{
455477 struct insn insn ;
@@ -467,8 +489,8 @@ static int arch_copy_kprobe(struct kprobe *p)
467489 */
468490 len = prepare_boost (buf , p , & insn );
469491
470- /* Check whether the instruction modifies Interrupt Flag or not */
471- p -> ainsn . if_modifier = is_IF_modifier ( buf );
492+ /* Analyze the opcode and set resume flags */
493+ set_resume_flags ( p , & insn );
472494
473495 /* Also, displacement change doesn't affect the first byte */
474496 p -> opcode = buf [0 ];
@@ -491,6 +513,9 @@ int arch_prepare_kprobe(struct kprobe *p)
491513
492514 if (!can_probe ((unsigned long )p -> addr ))
493515 return - EILSEQ ;
516+
517+ memset (& p -> ainsn , 0 , sizeof (p -> ainsn ));
518+
494519 /* insn: must be on special executable page on x86. */
495520 p -> ainsn .insn = get_insn_slot ();
496521 if (!p -> ainsn .insn )
@@ -806,72 +831,27 @@ NOKPROBE_SYMBOL(trampoline_handler);
806831 * 2) If the single-stepped instruction was a call, the return address
807832 * that is atop the stack is the address following the copied instruction.
808833 * We need to make it the address following the original instruction.
809- *
810- * If this is the first time we've single-stepped the instruction at
811- * this probepoint, and the instruction is boostable, boost it: add a
812- * jump instruction after the copied instruction, that jumps to the next
813- * instruction after the probepoint.
814834 */
815835static void resume_execution (struct kprobe * p , struct pt_regs * regs ,
816836 struct kprobe_ctlblk * kcb )
817837{
818838 unsigned long * tos = stack_addr (regs );
819839 unsigned long copy_ip = (unsigned long )p -> ainsn .insn ;
820840 unsigned long orig_ip = (unsigned long )p -> addr ;
821- kprobe_opcode_t * insn = p -> ainsn .insn ;
822-
823- /* Skip prefixes */
824- insn = skip_prefixes (insn );
825841
826842 regs -> flags &= ~X86_EFLAGS_TF ;
827- switch (* insn ) {
828- case 0x9c : /* pushfl */
843+
844+ /* Fixup the contents of top of stack */
845+ if (p -> ainsn .is_pushf ) {
829846 * tos &= ~(X86_EFLAGS_TF | X86_EFLAGS_IF );
830847 * tos |= kcb -> kprobe_old_flags ;
831- break ;
832- case 0xc2 : /* iret/ret/lret */
833- case 0xc3 :
834- case 0xca :
835- case 0xcb :
836- case 0xcf :
837- case 0xea : /* jmp absolute -- ip is correct */
838- /* ip is already adjusted, no more changes required */
839- p -> ainsn .boostable = true;
840- goto no_change ;
841- case 0xe8 : /* call relative - Fix return addr */
848+ } else if (p -> ainsn .is_call ) {
842849 * tos = orig_ip + (* tos - copy_ip );
843- break ;
844- #ifdef CONFIG_X86_32
845- case 0x9a : /* call absolute -- same as call absolute, indirect */
846- * tos = orig_ip + (* tos - copy_ip );
847- goto no_change ;
848- #endif
849- case 0xff :
850- if ((insn [1 ] & 0x30 ) == 0x10 ) {
851- /*
852- * call absolute, indirect
853- * Fix return addr; ip is correct.
854- * But this is not boostable
855- */
856- * tos = orig_ip + (* tos - copy_ip );
857- goto no_change ;
858- } else if (((insn [1 ] & 0x31 ) == 0x20 ) ||
859- ((insn [1 ] & 0x31 ) == 0x21 )) {
860- /*
861- * jmp near and far, absolute indirect
862- * ip is correct. And this is boostable
863- */
864- p -> ainsn .boostable = true;
865- goto no_change ;
866- }
867- break ;
868- default :
869- break ;
870850 }
871851
872- regs -> ip += orig_ip - copy_ip ;
852+ if (!p -> ainsn .is_abs_ip )
853+ regs -> ip += orig_ip - copy_ip ;
873854
874- no_change :
875855 restore_btf ();
876856}
877857NOKPROBE_SYMBOL (resume_execution );
0 commit comments