Commit 27527410 authored by Ze Gao's avatar Ze Gao Committed by Masami Hiramatsu (Google)

fprobe: add recursion detection in fprobe_exit_handler

fprobe_hander and fprobe_kprobe_handler has guarded ftrace recursion
detection but fprobe_exit_handler has not, which possibly introduce
recursive calls if the fprobe exit callback calls any traceable
functions. Checking in fprobe_hander or fprobe_kprobe_handler
is not enough and misses this case.

So add recursion free guard the same way as fprobe_hander. Since
ftrace recursion check does not employ ip(s), so here use entry_ip and
entry_parent_ip the same as fprobe_handler.

Link: https://lore.kernel.org/all/20230517034510.15639-4-zegao@tencent.com/

Fixes: 5b0ab789 ("fprobe: Add exit_handler support")
Signed-off-by: default avatarZe Gao <zegao@tencent.com>
Cc: stable@vger.kernel.org
Acked-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent 3cc4e2c5
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
struct fprobe_rethook_node { struct fprobe_rethook_node {
struct rethook_node node; struct rethook_node node;
unsigned long entry_ip; unsigned long entry_ip;
unsigned long entry_parent_ip;
char data[]; char data[];
}; };
...@@ -39,6 +40,7 @@ static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip, ...@@ -39,6 +40,7 @@ static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
} }
fpr = container_of(rh, struct fprobe_rethook_node, node); fpr = container_of(rh, struct fprobe_rethook_node, node);
fpr->entry_ip = ip; fpr->entry_ip = ip;
fpr->entry_parent_ip = parent_ip;
if (fp->entry_data_size) if (fp->entry_data_size)
entry_data = fpr->data; entry_data = fpr->data;
} }
...@@ -114,14 +116,26 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data, ...@@ -114,14 +116,26 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data,
{ {
struct fprobe *fp = (struct fprobe *)data; struct fprobe *fp = (struct fprobe *)data;
struct fprobe_rethook_node *fpr; struct fprobe_rethook_node *fpr;
int bit;
if (!fp || fprobe_disabled(fp)) if (!fp || fprobe_disabled(fp))
return; return;
fpr = container_of(rh, struct fprobe_rethook_node, node); 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->exit_handler(fp, fpr->entry_ip, regs,
fp->entry_data_size ? (void *)fpr->data : NULL); fp->entry_data_size ? (void *)fpr->data : NULL);
ftrace_test_recursion_unlock(bit);
} }
NOKPROBE_SYMBOL(fprobe_exit_handler); NOKPROBE_SYMBOL(fprobe_exit_handler);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment