|
@@ -223,27 +223,48 @@ static unsigned long
|
|
|
__recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
|
|
|
{
|
|
|
struct kprobe *kp;
|
|
|
+ unsigned long faddr;
|
|
|
|
|
|
kp = get_kprobe((void *)addr);
|
|
|
- /* There is no probe, return original address */
|
|
|
- if (!kp)
|
|
|
+ faddr = ftrace_location(addr);
|
|
|
+ /*
|
|
|
+ * Addresses inside the ftrace location are refused by
|
|
|
+ * arch_check_ftrace_location(). Something went terribly wrong
|
|
|
+ * if such an address is checked here.
|
|
|
+ */
|
|
|
+ if (WARN_ON(faddr && faddr != addr))
|
|
|
+ return 0UL;
|
|
|
+ /*
|
|
|
+ * Use the current code if it is not modified by Kprobe
|
|
|
+ * and it cannot be modified by ftrace.
|
|
|
+ */
|
|
|
+ if (!kp && !faddr)
|
|
|
return addr;
|
|
|
|
|
|
/*
|
|
|
- * Basically, kp->ainsn.insn has an original instruction.
|
|
|
- * However, RIP-relative instruction can not do single-stepping
|
|
|
- * at different place, __copy_instruction() tweaks the displacement of
|
|
|
- * that instruction. In that case, we can't recover the instruction
|
|
|
- * from the kp->ainsn.insn.
|
|
|
+ * Basically, kp->ainsn.insn has an original instruction.
|
|
|
+ * However, RIP-relative instruction can not do single-stepping
|
|
|
+ * at different place, __copy_instruction() tweaks the displacement of
|
|
|
+ * that instruction. In that case, we can't recover the instruction
|
|
|
+ * from the kp->ainsn.insn.
|
|
|
*
|
|
|
- * On the other hand, kp->opcode has a copy of the first byte of
|
|
|
- * the probed instruction, which is overwritten by int3. And
|
|
|
- * the instruction at kp->addr is not modified by kprobes except
|
|
|
- * for the first byte, we can recover the original instruction
|
|
|
- * from it and kp->opcode.
|
|
|
+ * On the other hand, in case on normal Kprobe, kp->opcode has a copy
|
|
|
+ * of the first byte of the probed instruction, which is overwritten
|
|
|
+ * by int3. And the instruction at kp->addr is not modified by kprobes
|
|
|
+ * except for the first byte, we can recover the original instruction
|
|
|
+ * from it and kp->opcode.
|
|
|
+ *
|
|
|
+ * In case of Kprobes using ftrace, we do not have a copy of
|
|
|
+ * the original instruction. In fact, the ftrace location might
|
|
|
+ * be modified at anytime and even could be in an inconsistent state.
|
|
|
+ * Fortunately, we know that the original code is the ideal 5-byte
|
|
|
+ * long NOP.
|
|
|
*/
|
|
|
- memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
|
|
|
- buf[0] = kp->opcode;
|
|
|
+ memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
|
|
|
+ if (faddr)
|
|
|
+ memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
|
|
|
+ else
|
|
|
+ buf[0] = kp->opcode;
|
|
|
return (unsigned long)buf;
|
|
|
}
|
|
|
|
|
@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
|
|
|
* Recover the probed instruction at addr for further analysis.
|
|
|
* Caller must lock kprobes by kprobe_mutex, or disable preemption
|
|
|
* for preventing to release referencing kprobes.
|
|
|
+ * Returns zero if the instruction can not get recovered.
|
|
|
*/
|
|
|
unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
|
|
|
{
|
|
@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
|
|
|
* normally used, we just go through if there is no kprobe.
|
|
|
*/
|
|
|
__addr = recover_probed_instruction(buf, addr);
|
|
|
+ if (!__addr)
|
|
|
+ return 0;
|
|
|
kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
|
|
|
insn_get_length(&insn);
|
|
|
|
|
@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
|
|
|
unsigned long recovered_insn =
|
|
|
recover_probed_instruction(buf, (unsigned long)src);
|
|
|
|
|
|
+ if (!recovered_insn)
|
|
|
+ return 0;
|
|
|
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
|
|
|
insn_get_length(&insn);
|
|
|
/* Another subsystem puts a breakpoint, failed to recover */
|