All of lore.kernel.org
 help / color / mirror / Atom feed
From: He Zhe <zhe.he@windriver.com>
To: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com,
	tglx@linutronix.de, bp@alien8.de, dave.hansen@linux.intel.com,
	keescook@chromium.org, alexander.shishkin@linux.intel.com,
	jolsa@kernel.org, namhyung@kernel.org, benh@kernel.crashing.org,
	paulus@samba.org, borntraeger@linux.ibm.com, svens@linux.ibm.com,
	hpa@zytor.com
Cc: x86@kernel.org, linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, linux-perf-users@vger.kernel.org,
	linux-kernel@vger.kernel.org, zhe.he@windriver.com
Subject: [PATCH RFC 2/8] arm64: stacktrace: Add arch_within_stack_frames
Date: Mon, 18 Apr 2022 21:22:11 +0800	[thread overview]
Message-ID: <20220418132217.1573072-3-zhe.he@windriver.com> (raw)
In-Reply-To: <20220418132217.1573072-1-zhe.he@windriver.com>

This function checks if the given address range crosses frame boundary.
It is based on the existing x86 algorithm, but implemented via stacktrace.
This can be tested by USERCOPY_STACK_FRAME_FROM and
USERCOPY_STACK_FRAME_TO in lkdtm.

Signed-off-by: He Zhe <zhe.he@windriver.com>
---
 arch/arm64/Kconfig                   |  1 +
 arch/arm64/include/asm/thread_info.h | 12 +++++
 arch/arm64/kernel/stacktrace.c       | 76 ++++++++++++++++++++++++++--
 3 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 57c4c995965f..0f52a83d7771 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,6 +165,7 @@ config ARM64
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_ARCH_VMAP_STACK
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_ARM_SMCCC
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_EBPF_JIT
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index e1317b7c4525..b839ad9f2248 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -58,6 +58,18 @@ void arch_setup_new_exec(void);
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst,
 				struct task_struct *src);
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len);
 
 #endif
 
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index e4103e085681..219b90c1de12 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -145,12 +145,17 @@ NOKPROBE_SYMBOL(unwind_frame);
 
 static void notrace walk_stackframe(struct task_struct *tsk,
 				    struct stackframe *frame,
-				    bool (*fn)(void *, unsigned long), void *data)
+				    stack_trace_consume_fn fn, void *data)
 {
+	struct frame_info fi;
+
 	while (1) {
 		int ret;
 
-		if (!fn(data, frame->pc))
+		fi.pc = frame->pc;
+		fi.fp = frame->fp;
+		fi.prev_fp = frame->prev_fp;
+		if (!fn(data, &fi))
 			break;
 		ret = unwind_frame(tsk, frame);
 		if (ret < 0)
@@ -159,10 +164,10 @@ static void notrace walk_stackframe(struct task_struct *tsk,
 }
 NOKPROBE_SYMBOL(walk_stackframe);
 
-static bool dump_backtrace_entry(void *arg, unsigned long where)
+static bool dump_backtrace_entry(void *arg, struct frame_info *fi)
 {
 	char *loglvl = arg;
-	printk("%s %pSb\n", loglvl, (void *)where);
+	printk("%s %pSb\n", loglvl, (void *)fi->pc);
 	return true;
 }
 
@@ -210,3 +215,66 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
 
 	walk_stackframe(task, &frame, consume_entry, cookie);
 }
+
+struct arch_stack_object {
+	unsigned long start;
+	unsigned long len;
+	int flag;
+};
+
+static bool arch_stack_object_check(void *data, struct frame_info *fi)
+{
+	struct arch_stack_object *obj = (struct arch_stack_object *)data;
+
+	/* Skip the frame of arch_within_stack_frames itself */
+	if (fi->prev_fp == 0)
+		return true;
+
+	/*
+	 * low ----------------------------------------------> high
+	 * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+	 *                     ^----------------^
+	 *               allow copies only within here
+	 */
+	if (obj->start + obj->len <= fi->fp) {
+		obj->flag = obj->start >=
+			fi->prev_fp + 2 * sizeof(void *) ?
+			GOOD_FRAME : BAD_STACK;
+		return false;
+	} else
+		return true;
+}
+
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	struct arch_stack_object object;
+	struct pt_regs regs;
+
+	if (__builtin_frame_address(1) == 0)
+		return NOT_STACK;
+
+	object.start = (unsigned long)obj;
+	object.len = len;
+	object.flag = NOT_STACK;
+
+	regs.regs[29] = (u64)__builtin_frame_address(1);
+
+	arch_stack_walk(arch_stack_object_check, (void *)&object, NULL, &regs);
+
+	return object.flag;
+#else
+	return NOT_STACK;
+#endif
+}
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: He Zhe <zhe.he@windriver.com>
To: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com,
	tglx@linutronix.de, bp@alien8.de, dave.hansen@linux.intel.com,
	keescook@chromium.org, alexander.shishkin@linux.intel.com,
	jolsa@kernel.org, namhyung@kernel.org, benh@kernel.crashing.org,
	paulus@samba.org, borntraeger@linux.ibm.com, svens@linux.ibm.com,
	hpa@zytor.com
Cc: x86@kernel.org, linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, linux-perf-users@vger.kernel.org,
	linux-kernel@vger.kernel.org, zhe.he@windriver.com
Subject: [PATCH RFC 2/8] arm64: stacktrace: Add arch_within_stack_frames
Date: Mon, 18 Apr 2022 21:22:11 +0800	[thread overview]
Message-ID: <20220418132217.1573072-3-zhe.he@windriver.com> (raw)
In-Reply-To: <20220418132217.1573072-1-zhe.he@windriver.com>

This function checks if the given address range crosses frame boundary.
It is based on the existing x86 algorithm, but implemented via stacktrace.
This can be tested by USERCOPY_STACK_FRAME_FROM and
USERCOPY_STACK_FRAME_TO in lkdtm.

Signed-off-by: He Zhe <zhe.he@windriver.com>
---
 arch/arm64/Kconfig                   |  1 +
 arch/arm64/include/asm/thread_info.h | 12 +++++
 arch/arm64/kernel/stacktrace.c       | 76 ++++++++++++++++++++++++++--
 3 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 57c4c995965f..0f52a83d7771 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,6 +165,7 @@ config ARM64
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_ARCH_VMAP_STACK
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_ARM_SMCCC
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_EBPF_JIT
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index e1317b7c4525..b839ad9f2248 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -58,6 +58,18 @@ void arch_setup_new_exec(void);
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst,
 				struct task_struct *src);
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len);
 
 #endif
 
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index e4103e085681..219b90c1de12 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -145,12 +145,17 @@ NOKPROBE_SYMBOL(unwind_frame);
 
 static void notrace walk_stackframe(struct task_struct *tsk,
 				    struct stackframe *frame,
-				    bool (*fn)(void *, unsigned long), void *data)
+				    stack_trace_consume_fn fn, void *data)
 {
+	struct frame_info fi;
+
 	while (1) {
 		int ret;
 
-		if (!fn(data, frame->pc))
+		fi.pc = frame->pc;
+		fi.fp = frame->fp;
+		fi.prev_fp = frame->prev_fp;
+		if (!fn(data, &fi))
 			break;
 		ret = unwind_frame(tsk, frame);
 		if (ret < 0)
@@ -159,10 +164,10 @@ static void notrace walk_stackframe(struct task_struct *tsk,
 }
 NOKPROBE_SYMBOL(walk_stackframe);
 
-static bool dump_backtrace_entry(void *arg, unsigned long where)
+static bool dump_backtrace_entry(void *arg, struct frame_info *fi)
 {
 	char *loglvl = arg;
-	printk("%s %pSb\n", loglvl, (void *)where);
+	printk("%s %pSb\n", loglvl, (void *)fi->pc);
 	return true;
 }
 
@@ -210,3 +215,66 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
 
 	walk_stackframe(task, &frame, consume_entry, cookie);
 }
+
+struct arch_stack_object {
+	unsigned long start;
+	unsigned long len;
+	int flag;
+};
+
+static bool arch_stack_object_check(void *data, struct frame_info *fi)
+{
+	struct arch_stack_object *obj = (struct arch_stack_object *)data;
+
+	/* Skip the frame of arch_within_stack_frames itself */
+	if (fi->prev_fp == 0)
+		return true;
+
+	/*
+	 * low ----------------------------------------------> high
+	 * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+	 *                     ^----------------^
+	 *               allow copies only within here
+	 */
+	if (obj->start + obj->len <= fi->fp) {
+		obj->flag = obj->start >=
+			fi->prev_fp + 2 * sizeof(void *) ?
+			GOOD_FRAME : BAD_STACK;
+		return false;
+	} else
+		return true;
+}
+
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	struct arch_stack_object object;
+	struct pt_regs regs;
+
+	if (__builtin_frame_address(1) == 0)
+		return NOT_STACK;
+
+	object.start = (unsigned long)obj;
+	object.len = len;
+	object.flag = NOT_STACK;
+
+	regs.regs[29] = (u64)__builtin_frame_address(1);
+
+	arch_stack_walk(arch_stack_object_check, (void *)&object, NULL, &regs);
+
+	return object.flag;
+#else
+	return NOT_STACK;
+#endif
+}
-- 
2.25.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

WARNING: multiple messages have this Message-ID (diff)
From: He Zhe <zhe.he@windriver.com>
To: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com,
	tglx@linutronix.de, bp@alien8.de, dave.hansen@linux.intel.com,
	keescook@chromium.org, alexander.shishkin@linux.intel.com,
	jolsa@kernel.org, namhyung@kernel.org, benh@kernel.crashing.org,
	paulus@samba.org, borntraeger@linux.ibm.com, svens@linux.ibm.com,
	hpa@zytor.com
Cc: linux-s390@vger.kernel.org, zhe.he@windriver.com, x86@kernel.org,
	linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
	linux-riscv@lists.infradead.org, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH RFC 2/8] arm64: stacktrace: Add arch_within_stack_frames
Date: Mon, 18 Apr 2022 21:22:11 +0800	[thread overview]
Message-ID: <20220418132217.1573072-3-zhe.he@windriver.com> (raw)
In-Reply-To: <20220418132217.1573072-1-zhe.he@windriver.com>

This function checks if the given address range crosses frame boundary.
It is based on the existing x86 algorithm, but implemented via stacktrace.
This can be tested by USERCOPY_STACK_FRAME_FROM and
USERCOPY_STACK_FRAME_TO in lkdtm.

Signed-off-by: He Zhe <zhe.he@windriver.com>
---
 arch/arm64/Kconfig                   |  1 +
 arch/arm64/include/asm/thread_info.h | 12 +++++
 arch/arm64/kernel/stacktrace.c       | 76 ++++++++++++++++++++++++++--
 3 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 57c4c995965f..0f52a83d7771 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,6 +165,7 @@ config ARM64
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_ARCH_VMAP_STACK
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_ARM_SMCCC
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_EBPF_JIT
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index e1317b7c4525..b839ad9f2248 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -58,6 +58,18 @@ void arch_setup_new_exec(void);
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst,
 				struct task_struct *src);
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len);
 
 #endif
 
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index e4103e085681..219b90c1de12 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -145,12 +145,17 @@ NOKPROBE_SYMBOL(unwind_frame);
 
 static void notrace walk_stackframe(struct task_struct *tsk,
 				    struct stackframe *frame,
-				    bool (*fn)(void *, unsigned long), void *data)
+				    stack_trace_consume_fn fn, void *data)
 {
+	struct frame_info fi;
+
 	while (1) {
 		int ret;
 
-		if (!fn(data, frame->pc))
+		fi.pc = frame->pc;
+		fi.fp = frame->fp;
+		fi.prev_fp = frame->prev_fp;
+		if (!fn(data, &fi))
 			break;
 		ret = unwind_frame(tsk, frame);
 		if (ret < 0)
@@ -159,10 +164,10 @@ static void notrace walk_stackframe(struct task_struct *tsk,
 }
 NOKPROBE_SYMBOL(walk_stackframe);
 
-static bool dump_backtrace_entry(void *arg, unsigned long where)
+static bool dump_backtrace_entry(void *arg, struct frame_info *fi)
 {
 	char *loglvl = arg;
-	printk("%s %pSb\n", loglvl, (void *)where);
+	printk("%s %pSb\n", loglvl, (void *)fi->pc);
 	return true;
 }
 
@@ -210,3 +215,66 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
 
 	walk_stackframe(task, &frame, consume_entry, cookie);
 }
+
+struct arch_stack_object {
+	unsigned long start;
+	unsigned long len;
+	int flag;
+};
+
+static bool arch_stack_object_check(void *data, struct frame_info *fi)
+{
+	struct arch_stack_object *obj = (struct arch_stack_object *)data;
+
+	/* Skip the frame of arch_within_stack_frames itself */
+	if (fi->prev_fp == 0)
+		return true;
+
+	/*
+	 * low ----------------------------------------------> high
+	 * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+	 *                     ^----------------^
+	 *               allow copies only within here
+	 */
+	if (obj->start + obj->len <= fi->fp) {
+		obj->flag = obj->start >=
+			fi->prev_fp + 2 * sizeof(void *) ?
+			GOOD_FRAME : BAD_STACK;
+		return false;
+	} else
+		return true;
+}
+
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	struct arch_stack_object object;
+	struct pt_regs regs;
+
+	if (__builtin_frame_address(1) == 0)
+		return NOT_STACK;
+
+	object.start = (unsigned long)obj;
+	object.len = len;
+	object.flag = NOT_STACK;
+
+	regs.regs[29] = (u64)__builtin_frame_address(1);
+
+	arch_stack_walk(arch_stack_object_check, (void *)&object, NULL, &regs);
+
+	return object.flag;
+#else
+	return NOT_STACK;
+#endif
+}
-- 
2.25.1


WARNING: multiple messages have this Message-ID (diff)
From: He Zhe <zhe.he@windriver.com>
To: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com,
	tglx@linutronix.de, bp@alien8.de, dave.hansen@linux.intel.com,
	keescook@chromium.org, alexander.shishkin@linux.intel.com,
	jolsa@kernel.org, namhyung@kernel.org, benh@kernel.crashing.org,
	paulus@samba.org, borntraeger@linux.ibm.com, svens@linux.ibm.com,
	hpa@zytor.com
Cc: x86@kernel.org, linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, linux-perf-users@vger.kernel.org,
	linux-kernel@vger.kernel.org, zhe.he@windriver.com
Subject: [PATCH RFC 2/8] arm64: stacktrace: Add arch_within_stack_frames
Date: Mon, 18 Apr 2022 21:22:11 +0800	[thread overview]
Message-ID: <20220418132217.1573072-3-zhe.he@windriver.com> (raw)
In-Reply-To: <20220418132217.1573072-1-zhe.he@windriver.com>

This function checks if the given address range crosses frame boundary.
It is based on the existing x86 algorithm, but implemented via stacktrace.
This can be tested by USERCOPY_STACK_FRAME_FROM and
USERCOPY_STACK_FRAME_TO in lkdtm.

Signed-off-by: He Zhe <zhe.he@windriver.com>
---
 arch/arm64/Kconfig                   |  1 +
 arch/arm64/include/asm/thread_info.h | 12 +++++
 arch/arm64/kernel/stacktrace.c       | 76 ++++++++++++++++++++++++++--
 3 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 57c4c995965f..0f52a83d7771 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,6 +165,7 @@ config ARM64
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_ARCH_VMAP_STACK
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_ARM_SMCCC
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_EBPF_JIT
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index e1317b7c4525..b839ad9f2248 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -58,6 +58,18 @@ void arch_setup_new_exec(void);
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst,
 				struct task_struct *src);
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len);
 
 #endif
 
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index e4103e085681..219b90c1de12 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -145,12 +145,17 @@ NOKPROBE_SYMBOL(unwind_frame);
 
 static void notrace walk_stackframe(struct task_struct *tsk,
 				    struct stackframe *frame,
-				    bool (*fn)(void *, unsigned long), void *data)
+				    stack_trace_consume_fn fn, void *data)
 {
+	struct frame_info fi;
+
 	while (1) {
 		int ret;
 
-		if (!fn(data, frame->pc))
+		fi.pc = frame->pc;
+		fi.fp = frame->fp;
+		fi.prev_fp = frame->prev_fp;
+		if (!fn(data, &fi))
 			break;
 		ret = unwind_frame(tsk, frame);
 		if (ret < 0)
@@ -159,10 +164,10 @@ static void notrace walk_stackframe(struct task_struct *tsk,
 }
 NOKPROBE_SYMBOL(walk_stackframe);
 
-static bool dump_backtrace_entry(void *arg, unsigned long where)
+static bool dump_backtrace_entry(void *arg, struct frame_info *fi)
 {
 	char *loglvl = arg;
-	printk("%s %pSb\n", loglvl, (void *)where);
+	printk("%s %pSb\n", loglvl, (void *)fi->pc);
 	return true;
 }
 
@@ -210,3 +215,66 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
 
 	walk_stackframe(task, &frame, consume_entry, cookie);
 }
+
+struct arch_stack_object {
+	unsigned long start;
+	unsigned long len;
+	int flag;
+};
+
+static bool arch_stack_object_check(void *data, struct frame_info *fi)
+{
+	struct arch_stack_object *obj = (struct arch_stack_object *)data;
+
+	/* Skip the frame of arch_within_stack_frames itself */
+	if (fi->prev_fp == 0)
+		return true;
+
+	/*
+	 * low ----------------------------------------------> high
+	 * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+	 *                     ^----------------^
+	 *               allow copies only within here
+	 */
+	if (obj->start + obj->len <= fi->fp) {
+		obj->flag = obj->start >=
+			fi->prev_fp + 2 * sizeof(void *) ?
+			GOOD_FRAME : BAD_STACK;
+		return false;
+	} else
+		return true;
+}
+
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *	GOOD_FRAME	if within a frame
+ *	BAD_STACK	if placed across a frame boundary (or outside stack)
+ *	NOT_STACK	unable to determine (no frame pointers, etc)
+ */
+int arch_within_stack_frames(const void * const stack,
+		const void * const stackend,
+		const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	struct arch_stack_object object;
+	struct pt_regs regs;
+
+	if (__builtin_frame_address(1) == 0)
+		return NOT_STACK;
+
+	object.start = (unsigned long)obj;
+	object.len = len;
+	object.flag = NOT_STACK;
+
+	regs.regs[29] = (u64)__builtin_frame_address(1);
+
+	arch_stack_walk(arch_stack_object_check, (void *)&object, NULL, &regs);
+
+	return object.flag;
+#else
+	return NOT_STACK;
+#endif
+}
-- 
2.25.1


  parent reply	other threads:[~2022-04-18 13:29 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-18 13:22 [PATCH RFC 0/8] hardened usercopy and stacktrace improvement He Zhe
2022-04-18 13:22 ` He Zhe
2022-04-18 13:22 ` He Zhe
2022-04-18 13:22 ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 1/8] stacktrace: Change callback prototype to pass more information He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-19 13:09   ` Mark Rutland
2022-04-19 13:09     ` Mark Rutland
2022-04-19 13:09     ` Mark Rutland
2022-04-19 13:09     ` Mark Rutland
2022-04-19 14:13     ` He Zhe
2022-04-19 14:13       ` He Zhe
2022-04-19 14:13       ` He Zhe
2022-04-19 14:13       ` He Zhe
2022-04-18 13:22 ` He Zhe [this message]
2022-04-18 13:22   ` [PATCH RFC 2/8] arm64: stacktrace: Add arch_within_stack_frames He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 21:59   ` Kees Cook
2022-04-18 21:59     ` Kees Cook
2022-04-18 21:59     ` Kees Cook
2022-04-18 21:59     ` Kees Cook
2022-04-19 14:01     ` He Zhe
2022-04-19 14:01       ` He Zhe
2022-04-19 14:01       ` He Zhe
2022-04-19 14:01       ` He Zhe
2022-04-20  7:32       ` David Laight
2022-04-20  7:32         ` David Laight
2022-04-20  7:32         ` David Laight
2022-04-20  7:32         ` David Laight
2022-04-19 14:40   ` Mark Rutland
2022-04-19 14:40     ` Mark Rutland
2022-04-19 14:40     ` Mark Rutland
2022-04-19 14:40     ` Mark Rutland
2022-04-21  9:20     ` He Zhe
2022-04-21  9:20       ` He Zhe
2022-04-21  9:20       ` He Zhe
2022-04-21  9:20       ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 3/8] arm64: stacktrace: Make callbacks use new prototype with frame info He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 4/8] powerpc: " He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 5/8] riscv: " He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 6/8] s390: " He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 7/8] x86: " He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22 ` [PATCH RFC 8/8] lkdtm: usercopy: Make USERCOPY_STACK_FRAME_x able to work for all archs He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe
2022-04-18 13:22   ` He Zhe

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=20220418132217.1573072-3-zhe.he@windriver.com \
    --to=zhe.he@windriver.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=benh@kernel.crashing.org \
    --cc=borntraeger@linux.ibm.com \
    --cc=bp@alien8.de \
    --cc=catalin.marinas@arm.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=jolsa@kernel.org \
    --cc=keescook@chromium.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mark.rutland@arm.com \
    --cc=namhyung@kernel.org \
    --cc=paulus@samba.org \
    --cc=svens@linux.ibm.com \
    --cc=tglx@linutronix.de \
    --cc=will@kernel.org \
    --cc=x86@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.