FAILED: patch "[PATCH] fprobe: make fprobe_kprobe_handler recursion free" failed to apply to 6.3-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.3-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.3.y
git checkout FETCH_HEAD
git cherry-pick -x 3cc4e2c5fbae84e5033723fb7e350bc6c164e3a2
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023052246-hardness-spoiling-5f03@gregkh' --subject-prefix 'PATCH 6.3.y' HEAD^..
Possible dependencies:
3cc4e2c5fbae ("fprobe: make fprobe_kprobe_handler recursion free") 6049674b5720 ("tracing: fprobe: Initialize ret valiable to fix smatch error") 39d954200bf6 ("fprobe: Skip exit_handler if entry_handler returns !0") 7e7ef1bfe552 ("lib/test_fprobe: Add a test case for nr_maxactive") 34cabf8fd18f ("lib/test_fprobe: Add private entry_data testcases") 76d0de5729c0 ("fprobe: Pass entry_data to handlers")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 3cc4e2c5fbae84e5033723fb7e350bc6c164e3a2 Mon Sep 17 00:00:00 2001
From: Ze Gao <[email protected]>
Date: Wed, 17 May 2023 11:45:07 +0800
Subject: [PATCH] fprobe: make fprobe_kprobe_handler recursion free
Current implementation calls kprobe related functions before doing ftrace recursion check in fprobe_kprobe_handler, which opens door to kernel crash due to stack recursion if preempt_count_{add, sub} is traceable in kprobe_busy_{begin, end}.
Things goes like this without this patch quoted from Steven:
"fprobe_kprobe_handler() {
kprobe_busy_begin() {
preempt_disable() {
preempt_count_add() { <-- trace
fprobe_kprobe_handler() {
[ wash, rinse, repeat, CRASH!!! ]
"
By refactoring the common part out of fprobe_kprobe_handler and fprobe_handler and call ftrace recursion detection at the very beginning, the whole fprobe_kprobe_handler is free from recursion.
[ Fix the indentation of __fprobe_handler() parameters. ]
kernel/trace/fprobe.c +44 -15
@@ -20,30 +20,22 @@ struct fprobe_rethook_node {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 =0 ; +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;
@@ -61,23 +53,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,