|
@@ -112,7 +112,8 @@ struct kretprobe_blackpoint kretprobe_blacklist[] = {
|
|
|
|
|
|
const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
|
|
|
|
|
|
-static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op)
|
|
|
+static nokprobe_inline void
|
|
|
+__synthesize_relative_insn(void *from, void *to, u8 op)
|
|
|
{
|
|
|
struct __arch_relative_insn {
|
|
|
u8 op;
|
|
@@ -125,21 +126,23 @@ static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op)
|
|
|
}
|
|
|
|
|
|
/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
|
|
|
-void __kprobes synthesize_reljump(void *from, void *to)
|
|
|
+void synthesize_reljump(void *from, void *to)
|
|
|
{
|
|
|
__synthesize_relative_insn(from, to, RELATIVEJUMP_OPCODE);
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(synthesize_reljump);
|
|
|
|
|
|
/* Insert a call instruction at address 'from', which calls address 'to'.*/
|
|
|
-void __kprobes synthesize_relcall(void *from, void *to)
|
|
|
+void synthesize_relcall(void *from, void *to)
|
|
|
{
|
|
|
__synthesize_relative_insn(from, to, RELATIVECALL_OPCODE);
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(synthesize_relcall);
|
|
|
|
|
|
/*
|
|
|
* Skip the prefixes of the instruction.
|
|
|
*/
|
|
|
-static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn)
|
|
|
+static kprobe_opcode_t *skip_prefixes(kprobe_opcode_t *insn)
|
|
|
{
|
|
|
insn_attr_t attr;
|
|
|
|
|
@@ -154,6 +157,7 @@ static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn)
|
|
|
#endif
|
|
|
return insn;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(skip_prefixes);
|
|
|
|
|
|
/*
|
|
|
* Returns non-zero if opcode is boostable.
|
|
@@ -425,7 +429,8 @@ void arch_remove_kprobe(struct kprobe *p)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
+static nokprobe_inline void
|
|
|
+save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
{
|
|
|
kcb->prev_kprobe.kp = kprobe_running();
|
|
|
kcb->prev_kprobe.status = kcb->kprobe_status;
|
|
@@ -433,7 +438,8 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
kcb->prev_kprobe.saved_flags = kcb->kprobe_saved_flags;
|
|
|
}
|
|
|
|
|
|
-static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
+static nokprobe_inline void
|
|
|
+restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
{
|
|
|
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
|
|
|
kcb->kprobe_status = kcb->prev_kprobe.status;
|
|
@@ -441,8 +447,9 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
|
kcb->kprobe_saved_flags = kcb->prev_kprobe.saved_flags;
|
|
|
}
|
|
|
|
|
|
-static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|
|
- struct kprobe_ctlblk *kcb)
|
|
|
+static nokprobe_inline void
|
|
|
+set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|
|
+ struct kprobe_ctlblk *kcb)
|
|
|
{
|
|
|
__this_cpu_write(current_kprobe, p);
|
|
|
kcb->kprobe_saved_flags = kcb->kprobe_old_flags
|
|
@@ -451,7 +458,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|
|
kcb->kprobe_saved_flags &= ~X86_EFLAGS_IF;
|
|
|
}
|
|
|
|
|
|
-static void __kprobes clear_btf(void)
|
|
|
+static nokprobe_inline void clear_btf(void)
|
|
|
{
|
|
|
if (test_thread_flag(TIF_BLOCKSTEP)) {
|
|
|
unsigned long debugctl = get_debugctlmsr();
|
|
@@ -461,7 +468,7 @@ static void __kprobes clear_btf(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void __kprobes restore_btf(void)
|
|
|
+static nokprobe_inline void restore_btf(void)
|
|
|
{
|
|
|
if (test_thread_flag(TIF_BLOCKSTEP)) {
|
|
|
unsigned long debugctl = get_debugctlmsr();
|
|
@@ -471,8 +478,7 @@ static void __kprobes restore_btf(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void __kprobes
|
|
|
-arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
|
|
|
+void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
|
|
|
{
|
|
|
unsigned long *sara = stack_addr(regs);
|
|
|
|
|
@@ -481,9 +487,10 @@ arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
|
|
|
/* Replace the return addr with trampoline addr */
|
|
|
*sara = (unsigned long) &kretprobe_trampoline;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(arch_prepare_kretprobe);
|
|
|
|
|
|
-static void __kprobes
|
|
|
-setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, int reenter)
|
|
|
+static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
|
|
|
+ struct kprobe_ctlblk *kcb, int reenter)
|
|
|
{
|
|
|
if (setup_detour_execution(p, regs, reenter))
|
|
|
return;
|
|
@@ -519,14 +526,15 @@ setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *k
|
|
|
else
|
|
|
regs->ip = (unsigned long)p->ainsn.insn;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(setup_singlestep);
|
|
|
|
|
|
/*
|
|
|
* We have reentered the kprobe_handler(), since another probe was hit while
|
|
|
* within the handler. We save the original kprobes variables and just single
|
|
|
* step on the instruction of the new probe without calling any user handlers.
|
|
|
*/
|
|
|
-static int __kprobes
|
|
|
-reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
|
|
|
+static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|
|
+ struct kprobe_ctlblk *kcb)
|
|
|
{
|
|
|
switch (kcb->kprobe_status) {
|
|
|
case KPROBE_HIT_SSDONE:
|
|
@@ -554,12 +562,13 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(reenter_kprobe);
|
|
|
|
|
|
/*
|
|
|
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
|
|
|
* remain disabled throughout this function.
|
|
|
*/
|
|
|
-int __kprobes kprobe_int3_handler(struct pt_regs *regs)
|
|
|
+int kprobe_int3_handler(struct pt_regs *regs)
|
|
|
{
|
|
|
kprobe_opcode_t *addr;
|
|
|
struct kprobe *p;
|
|
@@ -622,12 +631,13 @@ int __kprobes kprobe_int3_handler(struct pt_regs *regs)
|
|
|
preempt_enable_no_resched();
|
|
|
return 0;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(kprobe_int3_handler);
|
|
|
|
|
|
/*
|
|
|
* When a retprobed function returns, this code saves registers and
|
|
|
* calls trampoline_handler() runs, which calls the kretprobe's handler.
|
|
|
*/
|
|
|
-static void __used __kprobes kretprobe_trampoline_holder(void)
|
|
|
+static void __used kretprobe_trampoline_holder(void)
|
|
|
{
|
|
|
asm volatile (
|
|
|
".global kretprobe_trampoline\n"
|
|
@@ -658,11 +668,13 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
|
|
|
#endif
|
|
|
" ret\n");
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(kretprobe_trampoline_holder);
|
|
|
+NOKPROBE_SYMBOL(kretprobe_trampoline);
|
|
|
|
|
|
/*
|
|
|
* Called from kretprobe_trampoline
|
|
|
*/
|
|
|
-__visible __used __kprobes void *trampoline_handler(struct pt_regs *regs)
|
|
|
+__visible __used void *trampoline_handler(struct pt_regs *regs)
|
|
|
{
|
|
|
struct kretprobe_instance *ri = NULL;
|
|
|
struct hlist_head *head, empty_rp;
|
|
@@ -748,6 +760,7 @@ __visible __used __kprobes void *trampoline_handler(struct pt_regs *regs)
|
|
|
}
|
|
|
return (void *)orig_ret_address;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(trampoline_handler);
|
|
|
|
|
|
/*
|
|
|
* Called after single-stepping. p->addr is the address of the
|
|
@@ -776,8 +789,8 @@ __visible __used __kprobes void *trampoline_handler(struct pt_regs *regs)
|
|
|
* jump instruction after the copied instruction, that jumps to the next
|
|
|
* instruction after the probepoint.
|
|
|
*/
|
|
|
-static void __kprobes
|
|
|
-resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
|
|
|
+static void resume_execution(struct kprobe *p, struct pt_regs *regs,
|
|
|
+ struct kprobe_ctlblk *kcb)
|
|
|
{
|
|
|
unsigned long *tos = stack_addr(regs);
|
|
|
unsigned long copy_ip = (unsigned long)p->ainsn.insn;
|
|
@@ -852,12 +865,13 @@ resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *k
|
|
|
no_change:
|
|
|
restore_btf();
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(resume_execution);
|
|
|
|
|
|
/*
|
|
|
* Interrupts are disabled on entry as trap1 is an interrupt gate and they
|
|
|
* remain disabled throughout this function.
|
|
|
*/
|
|
|
-int __kprobes kprobe_debug_handler(struct pt_regs *regs)
|
|
|
+int kprobe_debug_handler(struct pt_regs *regs)
|
|
|
{
|
|
|
struct kprobe *cur = kprobe_running();
|
|
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
|
@@ -892,8 +906,9 @@ out:
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(kprobe_debug_handler);
|
|
|
|
|
|
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
{
|
|
|
struct kprobe *cur = kprobe_running();
|
|
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
|
@@ -950,12 +965,13 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(kprobe_fault_handler);
|
|
|
|
|
|
/*
|
|
|
* Wrapper routine for handling exceptions.
|
|
|
*/
|
|
|
-int __kprobes
|
|
|
-kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data)
|
|
|
+int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
|
|
|
+ void *data)
|
|
|
{
|
|
|
struct die_args *args = data;
|
|
|
int ret = NOTIFY_DONE;
|
|
@@ -975,8 +991,9 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(kprobe_exceptions_notify);
|
|
|
|
|
|
-int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
+int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
{
|
|
|
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
|
|
unsigned long addr;
|
|
@@ -1000,8 +1017,9 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
regs->ip = (unsigned long)(jp->entry);
|
|
|
return 1;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(setjmp_pre_handler);
|
|
|
|
|
|
-void __kprobes jprobe_return(void)
|
|
|
+void jprobe_return(void)
|
|
|
{
|
|
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
|
|
|
|
@@ -1017,8 +1035,10 @@ void __kprobes jprobe_return(void)
|
|
|
" nop \n"::"b"
|
|
|
(kcb->jprobe_saved_sp):"memory");
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(jprobe_return);
|
|
|
+NOKPROBE_SYMBOL(jprobe_return_end);
|
|
|
|
|
|
-int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
{
|
|
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
|
|
u8 *addr = (u8 *) (regs->ip - 1);
|
|
@@ -1046,6 +1066,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+NOKPROBE_SYMBOL(longjmp_break_handler);
|
|
|
|
|
|
bool arch_within_kprobe_blacklist(unsigned long addr)
|
|
|
{
|