* [PATCH v8 12/27] mm/ksw: add entry kprobe and exit fprobe management
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Provide ksw_stack_init() and ksw_stack_exit() to manage entry and exit
probes for the target function from ksw_get_config().
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
include/linux/kstackwatch.h | 4 ++
mm/kstackwatch/stack.c | 100 ++++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+)
diff --git a/include/linux/kstackwatch.h b/include/linux/kstackwatch.h
index d7ea89c8c6af..afedd9823de9 100644
--- a/include/linux/kstackwatch.h
+++ b/include/linux/kstackwatch.h
@@ -41,6 +41,10 @@ struct ksw_config {
// singleton, only modified in kernel.c
const struct ksw_config *ksw_get_config(void);
+/* stack management */
+int ksw_stack_init(void);
+void ksw_stack_exit(void);
+
/* watch management */
struct ksw_watchpoint {
struct perf_event *__percpu *event;
diff --git a/mm/kstackwatch/stack.c b/mm/kstackwatch/stack.c
index cec594032515..3aa02f8370af 100644
--- a/mm/kstackwatch/stack.c
+++ b/mm/kstackwatch/stack.c
@@ -1 +1,101 @@
// SPDX-License-Identifier: GPL-2.0
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/atomic.h>
+#include <linux/fprobe.h>
+#include <linux/kprobes.h>
+#include <linux/kstackwatch.h>
+#include <linux/kstackwatch_types.h>
+#include <linux/printk.h>
+
+static struct kprobe entry_probe;
+static struct fprobe exit_probe;
+
+static int ksw_stack_prepare_watch(struct pt_regs *regs,
+ const struct ksw_config *config,
+ ulong *watch_addr, u16 *watch_len)
+{
+ /* implement logic will be added in following patches */
+ *watch_addr = 0;
+ *watch_len = 0;
+ return 0;
+}
+
+static void ksw_stack_entry_handler(struct kprobe *p, struct pt_regs *regs,
+ unsigned long flags)
+{
+ struct ksw_ctx *ctx = ¤t->ksw_ctx;
+ ulong watch_addr;
+ u16 watch_len;
+ int ret;
+
+ ret = ksw_watch_get(&ctx->wp);
+ if (ret)
+ return;
+
+ ret = ksw_stack_prepare_watch(regs, ksw_get_config(), &watch_addr,
+ &watch_len);
+ if (ret) {
+ ksw_watch_off(ctx->wp);
+ ctx->wp = NULL;
+ pr_err("failed to prepare watch target: %d\n", ret);
+ return;
+ }
+
+ ret = ksw_watch_on(ctx->wp, watch_addr, watch_len);
+ if (ret) {
+ pr_err("failed to watch on depth:%d addr:0x%lx len:%u %d\n",
+ ksw_get_config()->depth, watch_addr, watch_len, ret);
+ return;
+ }
+
+}
+
+static void ksw_stack_exit_handler(struct fprobe *fp, unsigned long ip,
+ unsigned long ret_ip,
+ struct ftrace_regs *regs, void *data)
+{
+ struct ksw_ctx *ctx = ¤t->ksw_ctx;
+
+
+ if (ctx->wp) {
+ ksw_watch_off(ctx->wp);
+ ctx->wp = NULL;
+ ctx->sp = 0;
+ }
+}
+
+int ksw_stack_init(void)
+{
+ int ret;
+ char *symbuf = NULL;
+
+ memset(&entry_probe, 0, sizeof(entry_probe));
+ entry_probe.symbol_name = ksw_get_config()->func_name;
+ entry_probe.offset = ksw_get_config()->func_offset;
+ entry_probe.post_handler = ksw_stack_entry_handler;
+ ret = register_kprobe(&entry_probe);
+ if (ret) {
+ pr_err("failed to register kprobe ret %d\n", ret);
+ return ret;
+ }
+
+ memset(&exit_probe, 0, sizeof(exit_probe));
+ exit_probe.exit_handler = ksw_stack_exit_handler;
+ symbuf = (char *)ksw_get_config()->func_name;
+
+ ret = register_fprobe_syms(&exit_probe, (const char **)&symbuf, 1);
+ if (ret < 0) {
+ pr_err("failed to register fprobe ret %d\n", ret);
+ unregister_kprobe(&entry_probe);
+ return ret;
+ }
+
+ return 0;
+}
+
+void ksw_stack_exit(void)
+{
+ unregister_fprobe(&exit_probe);
+ unregister_kprobe(&entry_probe);
+}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 13/27] mm/ksw: add per-task ctx tracking
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Each task tracks its depth, stack pointer, and generation. A watchpoint is
enabled only when the configured depth is reached, and disabled on function
exit.
The context is reset when probes are disabled, generation changes, or exit
depth becomes inconsistent.
Duplicate arming on the same frame is skipped.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/stack.c | 67 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/mm/kstackwatch/stack.c b/mm/kstackwatch/stack.c
index 3aa02f8370af..96014eb4cb12 100644
--- a/mm/kstackwatch/stack.c
+++ b/mm/kstackwatch/stack.c
@@ -11,6 +11,53 @@
static struct kprobe entry_probe;
static struct fprobe exit_probe;
+static bool probe_enable;
+static u16 probe_generation;
+
+static void ksw_reset_ctx(void)
+{
+ struct ksw_ctx *ctx = ¤t->ksw_ctx;
+
+ if (ctx->wp)
+ ksw_watch_off(ctx->wp);
+
+ ctx->wp = NULL;
+ ctx->sp = 0;
+ ctx->depth = 0;
+ ctx->generation = READ_ONCE(probe_generation);
+}
+
+static bool ksw_stack_check_ctx(bool entry)
+{
+ struct ksw_ctx *ctx = ¤t->ksw_ctx;
+ u16 cur_enable = READ_ONCE(probe_enable);
+ u16 cur_generation = READ_ONCE(probe_generation);
+ u16 cur_depth, target_depth = ksw_get_config()->depth;
+
+ if (!cur_enable) {
+ ksw_reset_ctx();
+ return false;
+ }
+
+ if (ctx->generation != cur_generation)
+ ksw_reset_ctx();
+
+ if (!entry && !ctx->depth) {
+ ksw_reset_ctx();
+ return false;
+ }
+
+ if (entry)
+ cur_depth = ctx->depth++;
+ else
+ cur_depth = --ctx->depth;
+
+ if (cur_depth == target_depth)
+ return true;
+ else
+ return false;
+}
+
static int ksw_stack_prepare_watch(struct pt_regs *regs,
const struct ksw_config *config,
ulong *watch_addr, u16 *watch_len)
@@ -25,10 +72,22 @@ static void ksw_stack_entry_handler(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
struct ksw_ctx *ctx = ¤t->ksw_ctx;
+ ulong stack_pointer;
ulong watch_addr;
u16 watch_len;
int ret;
+ stack_pointer = kernel_stack_pointer(regs);
+
+ /*
+ * triggered more than once, may be in a loop
+ */
+ if (ctx->wp && ctx->sp == stack_pointer)
+ return;
+
+ if (!ksw_stack_check_ctx(true))
+ return;
+
ret = ksw_watch_get(&ctx->wp);
if (ret)
return;
@@ -49,6 +108,7 @@ static void ksw_stack_entry_handler(struct kprobe *p, struct pt_regs *regs,
return;
}
+ ctx->sp = stack_pointer;
}
static void ksw_stack_exit_handler(struct fprobe *fp, unsigned long ip,
@@ -57,6 +117,8 @@ static void ksw_stack_exit_handler(struct fprobe *fp, unsigned long ip,
{
struct ksw_ctx *ctx = ¤t->ksw_ctx;
+ if (!ksw_stack_check_ctx(false))
+ return;
if (ctx->wp) {
ksw_watch_off(ctx->wp);
@@ -91,11 +153,16 @@ int ksw_stack_init(void)
return ret;
}
+ WRITE_ONCE(probe_generation, READ_ONCE(probe_generation) + 1);
+ WRITE_ONCE(probe_enable, true);
+
return 0;
}
void ksw_stack_exit(void)
{
+ WRITE_ONCE(probe_enable, false);
+ WRITE_ONCE(probe_generation, READ_ONCE(probe_generation) + 1);
unregister_fprobe(&exit_probe);
unregister_kprobe(&entry_probe);
}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 14/27] mm/ksw: resolve stack watch addr and len
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add helpers to find the stack canary or a local variable addr and len
for the probed function based on ksw_get_config(). For canary search,
limits search to a fixed number of steps to avoid scanning the entire
stack. Validates that the computed address and length are within the
kernel stack.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/stack.c | 80 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 77 insertions(+), 3 deletions(-)
diff --git a/mm/kstackwatch/stack.c b/mm/kstackwatch/stack.c
index 96014eb4cb12..60371b292915 100644
--- a/mm/kstackwatch/stack.c
+++ b/mm/kstackwatch/stack.c
@@ -8,6 +8,7 @@
#include <linux/kstackwatch_types.h>
#include <linux/printk.h>
+#define MAX_CANARY_SEARCH_STEPS 128
static struct kprobe entry_probe;
static struct fprobe exit_probe;
@@ -58,13 +59,86 @@ static bool ksw_stack_check_ctx(bool entry)
return false;
}
+static unsigned long ksw_find_stack_canary_addr(struct pt_regs *regs)
+{
+ unsigned long *stack_ptr, *stack_end, *stack_base;
+ unsigned long expected_canary;
+ unsigned int i;
+
+ stack_ptr = (unsigned long *)kernel_stack_pointer(regs);
+
+ stack_base = (unsigned long *)(current->stack);
+
+ // TODO: limit it to the current frame
+ stack_end = (unsigned long *)((char *)current->stack + THREAD_SIZE);
+
+ expected_canary = current->stack_canary;
+
+ if (stack_ptr < stack_base || stack_ptr >= stack_end) {
+ pr_err("Stack pointer 0x%lx out of bounds [0x%lx, 0x%lx)\n",
+ (unsigned long)stack_ptr, (unsigned long)stack_base,
+ (unsigned long)stack_end);
+ return 0;
+ }
+
+ for (i = 0; i < MAX_CANARY_SEARCH_STEPS; i++) {
+ if (&stack_ptr[i] >= stack_end)
+ break;
+
+ if (stack_ptr[i] == expected_canary) {
+ pr_debug("canary found i:%d 0x%lx\n", i,
+ (unsigned long)&stack_ptr[i]);
+ return (unsigned long)&stack_ptr[i];
+ }
+ }
+
+ pr_debug("canary not found in first %d steps\n",
+ MAX_CANARY_SEARCH_STEPS);
+ return 0;
+}
+
+static int ksw_stack_validate_addr(unsigned long addr, size_t size)
+{
+ unsigned long stack_start, stack_end;
+
+ if (!addr || !size)
+ return -EINVAL;
+
+ stack_start = (unsigned long)current->stack;
+ stack_end = stack_start + THREAD_SIZE;
+
+ if (addr < stack_start || (addr + size) > stack_end)
+ return -ERANGE;
+
+ return 0;
+}
+
static int ksw_stack_prepare_watch(struct pt_regs *regs,
const struct ksw_config *config,
ulong *watch_addr, u16 *watch_len)
{
- /* implement logic will be added in following patches */
- *watch_addr = 0;
- *watch_len = 0;
+ ulong addr;
+ u16 len;
+
+ if (ksw_get_config()->auto_canary) {
+ addr = ksw_find_stack_canary_addr(regs);
+ if (!addr)
+ return -EINVAL;
+ len = sizeof(ulong);
+ } else {
+ addr = kernel_stack_pointer(regs) + ksw_get_config()->sp_offset;
+ len = ksw_get_config()->watch_len;
+ if (!len)
+ len = sizeof(ulong);
+ }
+
+ if (ksw_stack_validate_addr(addr, len)) {
+ pr_err("invalid stack addr:0x%lx len :%u\n", addr, len);
+ return -EINVAL;
+ }
+
+ *watch_addr = addr;
+ *watch_len = len;
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 15/27] mm/ksw: limit canary search to current stack frame
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Use the compiler-provided frame pointer when CONFIG_FRAME_POINTER is
enabled to restrict the stack canary search range to the current
function frame. This prevents scanning beyond valid stack bounds and
improves reliability across architectures.
Also add explicit handling for missing CONFIG_STACKPROTECTOR and make
the failure message more visible.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/stack.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/mm/kstackwatch/stack.c b/mm/kstackwatch/stack.c
index 60371b292915..3455d1e70db9 100644
--- a/mm/kstackwatch/stack.c
+++ b/mm/kstackwatch/stack.c
@@ -64,15 +64,32 @@ static unsigned long ksw_find_stack_canary_addr(struct pt_regs *regs)
unsigned long *stack_ptr, *stack_end, *stack_base;
unsigned long expected_canary;
unsigned int i;
+#ifdef CONFIG_FRAME_POINTER
+ unsigned long *fp = NULL;
+#endif
stack_ptr = (unsigned long *)kernel_stack_pointer(regs);
-
stack_base = (unsigned long *)(current->stack);
- // TODO: limit it to the current frame
stack_end = (unsigned long *)((char *)current->stack + THREAD_SIZE);
+#ifdef CONFIG_FRAME_POINTER
+ /*
+ * Use the compiler-provided frame pointer.
+ * Limit the search to the current frame
+ * Works on any arch that keeps FP when CONFIG_FRAME_POINTER=y.
+ */
+ fp = __builtin_frame_address(0);
+ if (fp > stack_ptr && fp < stack_end)
+ stack_end = fp;
+#endif
+
+#ifdef CONFIG_STACKPROTECTOR
expected_canary = current->stack_canary;
+#else
+ pr_err("no canary without CONFIG_STACKPROTECTOR\n");
+ return 0;
+#endif
if (stack_ptr < stack_base || stack_ptr >= stack_end) {
pr_err("Stack pointer 0x%lx out of bounds [0x%lx, 0x%lx)\n",
@@ -85,15 +102,11 @@ static unsigned long ksw_find_stack_canary_addr(struct pt_regs *regs)
if (&stack_ptr[i] >= stack_end)
break;
- if (stack_ptr[i] == expected_canary) {
- pr_debug("canary found i:%d 0x%lx\n", i,
- (unsigned long)&stack_ptr[i]);
+ if (stack_ptr[i] == expected_canary)
return (unsigned long)&stack_ptr[i];
- }
}
- pr_debug("canary not found in first %d steps\n",
- MAX_CANARY_SEARCH_STEPS);
+ pr_err("canary not found in first %d steps\n", MAX_CANARY_SEARCH_STEPS);
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 16/27] mm/ksw: manage probe and HWBP lifecycle via procfs
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Allow dynamic enabling/disabling of KStackWatch through user input of proc.
With this patch, the entire system becomes functional.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/kernel.c | 60 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/mm/kstackwatch/kernel.c b/mm/kstackwatch/kernel.c
index 87fef139f494..a0e676e60692 100644
--- a/mm/kstackwatch/kernel.c
+++ b/mm/kstackwatch/kernel.c
@@ -14,6 +14,43 @@ static struct ksw_config *ksw_config;
static struct dentry *dbgfs_config;
static struct dentry *dbgfs_dir;
+static bool watching_active;
+
+static int ksw_start_watching(void)
+{
+ int ret;
+
+ /*
+ * Watch init will preallocate the HWBP,
+ * so it must happen before stack init
+ */
+ ret = ksw_watch_init();
+ if (ret) {
+ pr_err("ksw_watch_init ret: %d\n", ret);
+ return ret;
+ }
+
+ ret = ksw_stack_init();
+ if (ret) {
+ pr_err("ksw_stack_init ret: %d\n", ret);
+ ksw_watch_exit();
+ return ret;
+ }
+ watching_active = true;
+
+ pr_info("start watching: %s\n", ksw_config->user_input);
+ return 0;
+}
+
+static void ksw_stop_watching(void)
+{
+ ksw_stack_exit();
+ ksw_watch_exit();
+ watching_active = false;
+
+ pr_info("stop watching: %s\n", ksw_config->user_input);
+}
+
struct param_map {
const char *name; /* long name */
const char *short_name; /* short name (2 letters) */
@@ -119,8 +156,18 @@ static int ksw_parse_config(char *buf, struct ksw_config *config)
static ssize_t ksw_dbgfs_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
- return simple_read_from_buffer(buf, count, ppos, ksw_config->user_input,
- ksw_config->user_input ? strlen(ksw_config->user_input) : 0);
+ const char *out;
+ size_t len;
+
+ if (watching_active && ksw_config->user_input) {
+ out = ksw_config->user_input;
+ len = strlen(out);
+ } else {
+ out = "not watching\n";
+ len = strlen(out);
+ }
+
+ return simple_read_from_buffer(buf, count, ppos, out, len);
}
static ssize_t ksw_dbgfs_write(struct file *file, const char __user *buffer,
@@ -135,6 +182,9 @@ static ssize_t ksw_dbgfs_write(struct file *file, const char __user *buffer,
if (copy_from_user(input, buffer, count))
return -EFAULT;
+ if (watching_active)
+ ksw_stop_watching();
+
input[count] = '\0';
strim(input);
@@ -149,6 +199,12 @@ static ssize_t ksw_dbgfs_write(struct file *file, const char __user *buffer,
return ret;
}
+ ret = ksw_start_watching();
+ if (ret) {
+ pr_err("Failed to start watching with %d\n", ret);
+ return ret;
+ }
+
return count;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 17/27] mm/ksw: add KSTACKWATCH_PROFILING to measure probe cost
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
CONFIG_KSTACKWATCH_PROFILING enables runtime measurement of KStackWatch
probe latencies. When profiling is enabled, KStackWatch collects
entry/exit latencies in its probe callbacks. When KStackWatch is
disabled by clearing its config file, the previously collected statistics
are printed.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/Kconfig | 10 +++
mm/kstackwatch/stack.c | 185 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 183 insertions(+), 12 deletions(-)
diff --git a/mm/kstackwatch/Kconfig b/mm/kstackwatch/Kconfig
index 496caf264f35..3c9385a15c33 100644
--- a/mm/kstackwatch/Kconfig
+++ b/mm/kstackwatch/Kconfig
@@ -12,3 +12,13 @@ config KSTACKWATCH
introduce minor overhead during runtime monitoring.
If unsure, say N.
+
+config KSTACKWATCH_PROFILING
+ bool "KStackWatch profiling"
+ depends on KSTACKWATCH
+ help
+ Measure probe latency and overhead in KStackWatch. It records
+ entry/exit probe times (ns and cycles) and shows statistics when
+ stopping. Useful for performance tuning, not for production use.
+
+ If unsure, say N.
diff --git a/mm/kstackwatch/stack.c b/mm/kstackwatch/stack.c
index 3455d1e70db9..72ae2d3adeec 100644
--- a/mm/kstackwatch/stack.c
+++ b/mm/kstackwatch/stack.c
@@ -6,7 +6,10 @@
#include <linux/kprobes.h>
#include <linux/kstackwatch.h>
#include <linux/kstackwatch_types.h>
+#include <linux/ktime.h>
+#include <linux/percpu.h>
#include <linux/printk.h>
+#include <linux/timex.h>
#define MAX_CANARY_SEARCH_STEPS 128
static struct kprobe entry_probe;
@@ -15,6 +18,120 @@ static struct fprobe exit_probe;
static bool probe_enable;
static u16 probe_generation;
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+struct measure_data {
+ u64 total_entry_with_watch_ns;
+ u64 total_entry_with_watch_cycles;
+ u64 total_entry_without_watch_ns;
+ u64 total_entry_without_watch_cycles;
+ u64 total_exit_with_watch_ns;
+ u64 total_exit_with_watch_cycles;
+ u64 total_exit_without_watch_ns;
+ u64 total_exit_without_watch_cycles;
+ u64 entry_with_watch_count;
+ u64 entry_without_watch_count;
+ u64 exit_with_watch_count;
+ u64 exit_without_watch_count;
+};
+
+static DEFINE_PER_CPU(struct measure_data, measure_stats);
+
+struct measure_ctx {
+ u64 ns_start;
+ u64 cycles_start;
+};
+
+static __always_inline void measure_start(struct measure_ctx *ctx)
+{
+ ctx->ns_start = ktime_get_ns();
+ ctx->cycles_start = get_cycles();
+}
+
+static __always_inline void measure_end(struct measure_ctx *ctx, u64 *total_ns,
+ u64 *total_cycles, u64 *count)
+{
+ u64 ns_end = ktime_get_ns();
+ u64 c_end = get_cycles();
+
+ *total_ns += ns_end - ctx->ns_start;
+ *total_cycles += c_end - ctx->cycles_start;
+ (*count)++;
+}
+
+static void show_measure_stats(void)
+{
+ int cpu;
+ struct measure_data sum = {};
+
+ for_each_possible_cpu(cpu) {
+ struct measure_data *md = per_cpu_ptr(&measure_stats, cpu);
+
+ sum.total_entry_with_watch_ns += md->total_entry_with_watch_ns;
+ sum.total_entry_with_watch_cycles +=
+ md->total_entry_with_watch_cycles;
+ sum.total_entry_without_watch_ns +=
+ md->total_entry_without_watch_ns;
+ sum.total_entry_without_watch_cycles +=
+ md->total_entry_without_watch_cycles;
+
+ sum.total_exit_with_watch_ns += md->total_exit_with_watch_ns;
+ sum.total_exit_with_watch_cycles +=
+ md->total_exit_with_watch_cycles;
+ sum.total_exit_without_watch_ns +=
+ md->total_exit_without_watch_ns;
+ sum.total_exit_without_watch_cycles +=
+ md->total_exit_without_watch_cycles;
+
+ sum.entry_with_watch_count += md->entry_with_watch_count;
+ sum.entry_without_watch_count += md->entry_without_watch_count;
+ sum.exit_with_watch_count += md->exit_with_watch_count;
+ sum.exit_without_watch_count += md->exit_without_watch_count;
+ }
+
+#define AVG(ns, cnt) ((cnt) ? ((ns) / (cnt)) : 0ULL)
+
+ pr_info("entry (with watch): %llu ns, %llu cycles (%llu samples)\n",
+ AVG(sum.total_entry_with_watch_ns, sum.entry_with_watch_count),
+ AVG(sum.total_entry_with_watch_cycles,
+ sum.entry_with_watch_count),
+ sum.entry_with_watch_count);
+
+ pr_info("entry (without watch): %llu ns, %llu cycles (%llu samples)\n",
+ AVG(sum.total_entry_without_watch_ns,
+ sum.entry_without_watch_count),
+ AVG(sum.total_entry_without_watch_cycles,
+ sum.entry_without_watch_count),
+ sum.entry_without_watch_count);
+
+ pr_info("exit (with watch): %llu ns, %llu cycles (%llu samples)\n",
+ AVG(sum.total_exit_with_watch_ns, sum.exit_with_watch_count),
+ AVG(sum.total_exit_with_watch_cycles,
+ sum.exit_with_watch_count),
+ sum.exit_with_watch_count);
+
+ pr_info("exit (without watch): %llu ns, %llu cycles (%llu samples)\n",
+ AVG(sum.total_exit_without_watch_ns,
+ sum.exit_without_watch_count),
+ AVG(sum.total_exit_without_watch_cycles,
+ sum.exit_without_watch_count),
+ sum.exit_without_watch_count);
+}
+
+static void reset_measure_stats(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct measure_data *md = per_cpu_ptr(&measure_stats, cpu);
+
+ memset(md, 0, sizeof(*md));
+ }
+
+ pr_info("measure stats reset.\n");
+}
+
+#endif
+
static void ksw_reset_ctx(void)
{
struct ksw_ctx *ctx = ¤t->ksw_ctx;
@@ -159,25 +276,28 @@ static void ksw_stack_entry_handler(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
struct ksw_ctx *ctx = ¤t->ksw_ctx;
- ulong stack_pointer;
- ulong watch_addr;
+ ulong stack_pointer, watch_addr;
u16 watch_len;
int ret;
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ struct measure_ctx m;
+ struct measure_data *md = this_cpu_ptr(&measure_stats);
+ bool watched = false;
+
+ measure_start(&m);
+#endif
stack_pointer = kernel_stack_pointer(regs);
- /*
- * triggered more than once, may be in a loop
- */
if (ctx->wp && ctx->sp == stack_pointer)
- return;
+ goto out;
if (!ksw_stack_check_ctx(true))
- return;
+ goto out;
ret = ksw_watch_get(&ctx->wp);
if (ret)
- return;
+ goto out;
ret = ksw_stack_prepare_watch(regs, ksw_get_config(), &watch_addr,
&watch_len);
@@ -185,17 +305,32 @@ static void ksw_stack_entry_handler(struct kprobe *p, struct pt_regs *regs,
ksw_watch_off(ctx->wp);
ctx->wp = NULL;
pr_err("failed to prepare watch target: %d\n", ret);
- return;
+ goto out;
}
ret = ksw_watch_on(ctx->wp, watch_addr, watch_len);
if (ret) {
pr_err("failed to watch on depth:%d addr:0x%lx len:%u %d\n",
ksw_get_config()->depth, watch_addr, watch_len, ret);
- return;
+ goto out;
}
ctx->sp = stack_pointer;
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ watched = true;
+#endif
+
+out:
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ if (watched)
+ measure_end(&m, &md->total_entry_with_watch_ns,
+ &md->total_entry_with_watch_cycles,
+ &md->entry_with_watch_count);
+ else
+ measure_end(&m, &md->total_entry_without_watch_ns,
+ &md->total_entry_without_watch_cycles,
+ &md->entry_without_watch_count);
+#endif
}
static void ksw_stack_exit_handler(struct fprobe *fp, unsigned long ip,
@@ -203,15 +338,36 @@ static void ksw_stack_exit_handler(struct fprobe *fp, unsigned long ip,
struct ftrace_regs *regs, void *data)
{
struct ksw_ctx *ctx = ¤t->ksw_ctx;
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ struct measure_ctx m;
+ struct measure_data *md = this_cpu_ptr(&measure_stats);
+ bool watched = false;
+ measure_start(&m);
+#endif
if (!ksw_stack_check_ctx(false))
- return;
+ goto out;
if (ctx->wp) {
ksw_watch_off(ctx->wp);
ctx->wp = NULL;
ctx->sp = 0;
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ watched = true;
+#endif
}
+
+out:
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ if (watched)
+ measure_end(&m, &md->total_exit_with_watch_ns,
+ &md->total_exit_with_watch_cycles,
+ &md->exit_with_watch_count);
+ else
+ measure_end(&m, &md->total_exit_without_watch_ns,
+ &md->total_exit_without_watch_cycles,
+ &md->exit_without_watch_count);
+#endif
}
int ksw_stack_init(void)
@@ -239,7 +395,9 @@ int ksw_stack_init(void)
unregister_kprobe(&entry_probe);
return ret;
}
-
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ reset_measure_stats();
+#endif
WRITE_ONCE(probe_generation, READ_ONCE(probe_generation) + 1);
WRITE_ONCE(probe_enable, true);
@@ -252,4 +410,7 @@ void ksw_stack_exit(void)
WRITE_ONCE(probe_generation, READ_ONCE(probe_generation) + 1);
unregister_fprobe(&exit_probe);
unregister_kprobe(&entry_probe);
+#ifdef CONFIG_KSTACKWATCH_PROFILING
+ show_measure_stats();
+#endif
}
--
2.43.0
^ permalink raw reply related
* [PATCH v8 18/27] arm64/hw_breakpoint: Add arch_reinstall_hw_breakpoint
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add arch_reinstall_hw_breakpoint() to restore a hardware breakpoint
in an atomic context. Unlike the full uninstall and reallocation
path, this lightweight function re-establishes an existing breakpoint
efficiently and safely.
This aligns ARM64 with x86 support for atomic breakpoint reinstalls.
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/hw_breakpoint.h | 1 +
arch/arm64/kernel/hw_breakpoint.c | 5 +++++
3 files changed, 7 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6663ffd23f25..fa35dfa2f5cc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -232,6 +232,7 @@ config ARM64
select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \
HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI
select HAVE_HW_BREAKPOINT if PERF_EVENTS
+ select HAVE_REINSTALL_HW_BREAKPOINT if PERF_EVENTS
select HAVE_IOREMAP_PROT
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_LIVEPATCH
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
index bd81cf17744a..6c98bbbc6aa6 100644
--- a/arch/arm64/include/asm/hw_breakpoint.h
+++ b/arch/arm64/include/asm/hw_breakpoint.h
@@ -119,6 +119,7 @@ extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);
extern int arch_install_hw_breakpoint(struct perf_event *bp);
+extern int arch_reinstall_hw_breakpoint(struct perf_event *bp);
extern void arch_uninstall_hw_breakpoint(struct perf_event *bp);
extern void hw_breakpoint_pmu_read(struct perf_event *bp);
extern int hw_breakpoint_slots(int type);
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ab76b36dce82..bd7d23d7893d 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -292,6 +292,11 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
return hw_breakpoint_control(bp, HW_BREAKPOINT_INSTALL);
}
+int arch_reinstall_hw_breakpoint(struct perf_event *bp)
+{
+ return hw_breakpoint_control(bp, HW_BREAKPOINT_RESTORE);
+}
+
void arch_uninstall_hw_breakpoint(struct perf_event *bp)
{
hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL);
--
2.43.0
^ permalink raw reply related
* [PATCH v8 19/27] arm64/hwbp/ksw: integrate KStackWatch handler support
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add support for identifying KStackWatch watchpoints in the ARM64
hardware breakpoint handler. When a watchpoint belongs to KStackWatch,
the handler bypasses single-step re-arming to allow proper recovery.
Introduce is_ksw_watch_handler() to detect KStackWatch-managed
breakpoints and use it in watchpoint_report() under
CONFIG_KSTACKWATCH.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
arch/arm64/kernel/hw_breakpoint.c | 7 +++++++
include/linux/kstackwatch.h | 2 ++
mm/kstackwatch/watch.c | 8 ++++++++
3 files changed, 17 insertions(+)
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index bd7d23d7893d..7abcd988c5c2 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -14,6 +14,9 @@
#include <linux/errno.h>
#include <linux/hw_breakpoint.h>
#include <linux/kprobes.h>
+#ifdef CONFIG_KSTACKWATCH
+#include <linux/kstackwatch.h>
+#endif
#include <linux/perf_event.h>
#include <linux/ptrace.h>
#include <linux/smp.h>
@@ -738,6 +741,10 @@ static int watchpoint_report(struct perf_event *wp, unsigned long addr,
struct pt_regs *regs)
{
int step = is_default_overflow_handler(wp);
+#ifdef CONFIG_KSTACKWATCH
+ if (is_ksw_watch_handler(wp))
+ step = 1;
+#endif
struct arch_hw_breakpoint *info = counter_arch_bp(wp);
info->trigger = addr;
diff --git a/include/linux/kstackwatch.h b/include/linux/kstackwatch.h
index afedd9823de9..ce3882acc5dc 100644
--- a/include/linux/kstackwatch.h
+++ b/include/linux/kstackwatch.h
@@ -53,6 +53,8 @@ struct ksw_watchpoint {
struct llist_node node; // for atomic watch_on and off
struct list_head list; // for cpu online and offline
};
+
+bool is_ksw_watch_handler(struct perf_event *event);
int ksw_watch_init(void);
void ksw_watch_exit(void);
int ksw_watch_get(struct ksw_watchpoint **out_wp);
diff --git a/mm/kstackwatch/watch.c b/mm/kstackwatch/watch.c
index 99184f63d7e3..c2aa912bf4c4 100644
--- a/mm/kstackwatch/watch.c
+++ b/mm/kstackwatch/watch.c
@@ -64,6 +64,14 @@ static void ksw_watch_handler(struct perf_event *bp,
panic("Stack corruption detected");
}
+bool is_ksw_watch_handler(struct perf_event *event)
+{
+ perf_overflow_handler_t overflow_handler = event->overflow_handler;
+
+ if (unlikely(overflow_handler == ksw_watch_handler))
+ return true;
+ return false;
+}
static void ksw_watch_on_local_cpu(void *info)
{
struct ksw_watchpoint *wp = info;
--
2.43.0
^ permalink raw reply related
* [PATCH v8 20/27] mm/ksw: add self-debug helpers
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Provide two debug helpers:
- ksw_watch_show(): print the current watch target address and length.
- ksw_watch_fire(): intentionally trigger the watchpoint immediately
by writing to the watched address, useful for testing HWBP behavior.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
include/linux/kstackwatch.h | 2 ++
mm/kstackwatch/watch.c | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/linux/kstackwatch.h b/include/linux/kstackwatch.h
index ce3882acc5dc..6daded932ba6 100644
--- a/include/linux/kstackwatch.h
+++ b/include/linux/kstackwatch.h
@@ -60,5 +60,7 @@ void ksw_watch_exit(void);
int ksw_watch_get(struct ksw_watchpoint **out_wp);
int ksw_watch_on(struct ksw_watchpoint *wp, ulong watch_addr, u16 watch_len);
int ksw_watch_off(struct ksw_watchpoint *wp);
+void ksw_watch_show(void);
+void ksw_watch_fire(void);
#endif /* _KSTACKWATCH_H */
diff --git a/mm/kstackwatch/watch.c b/mm/kstackwatch/watch.c
index c2aa912bf4c4..a298c31848a2 100644
--- a/mm/kstackwatch/watch.c
+++ b/mm/kstackwatch/watch.c
@@ -273,3 +273,37 @@ void ksw_watch_exit(void)
{
ksw_watch_free();
}
+
+/* self debug function */
+void ksw_watch_show(void)
+{
+ struct ksw_watchpoint *wp = current->ksw_ctx.wp;
+
+ if (!wp) {
+ pr_info("nothing to show\n");
+ return;
+ }
+
+ pr_info("watch target bp_addr: 0x%llx len:%llu\n", wp->attr.bp_addr,
+ wp->attr.bp_len);
+}
+EXPORT_SYMBOL_GPL(ksw_watch_show);
+
+/* self debug function */
+void ksw_watch_fire(void)
+{
+ struct ksw_watchpoint *wp;
+ char *ptr;
+
+ wp = current->ksw_ctx.wp;
+
+ if (!wp) {
+ pr_info("nothing to fire\n");
+ return;
+ }
+
+ ptr = (char *)wp->attr.bp_addr;
+ pr_warn("watch triggered immediately\n");
+ *ptr = 0x42; // This should trigger immediately for any bp_len
+}
+EXPORT_SYMBOL_GPL(ksw_watch_fire);
--
2.43.0
^ permalink raw reply related
* [PATCH v8 21/27] mm/ksw: add test module
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add a standalone test module for KStackWatch to validate functionality
in controlled scenarios.
The module exposes a simple interface via debugfs
(/sys/kernel/debug/kstackwatch/test), allowing specific test cases to
be triggered with commands such as:
echo test0 > /sys/kernel/debug/kstackwatch/test
To ensure predictable behavior during testing, the module is built with
optimizations disabled.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
show addr of buf and watch_addr of test case
---
include/linux/kstackwatch.h | 2 +
mm/kstackwatch/Kconfig | 10 +++
mm/kstackwatch/Makefile | 6 ++
mm/kstackwatch/kernel.c | 5 ++
mm/kstackwatch/test.c | 121 ++++++++++++++++++++++++++++++++++++
5 files changed, 144 insertions(+)
create mode 100644 mm/kstackwatch/test.c
diff --git a/include/linux/kstackwatch.h b/include/linux/kstackwatch.h
index 6daded932ba6..7711efe85240 100644
--- a/include/linux/kstackwatch.h
+++ b/include/linux/kstackwatch.h
@@ -40,6 +40,8 @@ struct ksw_config {
// singleton, only modified in kernel.c
const struct ksw_config *ksw_get_config(void);
+struct dentry *ksw_get_dbgdir(void);
+
/* stack management */
int ksw_stack_init(void);
diff --git a/mm/kstackwatch/Kconfig b/mm/kstackwatch/Kconfig
index 3c9385a15c33..343b492ddbd3 100644
--- a/mm/kstackwatch/Kconfig
+++ b/mm/kstackwatch/Kconfig
@@ -22,3 +22,13 @@ config KSTACKWATCH_PROFILING
stopping. Useful for performance tuning, not for production use.
If unsure, say N.
+
+config KSTACKWATCH_TEST
+ tristate "KStackWatch Test Module"
+ depends on KSTACKWATCH
+ help
+ This module provides controlled stack corruption scenarios to verify
+ the functionality of KStackWatch. It is useful for development and
+ validation of KStackWatch mechanism.
+
+ If unsure, say N.
diff --git a/mm/kstackwatch/Makefile b/mm/kstackwatch/Makefile
index c99c621eac02..a2c7cd647f69 100644
--- a/mm/kstackwatch/Makefile
+++ b/mm/kstackwatch/Makefile
@@ -1,2 +1,8 @@
obj-$(CONFIG_KSTACKWATCH) += kstackwatch.o
kstackwatch-y := kernel.o stack.o watch.o
+
+obj-$(CONFIG_KSTACKWATCH_TEST) += kstackwatch_test.o
+kstackwatch_test-y := test.o
+CFLAGS_test.o := -fno-inline \
+ -fno-optimize-sibling-calls \
+ -fno-pic -fno-pie -O0 -Og
diff --git a/mm/kstackwatch/kernel.c b/mm/kstackwatch/kernel.c
index a0e676e60692..b25cf6830b15 100644
--- a/mm/kstackwatch/kernel.c
+++ b/mm/kstackwatch/kernel.c
@@ -235,6 +235,11 @@ const struct ksw_config *ksw_get_config(void)
return ksw_config;
}
+struct dentry *ksw_get_dbgdir(void)
+{
+ return dbgfs_dir;
+}
+
static int __init kstackwatch_init(void)
{
int ret = 0;
diff --git a/mm/kstackwatch/test.c b/mm/kstackwatch/test.c
new file mode 100644
index 000000000000..2969564b1a00
--- /dev/null
+++ b/mm/kstackwatch/test.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/kstackwatch.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/prandom.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+
+static struct dentry *test_file;
+
+#define BUFFER_SIZE 32
+
+static void test_watch_fire(void)
+{
+ u64 buffer[BUFFER_SIZE] = { 0 };
+
+ pr_info("entry of %s\n", __func__);
+ ksw_watch_show();
+ pr_info("buf: 0x%px\n", buffer);
+
+ ksw_watch_fire();
+
+ barrier_data(buffer);
+ pr_info("exit of %s\n", __func__);
+}
+
+static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ char cmd[256];
+ int test_num;
+
+ if (count >= sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(cmd, buffer, count))
+ return -EFAULT;
+
+ cmd[count] = '\0';
+ strim(cmd);
+
+ pr_info("received command: %s\n", cmd);
+
+ if (sscanf(cmd, "test%d", &test_num) == 1) {
+ switch (test_num) {
+ case 0:
+ test_watch_fire();
+ break;
+ default:
+ pr_err("Unknown test number %d\n", test_num);
+ return -EINVAL;
+ }
+ } else {
+ pr_err("invalid command format. Use 'testN'.\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t test_dbgfs_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ static const char usage[] =
+ "KStackWatch Simplified Test Module\n"
+ "============ usage ===============\n"
+ "Usage:\n"
+ "echo test{i} > /sys/kernel/debug/kstackwatch/test\n"
+ " test0 - test watch fire\n";
+
+ return simple_read_from_buffer(buffer, count, ppos, usage,
+ strlen(usage));
+}
+
+static const struct file_operations test_dbgfs_fops = {
+ .owner = THIS_MODULE,
+ .read = test_dbgfs_read,
+ .write = test_dbgfs_write,
+ .llseek = noop_llseek,
+};
+
+static int __init kstackwatch_test_init(void)
+{
+ struct dentry *ksw_dir = ksw_get_dbgdir();
+
+ if (!ksw_dir) {
+ pr_err("kstackwatch must be loaded first\n");
+ return -ENODEV;
+ }
+
+ test_file = debugfs_create_file("test", 0600, ksw_dir, NULL,
+ &test_dbgfs_fops);
+ if (!test_file) {
+ pr_err("Failed to create debugfs test file\n");
+ return -ENOMEM;
+ }
+
+ pr_info("module loaded\n");
+ return 0;
+}
+
+static void __exit kstackwatch_test_exit(void)
+{
+ debugfs_remove(test_file);
+ pr_info("module unloaded\n");
+}
+
+module_init(kstackwatch_test_init);
+module_exit(kstackwatch_test_exit);
+
+MODULE_AUTHOR("Jinchao Wang");
+MODULE_DESCRIPTION("KStackWatch Test Module");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v8 22/27] mm/ksw: add stack overflow test
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Extend the test module with a new test case (test1) that intentionally
overflows a local u64 buffer to corrupt the stack canary.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
show addr of buf and watch_addr of test case
---
mm/kstackwatch/test.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/mm/kstackwatch/test.c b/mm/kstackwatch/test.c
index 2969564b1a00..b3f363d9e1e8 100644
--- a/mm/kstackwatch/test.c
+++ b/mm/kstackwatch/test.c
@@ -32,6 +32,22 @@ static void test_watch_fire(void)
pr_info("exit of %s\n", __func__);
}
+static void test_canary_overflow(void)
+{
+ u64 buffer[BUFFER_SIZE];
+
+ pr_info("entry of %s\n", __func__);
+ ksw_watch_show();
+ pr_info("buf: 0x%px\n", buffer);
+
+ /* intentionally overflow */
+ for (int i = BUFFER_SIZE; i < BUFFER_SIZE + 10; i++)
+ buffer[i] = 0xdeadbeefdeadbeef;
+ barrier_data(buffer);
+
+ pr_info("exit of %s\n", __func__);
+}
+
static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
@@ -54,6 +70,9 @@ static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
case 0:
test_watch_fire();
break;
+ case 1:
+ test_canary_overflow();
+ break;
default:
pr_err("Unknown test number %d\n", test_num);
return -EINVAL;
@@ -74,7 +93,8 @@ static ssize_t test_dbgfs_read(struct file *file, char __user *buffer,
"============ usage ===============\n"
"Usage:\n"
"echo test{i} > /sys/kernel/debug/kstackwatch/test\n"
- " test0 - test watch fire\n";
+ " test0 - test watch fire\n"
+ " test1 - test canary overflow\n";
return simple_read_from_buffer(buffer, count, ppos, usage,
strlen(usage));
--
2.43.0
^ permalink raw reply related
* [PATCH v8 23/27] mm/ksw: add recursive depth test
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Introduce a test that performs stack writes in recursive calls to exercise
stack watch at a specific recursion depth.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/test.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/mm/kstackwatch/test.c b/mm/kstackwatch/test.c
index b3f363d9e1e8..1d196f72faba 100644
--- a/mm/kstackwatch/test.c
+++ b/mm/kstackwatch/test.c
@@ -17,6 +17,7 @@
static struct dentry *test_file;
#define BUFFER_SIZE 32
+#define MAX_DEPTH 6
static void test_watch_fire(void)
{
@@ -48,6 +49,21 @@ static void test_canary_overflow(void)
pr_info("exit of %s\n", __func__);
}
+static void test_recursive_depth(int depth)
+{
+ u64 buffer[BUFFER_SIZE];
+
+ pr_info("entry of %s depth:%d\n", __func__, depth);
+
+ if (depth < MAX_DEPTH)
+ test_recursive_depth(depth + 1);
+
+ buffer[0] = depth;
+ barrier_data(buffer);
+
+ pr_info("exit of %s depth:%d\n", __func__, depth);
+}
+
static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
@@ -73,6 +89,9 @@ static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
case 1:
test_canary_overflow();
break;
+ case 2:
+ test_recursive_depth(0);
+ break;
default:
pr_err("Unknown test number %d\n", test_num);
return -EINVAL;
@@ -94,7 +113,8 @@ static ssize_t test_dbgfs_read(struct file *file, char __user *buffer,
"Usage:\n"
"echo test{i} > /sys/kernel/debug/kstackwatch/test\n"
" test0 - test watch fire\n"
- " test1 - test canary overflow\n";
+ " test1 - test canary overflow\n"
+ " test2 - test recursive func\n";
return simple_read_from_buffer(buffer, count, ppos, usage,
strlen(usage));
--
2.43.0
^ permalink raw reply related
* [PATCH v8 24/27] mm/ksw: add multi-thread corruption test cases
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
These tests share a common structure and are grouped together.
- buggy():
exposes the stack address to corrupting(); may omit waiting
- corrupting():
reads the exposed pointer and modifies memory;
if buggy() omits waiting, victim()'s buffer is corrupted
- victim():
initializes a local buffer and later verifies it;
reports an error if the buffer was unexpectedly modified
buggy() and victim() run in worker() thread, with similar stack frame sizes
to simplify testing. By adjusting fence_size in corrupting(), the test can
trigger either silent corruption or overflow across threads.
- Test 3: one worker, 20 loops, silent corruption
- Test 4: 20 workers, one loop each, silent corruption
- Test 5: one worker, one loop, overflow corruption
Test 4 also exercises multiple watchpoint instances.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
mm/ksw: add KSTACKWATCH_PROFILING to measure probe cost
Introduce CONFIG_KSTACKWATCH_PROFILING to enable optional runtime
profiling in KStackWatch. When enabled, it records entry and exit
probe latencies (in nanoseconds and CPU cycles) and reports averaged
statistics at module exit.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
mm/kstackwatch/test.c | 186 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 185 insertions(+), 1 deletion(-)
diff --git a/mm/kstackwatch/test.c b/mm/kstackwatch/test.c
index 1d196f72faba..4bd0e5026fd9 100644
--- a/mm/kstackwatch/test.c
+++ b/mm/kstackwatch/test.c
@@ -19,6 +19,20 @@ static struct dentry *test_file;
#define BUFFER_SIZE 32
#define MAX_DEPTH 6
+struct work_node {
+ ulong *ptr;
+ u64 start_ns;
+ struct completion done;
+ struct list_head list;
+};
+
+static DECLARE_COMPLETION(work_res);
+static DEFINE_MUTEX(work_mutex);
+static LIST_HEAD(work_list);
+
+static int global_fence_size;
+static int global_loop_count;
+
static void test_watch_fire(void)
{
u64 buffer[BUFFER_SIZE] = { 0 };
@@ -64,6 +78,164 @@ static void test_recursive_depth(int depth)
pr_info("exit of %s depth:%d\n", __func__, depth);
}
+static struct work_node *test_mthread_buggy(int thread_id, int seq_id)
+{
+ ulong buf[BUFFER_SIZE];
+ struct work_node *node;
+ bool trigger;
+
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return NULL;
+
+ init_completion(&node->done);
+ node->ptr = buf;
+ node->start_ns = ktime_get_ns();
+ mutex_lock(&work_mutex);
+ list_add(&node->list, &work_list);
+ mutex_unlock(&work_mutex);
+ complete(&work_res);
+
+ trigger = (get_random_u32() % 100) < 10;
+ if (trigger)
+ return node; /* let the caller handle cleanup */
+
+ wait_for_completion(&node->done);
+ kfree(node);
+ return NULL;
+}
+
+#define CORRUPTING_MINIOR_WAIT_NS (100000)
+#define VICTIM_MINIOR_WAIT_NS (300000)
+
+static inline void silent_wait_us(u64 start_ns, u64 min_wait_us)
+{
+ u64 diff_ns, remain_us;
+
+ diff_ns = ktime_get_ns() - start_ns;
+ if (diff_ns < min_wait_us * 1000ULL) {
+ remain_us = min_wait_us - (diff_ns >> 10);
+ usleep_range(remain_us, remain_us + 200);
+ }
+}
+
+static void test_mthread_victim(int thread_id, int seq_id, u64 start_ns)
+{
+ ulong buf[BUFFER_SIZE];
+
+ for (int j = 0; j < BUFFER_SIZE; j++)
+ buf[j] = 0xdeadbeef + seq_id;
+ if (start_ns)
+ silent_wait_us(start_ns, VICTIM_MINIOR_WAIT_NS);
+
+ for (int j = 0; j < BUFFER_SIZE; j++) {
+ if (buf[j] != (0xdeadbeef + seq_id)) {
+ pr_warn("victim[%d][%d]: unhappy buf[%d]=0x%lx\n",
+ thread_id, seq_id, j, buf[j]);
+ return;
+ }
+ }
+
+ pr_info("victim[%d][%d]: happy\n", thread_id, seq_id);
+}
+
+static int test_mthread_corrupting(void *data)
+{
+ struct work_node *node;
+ int fence_size;
+
+ while (!kthread_should_stop()) {
+ if (!wait_for_completion_timeout(&work_res, HZ))
+ continue;
+ while (true) {
+ mutex_lock(&work_mutex);
+ node = list_first_entry_or_null(&work_list,
+ struct work_node, list);
+ if (node)
+ list_del(&node->list);
+ mutex_unlock(&work_mutex);
+
+ if (!node)
+ break; /* no more nodes, exit inner loop */
+ silent_wait_us(node->start_ns,
+ CORRUPTING_MINIOR_WAIT_NS);
+
+ fence_size = READ_ONCE(global_fence_size);
+ for (int i = fence_size; i < BUFFER_SIZE - fence_size;
+ i++)
+ node->ptr[i] = 0xabcdabcd;
+
+ complete(&node->done);
+ }
+ }
+
+ return 0;
+}
+
+static int test_mthread_worker(void *data)
+{
+ int thread_id = (long)data;
+ int loop_count;
+ struct work_node *node;
+
+ loop_count = READ_ONCE(global_loop_count);
+
+ for (int i = 0; i < loop_count; i++) {
+ node = test_mthread_buggy(thread_id, i);
+
+ if (node)
+ test_mthread_victim(thread_id, i, node->start_ns);
+ else
+ test_mthread_victim(thread_id, i, 0);
+ if (node) {
+ wait_for_completion(&node->done);
+ kfree(node);
+ }
+ }
+ return 0;
+}
+
+static void test_mthread_case(int num_workers, int loop_count, int fence_size)
+{
+ static struct task_struct *corrupting;
+ static struct task_struct **workers;
+
+ WRITE_ONCE(global_loop_count, loop_count);
+ WRITE_ONCE(global_fence_size, fence_size);
+
+ init_completion(&work_res);
+ workers = kmalloc_array(num_workers, sizeof(void *), GFP_KERNEL);
+ memset(workers, 0, sizeof(struct task_struct *) * num_workers);
+
+ corrupting = kthread_run(test_mthread_corrupting, NULL, "corrupting");
+ if (IS_ERR(corrupting)) {
+ pr_err("failed to create corrupting thread\n");
+ return;
+ }
+
+ for (ulong i = 0; i < num_workers; i++) {
+ workers[i] = kthread_run(test_mthread_worker, (void *)i,
+ "worker_%ld", i);
+ if (IS_ERR(workers[i])) {
+ pr_err("failto create worker thread %ld", i);
+ workers[i] = NULL;
+ }
+ }
+
+ for (ulong i = 0; i < num_workers; i++) {
+ if (workers[i] && workers[i]->__state != TASK_DEAD) {
+ usleep_range(1000, 2000);
+ i--;
+ }
+ }
+ kfree(workers);
+
+ if (corrupting && !IS_ERR(corrupting)) {
+ kthread_stop(corrupting);
+ corrupting = NULL;
+ }
+}
+
static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
@@ -92,6 +264,15 @@ static ssize_t test_dbgfs_write(struct file *file, const char __user *buffer,
case 2:
test_recursive_depth(0);
break;
+ case 3:
+ test_mthread_case(1, 20, BUFFER_SIZE / 4);
+ break;
+ case 4:
+ test_mthread_case(200, 1, BUFFER_SIZE / 4);
+ break;
+ case 5:
+ test_mthread_case(1, 1, -3);
+ break;
default:
pr_err("Unknown test number %d\n", test_num);
return -EINVAL;
@@ -114,7 +295,10 @@ static ssize_t test_dbgfs_read(struct file *file, char __user *buffer,
"echo test{i} > /sys/kernel/debug/kstackwatch/test\n"
" test0 - test watch fire\n"
" test1 - test canary overflow\n"
- " test2 - test recursive func\n";
+ " test2 - test recursive func\n"
+ " test3 - test silent corruption\n"
+ " test4 - test multiple silent corruption\n"
+ " test5 - test prologue corruption\n";
return simple_read_from_buffer(buffer, count, ppos, usage,
strlen(usage));
--
2.43.0
^ permalink raw reply related
* [PATCH v8 25/27] tools/ksw: add arch-specific test script
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add a shell script under tools/kstackwatch to run self-tests such as
canary overflow and recursive depth. The script supports both x86_64
and arm64, selecting parameters automatically based on uname -m.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
tools/kstackwatch/kstackwatch_test.sh | 85 +++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100755 tools/kstackwatch/kstackwatch_test.sh
diff --git a/tools/kstackwatch/kstackwatch_test.sh b/tools/kstackwatch/kstackwatch_test.sh
new file mode 100755
index 000000000000..6e83397d3213
--- /dev/null
+++ b/tools/kstackwatch/kstackwatch_test.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+echo "IMPORTANT: Before running, make sure you have updated the config values!"
+
+usage() {
+ echo "Usage: $0 [0-5]"
+ echo " 0 - test watch fire"
+ echo " 1 - test canary overflow"
+ echo " 2 - test recursive depth"
+ echo " 3 - test silent corruption"
+ echo " 4 - test multi-threaded silent corruption"
+ echo " 5 - test multi-threaded overflow"
+}
+
+run_test_x86_64() {
+ local test_num=$1
+ case "$test_num" in
+ 0) echo fn=test_watch_fire fo=0x29 ac=1 >/sys/kernel/debug/kstackwatch/config
+ echo test0 > /sys/kernel/debug/kstackwatch/test
+ ;;
+ 1) echo fn=test_canary_overflow fo=0x14 >/sys/kernel/debug/kstackwatch/config
+ echo test1 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 2) echo fn=test_recursive_depth fo=0x2f dp=3 wl=8 so=0 >/sys/kernel/debug/kstackwatch/config
+ echo test2 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 3) echo fn=test_mthread_victim fo=0x4c so=64 wl=8 >/sys/kernel/debug/kstackwatch/config
+ echo test3 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 4) echo fn=test_mthread_victim fo=0x4c so=64 wl=8 >/sys/kernel/debug/kstackwatch/config
+ echo test4 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 5) echo fn=test_mthread_buggy fo=0x16 so=0x100 wl=8 >/sys/kernel/debug/kstackwatch/config
+ echo test5 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ *) usage
+ exit 1 ;;
+ esac
+ # Reset watch after test
+ echo >/sys/kernel/debug/kstackwatch/config
+}
+
+run_test_arm64() {
+ local test_num=$1
+ case "$test_num" in
+ 0) echo fn=test_watch_fire fo=0x50 ac=1 >/sys/kernel/debug/kstackwatch/config
+ echo test0 > /sys/kernel/debug/kstackwatch/test
+ ;;
+ 1) echo fn=test_canary_overflow fo=0x20 so=264 >/sys/kernel/debug/kstackwatch/config
+ echo test1 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 2) echo fn=test_recursive_depth fo=0x34 dp=3 wl=8 so=8 >/sys/kernel/debug/kstackwatch/config
+ echo test2 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 3) echo fn=test_mthread_victim fo=0x6c so=0x48 wl=8 >/sys/kernel/debug/kstackwatch/config
+ echo test3 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 4) echo fn=test_mthread_victim fo=0x6c so=0x48 wl=8 >/sys/kernel/debug/kstackwatch/config
+ echo test4 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ 5) echo fn=test_mthread_buggy fo=0x20 so=264 >/sys/kernel/debug/kstackwatch/config
+ echo test5 >/sys/kernel/debug/kstackwatch/test
+ ;;
+ *) usage
+ exit 1 ;;
+ esac
+ # Reset watch after test
+ echo >/sys/kernel/debug/kstackwatch/config
+}
+
+# Check root and module
+[ "$EUID" -ne 0 ] && echo "Run as root" && exit 1
+for f in /sys/kernel/debug/kstackwatch/config /sys/kernel/debug/kstackwatch/test; do
+ [ ! -f "$f" ] && echo "$f not found" && exit 1
+done
+
+# Run
+[ -z "$1" ] && { usage; exit 0; }
+
+arch=$(uname -m)
+case "$arch" in
+ x86_64|aarch64) run_test_${arch} "$1" ;;
+ *) echo "Unsupported architecture: $arch" && exit 1 ;;
+esac
--
2.43.0
^ permalink raw reply related
* [PATCH v8 26/27] docs: add KStackWatch document
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add documentation for KStackWatch under Documentation/.
It provides an overview, main features, usage details, configuration
parameters, and example scenarios with test cases. The document also
explains how to locate function offsets and interpret logs.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
Documentation/dev-tools/index.rst | 1 +
Documentation/dev-tools/kstackwatch.rst | 377 ++++++++++++++++++++++++
2 files changed, 378 insertions(+)
create mode 100644 Documentation/dev-tools/kstackwatch.rst
diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst
index 4b8425e348ab..272ae9b76863 100644
--- a/Documentation/dev-tools/index.rst
+++ b/Documentation/dev-tools/index.rst
@@ -32,6 +32,7 @@ Documentation/process/debugging/index.rst
lkmm/index
kfence
kselftest
+ kstackwatch
kunit/index
ktap
checkuapi
diff --git a/Documentation/dev-tools/kstackwatch.rst b/Documentation/dev-tools/kstackwatch.rst
new file mode 100644
index 000000000000..9b710b90e512
--- /dev/null
+++ b/Documentation/dev-tools/kstackwatch.rst
@@ -0,0 +1,377 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================================
+Kernel Stack Watch (KStackWatch)
+=================================
+
+Overview
+========
+
+KStackWatch is a lightweight debugging tool designed to detect kernel stack
+corruption in real time. It installs a hardware breakpoint (watchpoint) at a
+function's specified offset using *kprobe.post_handler* and removes it in
+*fprobe.exit_handler*. This covers the full execution window and reports
+corruption immediately with time, location, and call stack.
+
+Main features:
+
+* Immediate and precise stack corruption detection
+* Support for multiple concurrent watchpoints with configurable limits
+* Lockless design, usable in any context
+* Depth filter for recursive calls
+* Low overhead of memory and CPU
+* Flexible debugfs configuration with key=val syntax
+* Architecture support: x86_64 and arm64
+* Auto-canary detection to simplify configuration
+
+Performance Impact
+==================
+
+Runtime overhead was measured on Intel Core Ultra 5 125H @ 3 GHz running
+kernel 6.17, using test4:
+
++------------------------+-------------+---------+
+| Type | Time (ns) | Cycles |
++========================+=============+=========+
+| entry with watch | 10892 | 32620 |
++------------------------+-------------+---------+
+| entry without watch | 159 | 466 |
++------------------------+-------------+---------+
+| exit with watch | 12541 | 37556 |
++------------------------+-------------+---------+
+| exit without watch | 124 | 369 |
++------------------------+-------------+---------+
+
+From a broader perspective, the overall comparison is as follows:
+
++----------------------------+----------------------+-------------------------+
+| Mode | CPU Overhead (add) | Memory Overhead (add) |
++============================+======================+=========================+
+| Compiled but not enabled | None | ~20 B per task |
++----------------------------+----------------------+-------------------------+
+| Enabled, no function hit | None | ~few hundred B |
++----------------------------+----------------------+-------------------------+
+| Func hit, HWBP not toggled | ~140 ns per call | None |
++----------------------------+----------------------+-------------------------+
+| Func hit, HWBP toggled | ~11–12 µs per call | None |
++----------------------------+----------------------+-------------------------+
+
+The overhead is minimal, making KStackWatch suitable for production
+environments where stack corruption is suspected but kernel rebuilds are not
+feasible.
+
+Kconfig Options
+===============
+
+The following configuration options control KStackWatch builds:
+
+- CONFIG_KSTACKWATCH
+
+ Builds the kernel with KStackWatch enabled.
+
+- CONFIG_KSTACKWATCH_PROFILING
+
+ Measures probe runtime overhead for performance analysis and tuning.
+
+- CONFIG_KSTACKWATCH_TEST
+
+ Builds a test module to validate KStackWatch functionality.
+
+Usage
+=====
+
+KStackWatch provides optional configurations for different use cases.
+CONFIG_KSTACKWATCH enables real-time stack corruption detection using hardware breakpoints and probes.
+CONFIG_KSTACKWATCH_PROFILING allows measurement of probe latency and overhead for performance analysis.
+CONFIG_KSTACKWATCH_TEST builds a test module for validating KStackWatch functionality under controlled conditions.
+
+KStackWatch is configured through */sys/kernel/debug/kstackwatch/config* using a
+key=value format. Both long and short forms are supported. Writing an empty
+string disables the watch.
+
+.. code-block:: bash
+
+ # long form
+ echo func_name=? func_offset=? ... > /sys/kernel/debug/kstackwatch/config
+
+ # short form
+ echo fn=? fo=? ... > /sys/kernel/debug/kstackwatch/config
+
+ # disable
+ echo > /sys/kernel/debug/kstackwatch/config
+
+The func_name and the func_offset where the watchpoint should be placed must be
+known. This information can be obtained from *objdump* or other tools.
+
+Required parameters
+--------------------
+
++--------------+--------+-----------------------------------------+
+| Parameter | Short | Description |
++==============+========+=========================================+
+| func_name | fn | Name of the target function |
++--------------+--------+-----------------------------------------+
+| func_offset | fo | Instruction pointer offset |
++--------------+--------+-----------------------------------------+
+
+Optional parameters
+--------------------
+
+Default 0 and can be omitted.
+Both decimal and hexadecimal are supported.
+
++--------------+--------+------------------------------------------------+
+| Parameter | Short | Description |
++==============+========+================================================+
+| auto_canary | ac | Automatically calculated canary sp_offset |
++--------------+--------+------------------------------------------------+
+| depth | dp | Recursion depth filter |
++--------------+--------+------------------------------------------------+
+| | | Maximum number of concurrent watchpoints |
+| max_watch | mw | (default 0, capped by available hardware |
+| | | breakpoints) |
++--------------+--------+------------------------------------------------+
+| panic_hit | ph | Panic system on watchpoint hit (default 0) |
++--------------+--------+------------------------------------------------+
+| sp_offset | so | Watching addr offset from stack pointer |
++--------------+--------+------------------------------------------------+
+| watch_len | wl | Watch length in bytes (1, 2, 4, 8 onX86_64) |
++--------------+--------+------------------------------------------------+
+
+
+Workflow Example
+================
+
+Silent corruption
+-----------------
+
+Consider *test3* in *kstackwatch_test.sh*. Run it directly:
+
+.. code-block:: bash
+
+ echo test3 >/sys/kernel/debug/kstackwatch/test
+
+Sometimes, *test_mthread_victim()* may report as unhappy:
+
+.. code-block:: bash
+
+ [ 7.807082] kstackwatch_test: victim[0][11]: unhappy buf[8]=0xabcdabcd
+
+Its source code is:
+
+.. code-block:: c
+
+ static void test_mthread_victim(int thread_id, int seq_id, u64 start_ns)
+ {
+ ulong buf[BUFFER_SIZE];
+
+ for (int j = 0; j < BUFFER_SIZE; j++)
+ buf[j] = 0xdeadbeef + seq_id;
+
+ if (start_ns)
+ silent_wait_us(start_ns, VICTIM_MINIOR_WAIT_NS);
+
+ for (int j = 0; j < BUFFER_SIZE; j++) {
+ if (buf[j] != (0xdeadbeef + seq_id)) {
+ pr_warn("victim[%d][%d]: unhappy buf[%d]=0x%lx\n",
+ thread_id, seq_id, j, buf[j]);
+ return;
+ }
+ }
+
+ pr_info("victim[%d][%d]: happy\n", thread_id, seq_id);
+ }
+
+From the source code, the report indicates buf[8] was unexpectedly modified,
+a case of silent corruption.
+
+Configuration
+-------------
+
+Since buf[8] is the corrupted variable, the following configuration shows
+how to use KStackWatch to detect its corruption.
+
+func_name
+~~~~~~~~~~~
+
+As seen, buf[8] is initialized and modified in *test_mthread_victim*\(\) ,
+which sets *func_name*.
+
+func_offset & sp_offset
+~~~~~~~~~~~~~~~~~~~~~~~~~
+The watchpoint should be set after the assignment and as close as
+possible, which sets *func_offset*.
+
+The watchpoint should be set to watch buf[8], which sets *sp_offset*.
+
+Use the objdump output to disassemble the function:
+
+.. code-block:: bash
+
+ objdump -S --disassemble=test_mthread_victim vmlinux
+
+A shortened output is:
+
+.. code-block:: text
+
+ static void test_mthread_victim(int thread_id, int seq_id, u64 start_ns)
+ {
+ ffffffff815cb4e0: e8 5b 9b ca ff call ffffffff81275040 <__fentry__>
+ ffffffff815cb4e5: 55 push %rbp
+ ffffffff815cb4e6: 53 push %rbx
+ ffffffff815cb4e7: 48 81 ec 08 01 00 00 sub $0x108,%rsp
+ ffffffff815cb4ee: 89 fd mov %edi,%ebp
+ ffffffff815cb4f0: 89 f3 mov %esi,%ebx
+ ffffffff815cb4f2: 49 89 d0 mov %rdx,%r8
+ ffffffff815cb4f5: 65 48 8b 05 0b cb 80 mov %gs:0x280cb0b(%rip),%rax # ffffffff83dd8008 <__stack_chk_guard>
+ ffffffff815cb4fc: 02
+ ffffffff815cb4fd: 48 89 84 24 00 01 00 mov %rax,0x100(%rsp)
+ ffffffff815cb504: 00
+ ffffffff815cb505: 31 c0 xor %eax,%eax
+ ulong buf[BUFFER_SIZE];
+ ffffffff815cb507: 48 89 e2 mov %rsp,%rdx
+ ffffffff815cb50a: b9 20 00 00 00 mov $0x20,%ecx
+ ffffffff815cb50f: 48 89 d7 mov %rdx,%rdi
+ ffffffff815cb512: f3 48 ab rep stos %rax,%es:(%rdi)
+
+ for (int j = 0; j < BUFFER_SIZE; j++)
+ ffffffff815cb515: eb 10 jmp ffffffff815cb527 <test_mthread_victim+0x47>
+ buf[j] = 0xdeadbeef + seq_id;
+ ffffffff815cb517: 8d 93 ef be ad de lea -0x21524111(%rbx),%edx
+ ffffffff815cb51d: 48 63 c8 movslq %eax,%rcx
+ ffffffff815cb520: 48 89 14 cc mov %rdx,(%rsp,%rcx,8)
+ ffffffff815cb524: 83 c0 01 add $0x1,%eax
+ ffffffff815cb527: 83 f8 1f cmp $0x1f,%eax
+ ffffffff815cb52a: 7e eb jle ffffffff815cb517 <test_mthread_victim+0x37>
+ if (start_ns)
+ ffffffff815cb52c: 4d 85 c0 test %r8,%r8
+ ffffffff815cb52f: 75 21 jne ffffffff815cb552 <test_mthread_victim+0x72>
+ silent_wait_us(start_ns, VICTIM_MINIOR_WAIT_NS);
+ ...
+ ffffffff815cb571: 48 8b 84 24 00 01 00 mov 0x100(%rsp),%rax
+ ffffffff815cb579: 65 48 2b 05 87 ca 80 sub %gs:0x280ca87(%rip),%rax # ffffffff83dd8008 <__stack_chk_guard>
+ ...
+ ffffffff815cb5a1: eb ce jmp ffffffff815cb571 <test_mthread_victim+0x91>
+ }
+ ffffffff815cb5a3: e8 d8 86 f1 00 call ffffffff824e3c80 <__stack_chk_fail>
+
+
+func_offset
+^^^^^^^^^^^
+
+The function begins at ffffffff815cb4e0. The *buf* array is initialized in a loop.
+The instruction storing values into the array is at ffffffff815cb520, and the
+first instruction after the loop is at ffffffff815cb52c.
+
+Because KStackWatch uses *kprobe.post_handler*, the watchpoint can be
+set right after ffffffff815cb520. However, this will cause false positive
+because the watchpoint is active before buf[8] is assigned.
+
+An alternative is to place the watchpoint at ffffffff815cb52c, right
+after the loop. This avoids false positives but leaves a small window
+for false negatives.
+
+In this document, ffffffff815cb52c is chosen for cleaner logs. If false
+negatives are suspected, repeat the test to catch the corruption.
+
+The required offset is calculated from the function start:
+
+*func_offset* is 0x4c (ffffffff815cb52c - ffffffff815cb4e0).
+
+sp_offset
+^^^^^^^^^^^
+
+From the disassembly, the buf array is at the top of the stack,
+meaning buf == rsp. Therefore, buf[8] sits at rsp + 8 * sizeof(ulong) =
+rsp + 64. Thus, *sp_offset* is 64.
+
+Other parameters
+~~~~~~~~~~~~~~~~~~
+
+* *depth* is 0, as test_mthread_victim is not recursive
+* *max_watch* is 0 to use all available hwbps
+* *watch_len* is 8, the size of a ulong on x86_64
+
+Parameters with a value of 0 can be omitted as defaults.
+
+Configure the watch:
+
+.. code-block:: bash
+
+ echo "fn=test_mthread_victim fo=0x4c so=64 wl=8" > /sys/kernel/debug/kstackwatch/config
+
+Now rerun the test:
+
+.. code-block:: bash
+
+ echo test3 >/sys/kernel/debug/kstackwatch/test
+
+The dmesg log shows:
+
+.. code-block:: text
+
+ [ 7.607074] kstackwatch: ========== KStackWatch: Caught stack corruption =======
+ [ 7.607077] kstackwatch: config fn=test_mthread_victim fo=0x4c so=64 wl=8
+ [ 7.607080] CPU: 2 UID: 0 PID: 347 Comm: corrupting Not tainted 6.17.0-rc7-00022-g90270f3db80a-dirty #509 PREEMPT(voluntary)
+ [ 7.607083] Call Trace:
+ [ 7.607084] <#DB>
+ [ 7.607085] dump_stack_lvl+0x66/0xa0
+ [ 7.607091] ksw_watch_handler.part.0+0x2b/0x60
+ [ 7.607094] ksw_watch_handler+0xba/0xd0
+ [ 7.607095] ? test_mthread_corrupting+0x48/0xd0
+ [ 7.607097] ? kthread+0x10d/0x210
+ [ 7.607099] ? ret_from_fork+0x187/0x1e0
+ [ 7.607102] ? ret_from_fork_asm+0x1a/0x30
+ [ 7.607105] __perf_event_overflow+0x154/0x570
+ [ 7.607108] perf_bp_event+0xb4/0xc0
+ [ 7.607112] ? look_up_lock_class+0x59/0x150
+ [ 7.607115] hw_breakpoint_exceptions_notify+0xf7/0x110
+ [ 7.607117] notifier_call_chain+0x44/0x110
+ [ 7.607119] atomic_notifier_call_chain+0x5f/0x110
+ [ 7.607121] notify_die+0x4c/0xb0
+ [ 7.607123] exc_debug_kernel+0xaf/0x170
+ [ 7.607126] asm_exc_debug+0x1e/0x40
+ [ 7.607127] RIP: 0010:test_mthread_corrupting+0x48/0xd0
+ [ 7.607129] Code: c7 80 0a 24 83 e8 48 f1 f1 00 48 85 c0 74 dd eb 30 bb 00 00 00 00 eb 59 48 63 c2 48 c1 e0 03 48 03 03 be cd ab cd ab 48 89 30 <83> c2 01 b8 20 00 00 00 29 c8 39 d0 7f e0 48 8d 7b 10 e8 d1 86 d4
+ [ 7.607130] RSP: 0018:ffffc90000acfee0 EFLAGS: 00000286
+ [ 7.607132] RAX: ffffc90000a13de8 RBX: ffff888102d57580 RCX: 0000000000000008
+ [ 7.607132] RDX: 0000000000000008 RSI: 00000000abcdabcd RDI: ffffc90000acfe00
+ [ 7.607133] RBP: ffff8881085bc800 R08: 0000000000000001 R09: 0000000000000000
+ [ 7.607133] R10: 0000000000000001 R11: 0000000000000000 R12: ffff888105398000
+ [ 7.607134] R13: ffff8881085bc800 R14: ffffffff815cb660 R15: 0000000000000000
+ [ 7.607134] ? __pfx_test_mthread_corrupting+0x10/0x10
+ [ 7.607137] </#DB>
+ [ 7.607138] <TASK>
+ [ 7.607138] kthread+0x10d/0x210
+ [ 7.607140] ? __pfx_kthread+0x10/0x10
+ [ 7.607141] ret_from_fork+0x187/0x1e0
+ [ 7.607143] ? __pfx_kthread+0x10/0x10
+ [ 7.607144] ret_from_fork_asm+0x1a/0x30
+ [ 7.607147] </TASK>
+ [ 7.607147] kstackwatch: =================== KStackWatch End ===================
+ [ 7.807082] kstackwatch_test: victim[0][11]: unhappy buf[8]=0xabcdabcd
+
+The line ``RIP: 0010:test_mthread_corrupting+0x48/0xd0`` shows the exact
+location where the corruption occurred. Now that the ``corrupting()`` function has
+been identified, it is straightforward to trace back to ``buggy()`` and fix the bug.
+
+
+More usage examples and corruption scenarios are provided in
+``kstackwatch_test.sh`` and ``mm/kstackwatch/test.c``.
+
+Limitations
+===========
+
+* Limited by available hardware breakpoints
+* Only one function can be watched at a time
+* Canary search limited to 128 * sizeof(ulong) from the current stack
+ pointer. This is sufficient for most cases, but has three limitations:
+
+ - If the stack frame is larger, the search may fail.
+ - If the function does not have a canary, the search may fail.
+ - If stack memory occasionally contains the same value as the canary,
+ it may be incorrectly matched.
+
+ In these cases, the user can provide the canary location using
+ ``sp_offset``, or treat any memory in the function prologue
+ as the canary.
--
2.43.0
^ permalink raw reply related
* [PATCH v8 27/27] MAINTAINERS: add entry for KStackWatch
From: Jinchao Wang @ 2025-11-10 16:36 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark,
Jinchao Wang, Jinjie Ruan, Jiri Olsa, Jonathan Corbet, Juri Lelli,
Justin Stitt, kasan-dev, Kees Cook, Liam R. Howlett, Liang Kan,
Linus Walleij, linux-arm-kernel, linux-doc, linux-kernel,
linux-mm, linux-perf-users, linux-trace-kernel, llvm,
Lorenzo Stoakes, Mark Rutland, Masahiro Yamada, Mathieu Desnoyers,
Mel Gorman, Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
Add a maintainer entry for Kernel Stack Watch.
Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index ddecf1ef3bed..9757775de515 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13615,6 +13615,15 @@ F: Documentation/filesystems/smb/ksmbd.rst
F: fs/smb/common/
F: fs/smb/server/
+KERNEL STACK WATCH
+M: Jinchao Wang <wangjinchao600@gmail.com>
+S: Maintained
+F: Documentation/dev-tools/kstackwatch.rst
+F: include/linux/kstackwatch.h
+F: include/linux/kstackwatch_types.h
+F: mm/kstackwatch/
+F: tools/kstackwatch/
+
KERNEL UNIT TESTING FRAMEWORK (KUnit)
M: Brendan Higgins <brendan.higgins@linux.dev>
M: David Gow <davidgow@google.com>
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Lorenzo Stoakes @ 2025-11-10 16:51 UTC (permalink / raw)
To: Dave Hansen
Cc: Dave Hansen, linux-kernel, Steven Rostedt, Dan Williams,
Theodore Ts'o, Sasha Levin, Jonathan Corbet, Kees Cook,
Greg Kroah-Hartman, Miguel Ojeda, Shuah Khan, Christian Brauner,
Vlastimil Babka, workflows@vger.kernel.org,
ksummit@lists.linux.dev, Dan Carpenter, Julia Lawall,
James Bottomley, Mark Brown, Paul E. McKenney, Jiri Kosina
In-Reply-To: <103ee61c-f958-440c-af73-1cf3600d10fd@intel.com>
+re-cc various - email is a pain!
On Mon, Nov 10, 2025 at 08:35:12AM -0800, Dave Hansen wrote:
> On 11/10/25 02:48, Lorenzo Stoakes wrote:
> ...
> > It also seems slightly odd to produce this in advance of the maintainer's
> > summit, as I felt there was some agreement that the topic should be discussed
> > there?
>
> The TAB discussions have been ongoing and this document was mostly put
> together before the ksummit thread even launched off. This patch just
> suffered from being put on the back burner.
Ah that's useful context!
I mean I (obviously) feel this document is very necessary/useful so it's
nice that this was already an ongoing thing and we're all aligned anyway.
>
> > I think stating that we will NOT accept series that are generated without
> > understanding would be very beneficial in all respects, rather than leaving
> > it somehow implied.
>
> I actually don't think that's a tooling-specific requirement.
>
> If you're posting a series, you should understand it. I've seen quite a
> few cases where folks will pick up someone else's work, forward port it,
> and post it again without a clear understanding of the series.
>
> "Understand and be able to defend what you contribute" is certainly a
> good rule. It's also concise enough to have this document touch in it.
>
> Would that suffice?
That's great thanks. And yes absolutely it applies to everything, but
obviously LLMs are a realm where a person's capacity to exceed their
understanding is amplified.
>
> >> +Guidelines
> >> +==========
> >> +
> >> +First, read the Developer's Certificate of Origin:
> >> +Documentation/process/submitting-patches.rst . Its rules are simple
> >> +and have been in place for a long time. They have covered many
> >> +tool-generated contributions.
> >> +
> >> +Second, when making a contribution, be transparent about the origin of
> >> +content in cover letters and changelogs. You can be more transparent
> >> +by adding information like this:
> >> +
> >> + - What tools were used?
> >> + - The input to the tools you used, like the coccinelle source script.
> >
> > Not sure repeatedly using coccinelle as an example is helpful, as
> > coccinelle is far less of an issue than LLM tooling, perhaps for the
> > avoidance of doubt, expand this to include references to that?
> >
> >> + - If code was largely generated from a single or short set of
> >> + prompts, include those prompts in the commit log. For longer
> >> + sessions, include a summary of the prompts and the nature of
> >> + resulting assistance.
> >
> > Maybe worth saying send it in a cover letter if a series, but perhaps
> > pedantic.
>
> Do we have a good short term that means "commit logs or cover letter"?
> "Changelogs" maybe? But, yeah, we don't want people reading this and
> avoiding putting stuff in cover letters.
Yeah it's maybe not worth specifying to be honest, it might just add
confusion.
>
> >> + - Which portions of the content were affected by that tool?
> >> +
> >> +As with all contributions, individual maintainers have discretion to
> >> +choose how they handle the contribution. For example, they might:
> >> +
> >> + - Treat it just like any other contribution
> >> + - Reject it outright
> >> + - Review the contribution with extra scrutiny
> >> + - Suggest a better prompt instead of suggesting specific code changes
> >> + - Ask for some other special steps, like asking the contributor to
> >> + elaborate on how the tool or model was trained
> >> + - Ask the submitter to explain in more detail about the contribution
> >> + so that the maintainer can feel comfortable that the submitter fully
> >> + understands how the code works.
> >
> > OK I wrote something suggesting you add this and you already have :) that's
> > great. Let me go delete that request :)
> >
> > However I'm not sure the 'as with all contributions' is right though - as a
> > maintainer in mm I don't actually feel that we can reject outright without
> > having to give significant explanation as to why.
> >
> > And I think that's often the case - people (rightly) dislike blanket NAKs
> > and it's a terrible practice, which often (also rightly) gets pushback from
> > co-maintainers or others in the community.
> >
> > So I think perhaps it'd also be useful to very explicitly say that
> > maintainers may say no summarily in instances where the review load would
> > simply be too much to handle large clearly-AI-generated and
> > clearly-unfiltered series.
> >
> > Another point to raise perhaps is that - even in the cases where the
> > submitter is carefully reviewing generated output - that submitters must be
> > reasonable in terms of the volume they submit. This is perhaps hand wavey
> > but mentioning it would be great not least for the ability for maintainers
> > to point at the doc and reference it.
>
> How about we expand this bullet a bit?
>
> - Review the contribution with extra scrutiny
>
> to
>
> - Treat the contribution specially like reviewing with extra scrutiny,
> or at a lower priority than human-generated content.
>
> That's a good match for the "Treat it just like any other contribution"
> bullet. Maintainers can either treat it normally _or_ specially.
That sounds good.
I do still think an explicit point about volume is important though, at
least to underline it.
Something like:
Please be wary of the volume of submitted patches - sending an
unreasonable number of generated patches is more likely to result
in maintainers rejecting them or deprioritising review.
Perhaps?
>
> >> diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst
> >> index aa12f26601949..e1a8a31389f53 100644
> >> --- a/Documentation/process/index.rst
> >> +++ b/Documentation/process/index.rst
> >> @@ -68,6 +68,7 @@ beyond).
> >> stable-kernel-rules
> >> management-style
> >> researcher-guidelines
> >> + generated-content
> >>
> >> Dealing with bugs
> >> -----------------
> >
> > I guess this is a WIP?
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Laurent Pinchart @ 2025-11-10 17:25 UTC (permalink / raw)
To: Christian Brauner
Cc: Dave Hansen, Vlastimil Babka, linux-kernel,
workflows@vger.kernel.org, ksummit@lists.linux.dev,
Steven Rostedt, Dan Williams, Theodore Ts'o, Sasha Levin,
Jonathan Corbet, Kees Cook, Greg Kroah-Hartman, Miguel Ojeda,
Shuah Khan
In-Reply-To: <20251110-weiht-etablieren-39e7b63ef76d@brauner>
On Mon, Nov 10, 2025 at 09:58:52AM +0100, Christian Brauner wrote:
> On Mon, Nov 10, 2025 at 08:43:06AM +0100, Vlastimil Babka wrote:
> > +Cc ksummit (where the discussions about this topic happened recently) and
> > workflows (probably the closest list we have for such things in general)
> > because nobody reads lkml today and this seems to have been going under the
> > radar until mentioned at lwn yesterday
> >
> > On 11/6/25 00:15, Dave Hansen wrote:
> > > In the last few years, the capabilities of coding tools have exploded.
> > > As those capabilities have expanded, contributors and maintainers have
> > > more and more questions about how and when to apply those
> > > capabilities.
> > >
> > > The shiny new AI tools (chatbots, coding assistants and more) are
> > > impressive.
>
> This reads like a factual statement about "impressiveness" of the tools.
> Just drop that sentence, please. It doesn't add value to the commit
> message at all.
>
> > > Add new Documentation to guide contributors on how to
> > > best use kernel development tools, new and old.
> > >
> > > Note, though, there are fundamentally no new or unique rules in this
> > > new document. It clarifies expectations that the kernel community has
> > > had for many years. For example, researchers are already asked to
> > > disclose the tools they use to find issues in
> > > Documentation/process/researcher-guidelines.rst. This new document
> > > just reiterates existing best practices for development tooling.
> > >
> > > In short: Please show your work and make sure your contribution is
> > > easy to review.
> > >
> > > Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
> > > Cc: Steven Rostedt <rostedt@goodmis.org>
> > > Cc: Dan Williams <dan.j.williams@intel.com>
> > > Cc: Theodore Ts'o <tytso@mit.edu>
> > > Cc: Sasha Levin <sashal@kernel.org>
> > > Cc: Jonathan Corbet <corbet@lwn.net>
> > > Cc: Kees Cook <kees@kernel.org>
> > > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Cc: Miguel Ojeda <ojeda@kernel.org>
> > > Cc: Shuah Khan <shuah@kernel.org>
> > >
> > > --
> > >
> > > This document was a collaborative effort from all the members of
> > > the TAB. I just reformatted it into .rst and wrote the changelog.
> > >
> > > Changes from v1:
> > > * Rename to generated-content.rst and add to documentation index.
> > > (Jon)
> > > * Rework subject to align with the new filename
> > > * Replace commercial names with generic ones. (Jon)
> > > * Be consistent about punctuation at the end of bullets for whole
> > > sentences. (Miguel)
> > > * Formatting sprucing up and minor typos (Miguel)
> > > ---
> > > Documentation/process/generated-content.rst | 94 +++++++++++++++++++++
> > > Documentation/process/index.rst | 1 +
> > > 2 files changed, 95 insertions(+)
> > > create mode 100644 Documentation/process/generated-content.rst
> > >
> > > diff --git a/Documentation/process/generated-content.rst b/Documentation/process/generated-content.rst
> > > new file mode 100644
> > > index 0000000000000..5e8ff44190932
> > > --- /dev/null
> > > +++ b/Documentation/process/generated-content.rst
> > > @@ -0,0 +1,94 @@
> > > +============================================
> > > +Kernel Guidelines for Tool Generated Content
> > > +============================================
> > > +
> > > +Purpose
> > > +=======
> > > +
> > > +Kernel contributors have been using tooling to generate contributions
> > > +for a long time.
>
> > > These tools are constantly becoming more capable and
> > > +undoubtedly improve developer productivity. At the same time, reviewer
>
> "undoubtedly improve developer productivity"?
> Am I reading an advert or kernel documentation about the policy how to
> use new tooling?
>
> Please keep it factual without statements about what perceived value
> this adds. People use it and we have to have a policy for it. There's no
> need to celebrate it.
>
> > > +and maintainer bandwidth is a very scarce resource. Understanding
> > > +which portions of a contribution come from humans versus tools is
> > > +critical to maintain those resources and keep kernel development
> > > +healthy.
> > > +
> > > +The goal here is to clarify community expectations around tools. This
> > > +lets everyone become more productive while also maintaining high
> > > +degrees of trust between submitters and reviewers.
> > > +
> > > +Out of Scope
> > > +============
> > > +
> > > +These guidelines do not apply to tools that make trivial tweaks to
> > > +preexisting content. Nor do they pertain to AI tooling that helps with
> > > +menial tasks. Some examples:
> > > +
> > > + - Spelling and grammar fix ups, like rephrasing to imperative voice
> > > + - Typing aids like identifier completion, common boilerplate or
> > > + trivial pattern completion
> > > + - Purely mechanical transformations like variable renaming
Mechanical transformations are often performed with Coccinelle. Given
how you mention that tool below, I wouldn't frame it as out of scope
here.
> > > + - Reformatting, like running Lindent, ``clang-format`` or
> > > + ``rust-fmt``
> > > +
> > > +Even if your tool use is out of scope you should still always consider
> > > +if it would help reviewing your contribution if the reviewer knows
> > > +about the tool that you used.
> > > +
> > > +In Scope
> > > +========
> > > +
> > > +These guidelines apply when a meaningful amount of content in a kernel
> > > +contribution was not written by a person in the Signed-off-by chain,
> > > +but was instead created by a tool.
> > > +
> > > +Detection of a problem is also a part of the development process; if a
> > > +tool was used to find a problem addressed by a change, that should be
> > > +noted in the changelog. This not only gives credit where it is due, it
> > > +also helps fellow developers find out about these tools.
> > > +
> > > +Some examples:
> > > + - Any tool-suggested fix such as ``checkpatch.pl --fix``
> > > + - Coccinelle scripts
> > > + - A chatbot generated a new function in your patch to sort list entries.
> > > + - A .c file in the patch was originally generated by a LLM but cleaned
> > > + up by hand.
> > > + - The changelog was generated by handing the patch to a generative AI
> > > + tool and asking it to write the changelog.
> > > + - The changelog was translated from another language.
> > > +
> > > +If in doubt, choose transparency and assume these guidelines apply to
> > > +your contribution.
> > > +
> > > +Guidelines
> > > +==========
> > > +
> > > +First, read the Developer's Certificate of Origin:
> > > +Documentation/process/submitting-patches.rst . Its rules are simple
> > > +and have been in place for a long time. They have covered many
> > > +tool-generated contributions.
> > > +
> > > +Second, when making a contribution, be transparent about the origin of
> > > +content in cover letters and changelogs. You can be more transparent
> > > +by adding information like this:
> > > +
> > > + - What tools were used?
> > > + - The input to the tools you used, like the coccinelle source script.
> > > + - If code was largely generated from a single or short set of
> > > + prompts, include those prompts in the commit log. For longer
> > > + sessions, include a summary of the prompts and the nature of
> > > + resulting assistance.
> > > + - Which portions of the content were affected by that tool?
> > > +
> > > +As with all contributions, individual maintainers have discretion to
> > > +choose how they handle the contribution. For example, they might:
> > > +
> > > + - Treat it just like any other contribution
> > > + - Reject it outright
> > > + - Review the contribution with extra scrutiny
> > > + - Suggest a better prompt instead of suggesting specific code changes
> > > + - Ask for some other special steps, like asking the contributor to
> > > + elaborate on how the tool or model was trained
> > > + - Ask the submitter to explain in more detail about the contribution
> > > + so that the maintainer can feel comfortable that the submitter fully
> > > + understands how the code works.
> > > diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst
> > > index aa12f26601949..e1a8a31389f53 100644
> > > --- a/Documentation/process/index.rst
> > > +++ b/Documentation/process/index.rst
> > > @@ -68,6 +68,7 @@ beyond).
> > > stable-kernel-rules
> > > management-style
> > > researcher-guidelines
> > > + generated-content
> > >
> > > Dealing with bugs
> > > -----------------
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v8 00/27] mm/ksw: Introduce KStackWatch debugging tool
From: Matthew Wilcox @ 2025-11-10 17:33 UTC (permalink / raw)
To: Jinchao Wang
Cc: Andrew Morton, Masami Hiramatsu (Google), Peter Zijlstra,
Randy Dunlap, Marco Elver, Mike Rapoport, Alexander Potapenko,
Adrian Hunter, Alexander Shishkin, Alice Ryhl, Andrey Konovalov,
Andrey Ryabinin, Andrii Nakryiko, Ard Biesheuvel,
Arnaldo Carvalho de Melo, Ben Segall, Bill Wendling,
Borislav Petkov, Catalin Marinas, Dave Hansen, David Hildenbrand,
David Kaplan, David S. Miller, Dietmar Eggemann, Dmitry Vyukov,
H. Peter Anvin, Ian Rogers, Ingo Molnar, James Clark, Jinjie Ruan,
Jiri Olsa, Jonathan Corbet, Juri Lelli, Justin Stitt, kasan-dev,
Kees Cook, Liam R. Howlett, Liang Kan, Linus Walleij,
linux-arm-kernel, linux-doc, linux-kernel, linux-mm,
linux-perf-users, linux-trace-kernel, llvm, Lorenzo Stoakes,
Mark Rutland, Masahiro Yamada, Mathieu Desnoyers, Mel Gorman,
Michal Hocko, Miguel Ojeda, Nam Cao, Namhyung Kim,
Nathan Chancellor, Naveen N Rao, Nick Desaulniers, Rong Xu,
Sami Tolvanen, Steven Rostedt, Suren Baghdasaryan,
Thomas Gleixner, Thomas Weißschuh, Valentin Schneider,
Vincent Guittot, Vincenzo Frascino, Vlastimil Babka, Will Deacon,
workflows, x86
In-Reply-To: <20251110163634.3686676-1-wangjinchao600@gmail.com>
On Tue, Nov 11, 2025 at 12:35:55AM +0800, Jinchao Wang wrote:
> Earlier this year, I debugged a stack corruption panic that revealed the
> limitations of existing debugging tools. The bug persisted for 739 days
> before being fixed (CVE-2025-22036), and my reproduction scenario
> differed from the CVE report—highlighting how unpredictably these bugs
> manifest.
Well, this demonstrates the dangers of keeping this problem siloed
within your own exfat group. The fix made in 1bb7ff4204b6 is wrong!
It was fixed properly in 7375f22495e7 which lists its Fixes: as
Linux-2.6.12-rc2, but that's simply the beginning of git history.
It's actually been there since v2.4.6.4 where it's documented as simply:
- some subtle fs/buffer.c race conditions (Andrew Morton, me)
As far as I can tell the changes made in 1bb7ff4204b6 should be
reverted.
> Initially, I enabled KASAN, but the bug did not reproduce. Reviewing the
> code in __blk_flush_plug(), I found it difficult to trace all logic
> paths due to indirect function calls through function pointers.
So why is the solution here not simply to fix KASAN instead of this
giant patch series?
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Linus Torvalds @ 2025-11-10 17:44 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Christian Brauner, Dave Hansen, Vlastimil Babka, linux-kernel,
workflows@vger.kernel.org, ksummit@lists.linux.dev,
Steven Rostedt, Dan Williams, Theodore Ts'o, Sasha Levin,
Jonathan Corbet, Kees Cook, Greg Kroah-Hartman, Miguel Ojeda,
Shuah Khan
In-Reply-To: <20251110172507.GA21641@pendragon.ideasonboard.com>
On Mon, 10 Nov 2025 at 09:25, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Mechanical transformations are often performed with Coccinelle. Given
> how you mention that tool below, I wouldn't frame it as out of scope
> here.
Honestly, I think the documented rule should not aim to treat AI as
anything special at all, and literally just talk about tooling.
Exactly because we've used things like coccinelle (and much simpler
tools like 'sed', for that matter) for ages.
IOW, this should all be about "tool-assisted patches should be
described as such, and should explain how the tool was used".
If people send in patches that have been generated by tools, we
already ask people to just include the script in the commit message.
I mean, we already have commit messages that say things like
This is a completely mechanical patch (done with a simple "sed -i"
statement).
when people do mindless conversions that are so straightforward that
the actual sed patch isn't even documented (in that case is was
something like just
sed -i 's/__ASSEMBLY__/__ASSEMBLER__/'
or whatever), and in other cases people include the actual script
(random example being commit 96b451d53ae9: "drm/{i915,xe}: convert
i915 and xe display members into pointers").
I think we should treat any AI generated patches similarly: people
should mention the tool it was done with, and the script (ok, the
"scripts" are called "prompts", because AI is so "special") used.
Sure, AI ends up making the result potentially much more subtle, but I
don't think the *issue* is new, and I don't think it should need to be
treated as such.
Linus
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Steven Rostedt @ 2025-11-10 17:46 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Christian Brauner, Dave Hansen, Vlastimil Babka, linux-kernel,
workflows@vger.kernel.org, ksummit@lists.linux.dev, Dan Williams,
Theodore Ts'o, Sasha Levin, Jonathan Corbet, Kees Cook,
Greg Kroah-Hartman, Miguel Ojeda, Shuah Khan
In-Reply-To: <20251110172507.GA21641@pendragon.ideasonboard.com>
On Mon, 10 Nov 2025 19:25:07 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > > > + - Purely mechanical transformations like variable renaming
>
> Mechanical transformations are often performed with Coccinelle. Given
> how you mention that tool below, I wouldn't frame it as out of scope
> here.
Agreed. Tooling that performs "mechanical transformations like variable
renaming" is definitely in scope of this document. The number of times I've
seen this "simple" activity make mistakes. It most definitely should be
disclosed if a tool helped in this regard.
Anyway,
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
-- Steve
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Dave Hansen @ 2025-11-10 17:41 UTC (permalink / raw)
To: Laurent Pinchart, Christian Brauner
Cc: Dave Hansen, Vlastimil Babka, linux-kernel,
workflows@vger.kernel.org, ksummit@lists.linux.dev,
Steven Rostedt, Dan Williams, Theodore Ts'o, Sasha Levin,
Jonathan Corbet, Kees Cook, Greg Kroah-Hartman, Miguel Ojeda,
Shuah Khan
In-Reply-To: <20251110172507.GA21641@pendragon.ideasonboard.com>
On 11/10/25 09:25, Laurent Pinchart wrote:
>>>> + - Purely mechanical transformations like variable renaming
> Mechanical transformations are often performed with Coccinelle. Given
> how you mention that tool below, I wouldn't frame it as out of scope
> here.
The key here isn't which tool is used, it's how it's used.
If you go use Coccinelle for pure variable renaming, you don't need to
mention it. Same as if you use perl or vim to do a s/foo/bar/.
That said, if you choose to attach your trivial variable renaming
Coccinelle script, everyone will be better off for it.
^ permalink raw reply
* RE: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Luck, Tony @ 2025-11-10 17:56 UTC (permalink / raw)
To: Linus Torvalds, Laurent Pinchart
Cc: Christian Brauner, Dave Hansen, Vlastimil Babka,
linux-kernel@vger.kernel.org, workflows@vger.kernel.org,
ksummit@lists.linux.dev, Steven Rostedt, Williams, Dan J,
Theodore Ts'o, Sasha Levin, Jonathan Corbet, Kees Cook,
Greg Kroah-Hartman, Miguel Ojeda, Shuah Khan
In-Reply-To: <CAHk-=wgEPve=BO=SOmgEOd4kv76bSbm0jWFzRzcs4Y7EedpgfA@mail.gmail.com>
> I think we should treat any AI generated patches similarly: people
> should mention the tool it was done with, and the script (ok, the
> "scripts" are called "prompts", because AI is so "special") used.
AI is also special in that it is effectively non-deterministic. You probably won't get
the same output from the same prompt.
Maybe still helpful to include the prompt, but it has less utility that a
sed or coccinelle script.
-Tony
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Mike Rapoport @ 2025-11-10 18:39 UTC (permalink / raw)
To: Linus Torvalds
Cc: Laurent Pinchart, Christian Brauner, Dave Hansen, Vlastimil Babka,
linux-kernel, workflows@vger.kernel.org, ksummit@lists.linux.dev,
Steven Rostedt, Dan Williams, Theodore Ts'o, Sasha Levin,
Jonathan Corbet, Kees Cook, Greg Kroah-Hartman, Miguel Ojeda,
Shuah Khan
In-Reply-To: <CAHk-=wgEPve=BO=SOmgEOd4kv76bSbm0jWFzRzcs4Y7EedpgfA@mail.gmail.com>
On Mon, Nov 10, 2025 at 09:44:00AM -0800, Linus Torvalds wrote:
> On Mon, 10 Nov 2025 at 09:25, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Mechanical transformations are often performed with Coccinelle. Given
> > how you mention that tool below, I wouldn't frame it as out of scope
> > here.
>
> Honestly, I think the documented rule should not aim to treat AI as
> anything special at all, and literally just talk about tooling.
>
> I think we should treat any AI generated patches similarly: people
> should mention the tool it was done with, and the script (ok, the
> "scripts" are called "prompts", because AI is so "special") used.
>
> Sure, AI ends up making the result potentially much more subtle, but I
> don't think the *issue* is new, and I don't think it should need to be
> treated as such.
The novelty here is that AI does not only transform the code, it can
generate it from scratch en masse.
> Linus
>
--
Sincerely yours,
Mike.
^ permalink raw reply
* Re: [PATCH] [v2] Documentation: Provide guidelines for tool-generated content
From: Linus Torvalds @ 2025-11-10 19:05 UTC (permalink / raw)
To: Mike Rapoport
Cc: Laurent Pinchart, Christian Brauner, Dave Hansen, Vlastimil Babka,
linux-kernel, workflows@vger.kernel.org, ksummit@lists.linux.dev,
Steven Rostedt, Dan Williams, Theodore Ts'o, Sasha Levin,
Jonathan Corbet, Kees Cook, Greg Kroah-Hartman, Miguel Ojeda,
Shuah Khan
In-Reply-To: <aRIxYkjX7EzalSoI@kernel.org>
On Mon, 10 Nov 2025 at 10:39, Mike Rapoport <rppt@kernel.org> wrote:
>
> The novelty here is that AI does not only transform the code, it can
> generate it from scratch en masse.
And why would that make any difference to the basic rules for us?
"Plus ça change, plus c'est la même chose"
It's a change in degree, not in any fundamentals.
Linus
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox