linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@kernel.org>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: "Naveen N . Rao" <naveen.n.rao@linux.vnet.ibm.com>,
	Ananth N Mavinakayanahalli <ananth@linux.ibm.com>,
	Ingo Molnar <mingo@kernel.org>,
	linux-kernel@vger.kernel.org, mhiramat@kernel.org,
	Sven Schnelle <svens@linux.ibm.com>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Russell King <linux@armlinux.org.uk>,
	Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH 10/10] [RFC] arm64: kprobes: Detect error of kretprobe return address fixup
Date: Fri, 15 Oct 2021 21:52:14 +0900	[thread overview]
Message-ID: <163430233451.459050.14342207133770952671.stgit@devnote2> (raw)
In-Reply-To: <163430224341.459050.2369208860773018092.stgit@devnote2>

Add kretprobe_next_ret_addr() which can detect errors in
the given parameter or the kretprobe_instance list, and call
it from arm64 stacktrace.

This kretprobe_next_ret_addr() will return following errors
when it detects;

 - -EINVAL if @cur is NULL (caller issue)
 - -ENOENT if there is no next correct return address
   (either kprobes or caller issue)
 - -EILSEQ if the next currect return address is there
   but doesn't match the framepointer (maybe caller issue)

Thus the caller must check the error and handle it. On arm64,
this tries to handle the errors and show it on the log.

Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 arch/arm64/kernel/stacktrace.c |   10 +++++++-
 include/linux/kprobes.h        |    2 ++
 kernel/kprobes.c               |   49 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index c30624fff6ac..e2f9f479da99 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -133,8 +133,14 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 	}
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 #ifdef CONFIG_KRETPROBES
-	if (is_kretprobe_trampoline(frame->pc))
-		frame->pc = kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
+	if (is_kretprobe_trampoline(frame->pc)) {
+		void *ret = kretprobe_next_ret_addr(tsk, (void *)frame->fp, &frame->kr_cur);
+		/* There must be a bug in this unwinder or kretprobe. */
+		if (WARN_ON_ONCE(IS_ERR(ret)))
+			pr_err("Kretprobe_trampoline recovery failed (%d)\n", PTR_ERR(ret));
+		else
+			frame->pc = (unsigned long)ret;
+	}
 #endif
 
 	frame->pc = ptrauth_strip_insn_pac(frame->pc);
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index e974caf39d3e..8133455c3522 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -516,6 +516,8 @@ static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
 
 unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
 				      struct llist_node **cur);
+kprobe_opcode_t *kretprobe_next_ret_addr(struct task_struct *tsk, void *fp,
+					 struct llist_node **cur);
 #else
 static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
 {
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 4676627cb066..c57168753467 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1922,6 +1922,55 @@ unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
 }
 NOKPROBE_SYMBOL(kretprobe_find_ret_addr);
 
+/**
+ * kretprobe_next_ret_addr -- Find next correct return address from @cur
+ * @tsk: Target task
+ * @fp: A framepointer to verify
+ * @cur: a storage and the base point of the loop cursor.
+ *
+ * Find the next correct return address modified by a kretprobe on @tsk from
+ * the entry which points *@cur. If it finds the next currect return address
+ * whose framepointer matches @fp, returns the return address.
+ * If the next current return address's framepointer doesn't match @fp, this
+ * returns ERR_PTR(-EILSEQ). If the *@cur is the end of the kretprobe_instance
+ * list, returns ERR_PTR(-ENOENT). If the @cur is NULL, returns ERR_PTR(-EINVAL).
+ * The @tsk must be 'current' or a task which is not running. @fp is used for
+ * verifying the framepointer which recorded with the correct return address
+ * (kretprobe_instance::fp field.)
+ * The @cur is a loop cursor for searching the kretprobe return addresses on
+ * the @tsk. If *@cur is NULL, this returns the top entry of the correct return
+ * address.
+ */
+kprobe_opcode_t *kretprobe_next_ret_addr(struct task_struct *tsk, void *fp,
+					 struct llist_node **cur)
+{
+	struct kretprobe_instance *ri = NULL;
+	kprobe_opcode_t *ret;
+
+	if (WARN_ON_ONCE(!cur))
+		return ERR_PTR(-EINVAL);
+
+	if (*cur) {
+		/* This returns the next correct return address */
+		ret = __kretprobe_find_ret_addr(tsk, cur);
+		if (!ret)
+			return ERR_PTR(-ENOENT);
+		ri = container_of(*cur, struct kretprobe_instance, llist);
+		return ri->fp == fp ? ret : ERR_PTR(-EILSEQ);
+	}
+
+	/* If this is the first try, find the FP-matched entry */
+	do {
+		ret = __kretprobe_find_ret_addr(tsk, cur);
+		if (!ret)
+			return ERR_PTR(-ENOENT);
+		ri = container_of(*cur, struct kretprobe_instance, llist);
+	} while (ri->fp != fp);
+
+	return ret;
+}
+NOKPROBE_SYMBOL(kretprobe_next_ret_addr);
+
 void __weak arch_kretprobe_fixup_return(struct pt_regs *regs,
 					kprobe_opcode_t *correct_ret_addr)
 {


      parent reply	other threads:[~2021-10-15 12:52 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-15 12:50 [PATCH 00/10] kprobes: Make KUnit and add stacktrace on kretprobe tests Masami Hiramatsu
2021-10-15 12:50 ` [PATCH 01/10] kprobes: convert tests to kunit Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 02/10] kprobes: Add a test case for stacktrace from kretprobe handler Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 03/10] x86/unwind: Compile kretprobe fixup code only if CONFIG_KRETPROBES=y Masami Hiramatsu
2021-10-15 13:10   ` Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 04/10] arm64: kprobes: Record frame pointer with kretprobe instance Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 05/10] arm64: kprobes: Make a frame pointer on __kretprobe_trampoline Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 06/10] arm64: Recover kretprobe modified return address in stacktrace Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 07/10] ARM: clang: Do not rely on lr register for stacktrace Masami Hiramatsu
2021-10-15 12:51 ` [PATCH 08/10] ARM: kprobes: Make a frame pointer on __kretprobe_trampoline Masami Hiramatsu
2021-10-16 10:37   ` kernel test robot
2021-10-16 21:15   ` Russell King (Oracle)
2021-10-18  5:55     ` Masami Hiramatsu
2021-10-15 12:52 ` [PATCH 09/10] ARM: Recover kretprobe modified return address in stacktrace Masami Hiramatsu
2021-10-15 12:52 ` Masami Hiramatsu [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=163430233451.459050.14342207133770952671.stgit@devnote2 \
    --to=mhiramat@kernel.org \
    --cc=ananth@linux.ibm.com \
    --cc=catalin.marinas@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mingo@kernel.org \
    --cc=nathan@kernel.org \
    --cc=naveen.n.rao@linux.vnet.ibm.com \
    --cc=ndesaulniers@google.com \
    --cc=rostedt@goodmis.org \
    --cc=svens@linux.ibm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).