Probes fixes for 6.4-rc1:
- Initialize 'ret' local variables on fprobe_handler() to fix the smatch warning. With this, fprobe function exit handler is not working randomly. - Fix to use preempt_enable/disable_notrace for rethook handler to prevent recursive call of fprobe exit handler (which is based on rethook) - Fix recursive call issue on fprobe_kprobe_handler(). - Fix to detect recursive call on fprobe_exit_handler(). - Fix to make all arch-dependent rethook code notrace. (the arch-independent code is already notrace) -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEh7BulGwFlgAOi5DV2/sHvwUrPxsFAmRmKgQACgkQ2/sHvwUr PxvlCgf+OJk5O9IJlTgqDV6JNPsTzFS7qqyAyQmZW9Bj8STfWAIRxa0zeGbZE58K 5LwgzAj+SqzYRwIvzzZ3xsA5j7f1Wj7wG0TQgmpnIW+hprwDrLsUhoZ5s1D/Ojel A4rAnqCrgnh5m5SenU2QCUngGKn004j4RASaZvRELDyvyIkBSqNhswCH8ZWGPror KuCu5AmEnFagYl0lmNL3H2aCITAg3QEK+fE6iR+lYsqfR3xbs4YAcqiylHBdY0wX ssK7LVdRmv7O6TxSj4P2ohDvLJP3eL9bVirsJpg0OVbqWJCs65T2rJJjXiKojYXf vSVWFJFK5oV98ZHfXTG9R7x0DEwc+g== =jO68 -----END PGP SIGNATURE----- Merge tag 'probes-fixes-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull probes fixes from Masami Hiramatsu: - Initialize 'ret' local variables on fprobe_handler() to fix the smatch warning. With this, fprobe function exit handler is not working randomly. - Fix to use preempt_enable/disable_notrace for rethook handler to prevent recursive call of fprobe exit handler (which is based on rethook) - Fix recursive call issue on fprobe_kprobe_handler() - Fix to detect recursive call on fprobe_exit_handler() - Fix to make all arch-dependent rethook code notrace (the arch-independent code is already notrace)" * tag 'probes-fixes-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: rethook, fprobe: do not trace rethook related functions fprobe: add recursion detection in fprobe_exit_handler fprobe: make fprobe_kprobe_handler recursion free rethook: use preempt_{disable, enable}_notrace in rethook_trampoline_handler tracing: fprobe: Initialize ret valiable to fix smatch error
This commit is contained in:
commit
2d1bcbc6cd
@ -4,3 +4,5 @@ obj-$(CONFIG_RETHOOK) += rethook.o rethook_trampoline.o
|
||||
obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o
|
||||
CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_rethook.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_rethook_trampoline.o = $(CC_FLAGS_FTRACE)
|
||||
|
@ -10,6 +10,7 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
|
||||
|
||||
# Do not trace early setup code
|
||||
CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_rethook.o = $(CC_FLAGS_FTRACE)
|
||||
|
||||
endif
|
||||
|
||||
|
@ -17,6 +17,7 @@ CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_early_printk.o = -pg
|
||||
CFLAGS_REMOVE_head64.o = -pg
|
||||
CFLAGS_REMOVE_sev.o = -pg
|
||||
CFLAGS_REMOVE_rethook.o = -pg
|
||||
endif
|
||||
|
||||
KASAN_SANITIZE_head$(BITS).o := n
|
||||
|
@ -17,36 +17,30 @@
|
||||
struct fprobe_rethook_node {
|
||||
struct rethook_node node;
|
||||
unsigned long entry_ip;
|
||||
unsigned long entry_parent_ip;
|
||||
char data[];
|
||||
};
|
||||
|
||||
static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *ops, struct ftrace_regs *fregs)
|
||||
static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *ops, struct ftrace_regs *fregs)
|
||||
{
|
||||
struct fprobe_rethook_node *fpr;
|
||||
struct rethook_node *rh = NULL;
|
||||
struct fprobe *fp;
|
||||
void *entry_data = NULL;
|
||||
int bit, ret;
|
||||
int ret = 0;
|
||||
|
||||
fp = container_of(ops, struct fprobe, ops);
|
||||
if (fprobe_disabled(fp))
|
||||
return;
|
||||
|
||||
bit = ftrace_test_recursion_trylock(ip, parent_ip);
|
||||
if (bit < 0) {
|
||||
fp->nmissed++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp->exit_handler) {
|
||||
rh = rethook_try_get(fp->rethook);
|
||||
if (!rh) {
|
||||
fp->nmissed++;
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
fpr = container_of(rh, struct fprobe_rethook_node, node);
|
||||
fpr->entry_ip = ip;
|
||||
fpr->entry_parent_ip = parent_ip;
|
||||
if (fp->entry_data_size)
|
||||
entry_data = fpr->data;
|
||||
}
|
||||
@ -61,23 +55,60 @@ static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||
else
|
||||
rethook_hook(rh, ftrace_get_regs(fregs), true);
|
||||
}
|
||||
out:
|
||||
}
|
||||
|
||||
static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *ops, struct ftrace_regs *fregs)
|
||||
{
|
||||
struct fprobe *fp;
|
||||
int bit;
|
||||
|
||||
fp = container_of(ops, struct fprobe, ops);
|
||||
if (fprobe_disabled(fp))
|
||||
return;
|
||||
|
||||
/* recursion detection has to go before any traceable function and
|
||||
* all functions before this point should be marked as notrace
|
||||
*/
|
||||
bit = ftrace_test_recursion_trylock(ip, parent_ip);
|
||||
if (bit < 0) {
|
||||
fp->nmissed++;
|
||||
return;
|
||||
}
|
||||
__fprobe_handler(ip, parent_ip, ops, fregs);
|
||||
ftrace_test_recursion_unlock(bit);
|
||||
|
||||
}
|
||||
NOKPROBE_SYMBOL(fprobe_handler);
|
||||
|
||||
static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *ops, struct ftrace_regs *fregs)
|
||||
{
|
||||
struct fprobe *fp = container_of(ops, struct fprobe, ops);
|
||||
struct fprobe *fp;
|
||||
int bit;
|
||||
|
||||
fp = container_of(ops, struct fprobe, ops);
|
||||
if (fprobe_disabled(fp))
|
||||
return;
|
||||
|
||||
/* recursion detection has to go before any traceable function and
|
||||
* all functions called before this point should be marked as notrace
|
||||
*/
|
||||
bit = ftrace_test_recursion_trylock(ip, parent_ip);
|
||||
if (bit < 0) {
|
||||
fp->nmissed++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(kprobe_running())) {
|
||||
fp->nmissed++;
|
||||
return;
|
||||
}
|
||||
|
||||
kprobe_busy_begin();
|
||||
fprobe_handler(ip, parent_ip, ops, fregs);
|
||||
__fprobe_handler(ip, parent_ip, ops, fregs);
|
||||
kprobe_busy_end();
|
||||
ftrace_test_recursion_unlock(bit);
|
||||
}
|
||||
|
||||
static void fprobe_exit_handler(struct rethook_node *rh, void *data,
|
||||
@ -85,14 +116,26 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data,
|
||||
{
|
||||
struct fprobe *fp = (struct fprobe *)data;
|
||||
struct fprobe_rethook_node *fpr;
|
||||
int bit;
|
||||
|
||||
if (!fp || fprobe_disabled(fp))
|
||||
return;
|
||||
|
||||
fpr = container_of(rh, struct fprobe_rethook_node, node);
|
||||
|
||||
/*
|
||||
* we need to assure no calls to traceable functions in-between the
|
||||
* end of fprobe_handler and the beginning of fprobe_exit_handler.
|
||||
*/
|
||||
bit = ftrace_test_recursion_trylock(fpr->entry_ip, fpr->entry_parent_ip);
|
||||
if (bit < 0) {
|
||||
fp->nmissed++;
|
||||
return;
|
||||
}
|
||||
|
||||
fp->exit_handler(fp, fpr->entry_ip, regs,
|
||||
fp->entry_data_size ? (void *)fpr->data : NULL);
|
||||
ftrace_test_recursion_unlock(bit);
|
||||
}
|
||||
NOKPROBE_SYMBOL(fprobe_exit_handler);
|
||||
|
||||
|
@ -288,7 +288,7 @@ unsigned long rethook_trampoline_handler(struct pt_regs *regs,
|
||||
* These loops must be protected from rethook_free_rcu() because those
|
||||
* are accessing 'rhn->rethook'.
|
||||
*/
|
||||
preempt_disable();
|
||||
preempt_disable_notrace();
|
||||
|
||||
/*
|
||||
* Run the handler on the shadow stack. Do not unlink the list here because
|
||||
@ -321,7 +321,7 @@ unsigned long rethook_trampoline_handler(struct pt_regs *regs,
|
||||
first = first->next;
|
||||
rethook_recycle(rhn);
|
||||
}
|
||||
preempt_enable();
|
||||
preempt_enable_notrace();
|
||||
|
||||
return correct_ret_addr;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user