Miroslav Franc eb129d
From: Vasily Gorbik <gor@linux.ibm.com>
Miroslav Franc eb129d
Date: Wed, 1 Mar 2023 17:58:06 +0100
Miroslav Franc eb129d
Subject: s390/kprobes: fix current_kprobe never cleared after kprobes reenter
Miroslav Franc eb129d
Git-commit: cd57953936f2213dfaccce10d20f396956222c7d
Miroslav Franc eb129d
Patch-mainline: v6.3-rc1
Miroslav Franc eb129d
References: git-fixes bsc#1211688
Miroslav Franc eb129d
Miroslav Franc eb129d
Recent test_kprobe_missed kprobes kunit test uncovers the following
Miroslav Franc eb129d
problem. Once kprobe is triggered from another kprobe (kprobe reenter),
Miroslav Franc eb129d
all future kprobes on this cpu are considered as kprobe reenter, thus
Miroslav Franc eb129d
pre_handler and post_handler are not being called and kprobes are counted
Miroslav Franc eb129d
as "missed".
Miroslav Franc eb129d
Miroslav Franc eb129d
Commit b9599798f953 ("[S390] kprobes: activation and deactivation")
Miroslav Franc eb129d
introduced a simpler scheme for kprobes (de)activation and status
Miroslav Franc eb129d
tracking by using push_kprobe/pop_kprobe, which supposed to work for
Miroslav Franc eb129d
both initial kprobe entry as well as kprobe reentry and helps to avoid
Miroslav Franc eb129d
handling those two cases differently. The problem is that a sequence of
Miroslav Franc eb129d
calls in case of kprobes reenter:
Miroslav Franc eb129d
push_kprobe() <- NULL (current_kprobe)
Miroslav Franc eb129d
push_kprobe() <- kprobe1 (current_kprobe)
Miroslav Franc eb129d
pop_kprobe() -> kprobe1 (current_kprobe)
Miroslav Franc eb129d
pop_kprobe() -> kprobe1 (current_kprobe)
Miroslav Franc eb129d
leaves "kprobe1" as "current_kprobe" on this cpu, instead of setting it
Miroslav Franc eb129d
to NULL. In fact push_kprobe/pop_kprobe can only store a single state
Miroslav Franc eb129d
(there is just one prev_kprobe in kprobe_ctlblk). Which is a hack but
Miroslav Franc eb129d
sufficient, there is no need to have another prev_kprobe just to store
Miroslav Franc eb129d
NULL. To make a simple and backportable fix simply reset "prev_kprobe"
Miroslav Franc eb129d
when kprobe is poped from this "stack". No need to worry about
Miroslav Franc eb129d
"kprobe_status" in this case, because its value is only checked when
Miroslav Franc eb129d
current_kprobe != NULL.
Miroslav Franc eb129d
Miroslav Franc eb129d
Cc: stable@vger.kernel.org
Miroslav Franc eb129d
Fixes: b9599798f953 ("[S390] kprobes: activation and deactivation")
Miroslav Franc eb129d
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Miroslav Franc eb129d
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Miroslav Franc eb129d
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Miroslav Franc eb129d
Acked-by: Miroslav Franc <mfranc@suse.cz>
Miroslav Franc eb129d
---
Miroslav Franc eb129d
 arch/s390/kernel/kprobes.c | 1 +
Miroslav Franc eb129d
 1 file changed, 1 insertion(+)
Miroslav Franc eb129d
Miroslav Franc eb129d
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
Miroslav Franc eb129d
index c505c0ee5f47..e53192a5d593 100644
Miroslav Franc eb129d
--- a/arch/s390/kernel/kprobes.c
Miroslav Franc eb129d
+++ b/arch/s390/kernel/kprobes.c
Miroslav Franc eb129d
@@ -233,6 +233,7 @@ static void pop_kprobe(struct kprobe_ctlblk *kcb)
Miroslav Franc eb129d
 {
Miroslav Franc eb129d
 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
Miroslav Franc eb129d
 	kcb->kprobe_status = kcb->prev_kprobe.status;
Miroslav Franc eb129d
+	kcb->prev_kprobe.kp = NULL;
Miroslav Franc eb129d
 }
Miroslav Franc eb129d
 NOKPROBE_SYMBOL(pop_kprobe);
Miroslav Franc eb129d