|
@@ -1405,10 +1405,16 @@ int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Replace a breakpoint (int3) with a relative jump. */
|
|
|
-int __kprobes arch_optimize_kprobe(struct optimized_kprobe *op)
|
|
|
+#define MAX_OPTIMIZE_PROBES 256
|
|
|
+static struct text_poke_param *jump_poke_params;
|
|
|
+static struct jump_poke_buffer {
|
|
|
+ u8 buf[RELATIVEJUMP_SIZE];
|
|
|
+} *jump_poke_bufs;
|
|
|
+
|
|
|
+static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm,
|
|
|
+ u8 *insn_buf,
|
|
|
+ struct optimized_kprobe *op)
|
|
|
{
|
|
|
- unsigned char jmp_code[RELATIVEJUMP_SIZE];
|
|
|
s32 rel = (s32)((long)op->optinsn.insn -
|
|
|
((long)op->kp.addr + RELATIVEJUMP_SIZE));
|
|
|
|
|
@@ -1416,16 +1422,39 @@ int __kprobes arch_optimize_kprobe(struct optimized_kprobe *op)
|
|
|
memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
|
|
|
RELATIVE_ADDR_SIZE);
|
|
|
|
|
|
- jmp_code[0] = RELATIVEJUMP_OPCODE;
|
|
|
- *(s32 *)(&jmp_code[1]) = rel;
|
|
|
+ insn_buf[0] = RELATIVEJUMP_OPCODE;
|
|
|
+ *(s32 *)(&insn_buf[1]) = rel;
|
|
|
+
|
|
|
+ tprm->addr = op->kp.addr;
|
|
|
+ tprm->opcode = insn_buf;
|
|
|
+ tprm->len = RELATIVEJUMP_SIZE;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Replace breakpoints (int3) with relative jumps.
|
|
|
+ * Caller must call with locking kprobe_mutex and text_mutex.
|
|
|
+ */
|
|
|
+void __kprobes arch_optimize_kprobes(struct list_head *oplist)
|
|
|
+{
|
|
|
+ struct optimized_kprobe *op, *tmp;
|
|
|
+ int c = 0;
|
|
|
+
|
|
|
+ list_for_each_entry_safe(op, tmp, oplist, list) {
|
|
|
+ WARN_ON(kprobe_disabled(&op->kp));
|
|
|
+ /* Setup param */
|
|
|
+ setup_optimize_kprobe(&jump_poke_params[c],
|
|
|
+ jump_poke_bufs[c].buf, op);
|
|
|
+ list_del_init(&op->list);
|
|
|
+ if (++c >= MAX_OPTIMIZE_PROBES)
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* text_poke_smp doesn't support NMI/MCE code modifying.
|
|
|
* However, since kprobes itself also doesn't support NMI/MCE
|
|
|
* code probing, it's not a problem.
|
|
|
*/
|
|
|
- text_poke_smp(op->kp.addr, jmp_code, RELATIVEJUMP_SIZE);
|
|
|
- return 0;
|
|
|
+ text_poke_smp_batch(jump_poke_params, c);
|
|
|
}
|
|
|
|
|
|
/* Replace a relative jump with a breakpoint (int3). */
|
|
@@ -1457,11 +1486,35 @@ static int __kprobes setup_detour_execution(struct kprobe *p,
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+static int __kprobes init_poke_params(void)
|
|
|
+{
|
|
|
+ /* Allocate code buffer and parameter array */
|
|
|
+ jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) *
|
|
|
+ MAX_OPTIMIZE_PROBES, GFP_KERNEL);
|
|
|
+ if (!jump_poke_bufs)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ jump_poke_params = kmalloc(sizeof(struct text_poke_param) *
|
|
|
+ MAX_OPTIMIZE_PROBES, GFP_KERNEL);
|
|
|
+ if (!jump_poke_params) {
|
|
|
+ kfree(jump_poke_bufs);
|
|
|
+ jump_poke_bufs = NULL;
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#else /* !CONFIG_OPTPROBES */
|
|
|
+static int __kprobes init_poke_params(void)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
#endif
|
|
|
|
|
|
int __init arch_init_kprobes(void)
|
|
|
{
|
|
|
- return 0;
|
|
|
+ return init_poke_params();
|
|
|
}
|
|
|
|
|
|
int __kprobes arch_trampoline_kprobe(struct kprobe *p)
|