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

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
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
struct fprobe_rethook_node {
	struct rethook_node node;
	unsigned long entry_ip;
	unsigned long entry_parent_ip;
	char data[];
};

@@ -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->entry_ip = ip;
		fpr->entry_parent_ip = parent_ip;
		if (fp->entry_data_size)
			entry_data = fpr->data;
	}
@@ -114,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);