From: sashiko-bot@kernel.org
To: "Jinchao Wang" <wangjinchao600@gmail.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [RFC PATCH v2 09/13] mm/kwatch: add probe lifecycle runtime
Date: Fri, 17 Jul 2026 13:20:00 +0000 [thread overview]
Message-ID: <20260717132000.D61631F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260717130544.1903146-1-wangjinchao600@gmail.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Use-After-Free and data race in `kwatch_probe_validate_hit()` during session teardown.
- [High] Mid-function offset kprobes incorrectly inherit NMI context rejection, bypassing safety policies.
- [High] Tasks terminating abnormally leak hardware watchpoints and cause pointer ABA vulnerabilities in the lockless context pool.
- [Medium] Race condition causing false NMI context rejections due to uninitialized delivery flag.
- [Low] Unused macro definition `TRAMPOLINE_CHECK_DEPTH`.
--
--- Patch [9]: [RFC PATCH v2 09/13] mm/kwatch: add probe lifecycle runtime ---
commit 4c4a554ca5428e6d0dbf3c8593ac5647b9e7d585
Author: Jinchao Wang <wangjinchao600@gmail.com>
Subject: mm/kwatch: add probe lifecycle runtime
This commit introduces the probe lifecycle runtime for the watch window using a
kretprobe. It handles function entry and exit, tracks nesting depth to manage
hardware watchpoints, and includes logic for NMI rejection and epoch versioning.
> diff --git a/mm/kwatch/probe.c b/mm/kwatch/probe.c
> new file mode 100644
> index 0000000000000..249aa50c9f782
> --- /dev/null
> +++ b/mm/kwatch/probe.c
> @@ -0,0 +1,275 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/atomic.h>
> +#include <linux/kprobes.h>
> +#include <linux/kallsyms.h>
> +#include <linux/percpu.h>
> +#include <linux/preempt.h>
> +#include <linux/sched.h>
> +
> +#include "kwatch.h"
> +#define TRAMPOLINE_CHECK_DEPTH 16
[Severity: Low]
Is this macro used anywhere in the codebase?
[ ... ]
> +static void kwatch_pin_post_handler(struct kprobe *p, struct pt_regs *regs,
> + unsigned long flags)
> +{
> + /* a post_handler pins the probepoint: no jump optimization */
> +}
> +
> +bool kwatch_probe_validate_hit(struct pt_regs *regs,
> + struct task_struct *arm_tsk)
> +{
> + struct kwatch_tsk_ctx *ctx = kwatch_tsk_ctx_get(false);
> + const struct kwatch_config *cfg = kwatch_probe_ctx.cfg;
[Severity: Critical]
If a session is stopped, kwatch_probe_stop() resets the epoch but does not
synchronously disarm hardware watchpoints for tasks still executing inside the
probed function.
Could a leftover watchpoint firing later cause this handler path to locklessly
dereference a freed cfg pointer?
Additionally, if a new session starts concurrently, kwatch_probe_start()
clears the context via memset:
kwatch_probe_start() {
...
memset(&kwatch_probe_ctx, 0, sizeof(kwatch_probe_ctx));
...
}
Might this result in a torn or null pointer dereference here if a hardware
watchpoint fires during the memset?
[ ... ]
> +static int kwatch_activate_handler(struct kprobe *p, struct pt_regs *regs)
> +{
> + struct kwatch_tsk_ctx *ctx = kwatch_tsk_ctx_get(false);
> + unsigned long watch_addr;
> + u16 watch_len;
> +
> + if (unlikely(!ctx))
> + return 0;
> +
> + if (unlikely(kwatch_probe_is_muted()))
> + return 0;
> +
> + if (unlikely(!kwatch_tsk_ctx_check(KWATCH_PROBE_POSITION_ACTIVE)))
> + return 0;
> +
> + if (ctx->depth != kwatch_probe_ctx.cfg->depth + 1 || ctx->wp)
> + return 0;
[Severity: High]
Could an NMI interrupt the probed function after the outer invocation has
already incremented ctx->depth, and then recursively call the same probed
function?
Since kwatch_lifecycle_entry() deliberately skips the ctx->depth increment
for rejected NMIs, would this mid-function offset kprobe falsely pass the
check by reading the outer context's depth and incorrectly arm the hardware
watchpoint using NMI register state?
[ ... ]
> +static int kwatch_lifecycle_entry(struct kretprobe_instance *ri,
> + struct pt_regs *regs)
> +{
> + /*
> + * Single policy point: the target function's context is judged once
> + * here. A rejected invocation never increments depth, so the offset
> + * kprobe path inherits the verdict through the depth check.
> + */
> + if (unlikely(kwatch_probed_ctx_in_nmi(kwatch_probe_ctx.rp_via_int3))) {
> + atomic_long_inc(&kwatch_nmi_rejected);
> + return 1; /* NMI context is unsupported: no window, no return hook */
> + }
[Severity: Medium]
Is there a race window here where rp_via_int3 is read before being
initialized?
kwatch_probe_start() registers the kretprobe, which enables this function to
intercept calls across all CPUs, but it initializes rp_via_int3 slightly
after:
kwatch_probe_start() {
...
ret = register_kretprobe(&kwatch_probe_ctx.rp);
if (ret < 0) {
...
}
kwatch_probe_ctx.rp_via_int3 = !kprobe_ftrace(&kwatch_probe_ctx.rp.kp);
...
}
If another CPU hits this probe before rp_via_int3 is set, might it evaluate
as false and misclassify a normal trap context as an NMI if the architecture
uses int3 for delivery?
[ ... ]
> +static int kwatch_lifecycle_exit(struct kretprobe_instance *ri,
> + struct pt_regs *regs)
> +{
> + struct kwatch_tsk_ctx *ctx = kwatch_tsk_ctx_get(false);
[Severity: High]
If a task is killed by a fatal signal (like SIGKILL) or calls do_exit()
directly while inside the probed function, it bypasses this kretprobe exit
handler.
Does this permanently leak the hardware watchpoint assigned to ctx->wp?
Furthermore, kwatch_tsk_ctx_get() matches raw pointers for the active task:
mm/kwatch/task_ctx.c:kwatch_tsk_ctx_get() {
...
t = READ_ONCE(kwatch_ctx_pool[idx].task);
if (t == current)
return &kwatch_ctx_pool[idx];
...
}
If the slab allocator reuses the dead task's task_struct memory address for a
new task, will the new task erroneously inherit the corrupted state and leaked
watchpoint from the pool?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260717125023.1895892-1-wangjinchao600@gmail.com?part=9
next prev parent reply other threads:[~2026-07-17 13:20 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 12:50 [RFC PATCH v2 00/13] mm/kwatch: dynamic hardware watchpoints for hunting memory corruption Jinchao Wang
2026-07-17 13:02 ` [RFC PATCH v2 01/13] arch: add HAVE_REINSTALL_HW_BREAKPOINT Jinchao Wang
2026-07-17 13:02 ` [RFC PATCH v2 02/13] x86/hw_breakpoint: Unify breakpoint install/uninstall Jinchao Wang
2026-07-17 13:15 ` sashiko-bot
2026-07-17 13:03 ` [RFC PATCH v2 03/13] x86/hw_breakpoint: Add arch_reinstall_hw_breakpoint Jinchao Wang
2026-07-17 13:03 ` [RFC PATCH v2 04/13] HWBP: Add modify_wide_hw_breakpoint_local() API Jinchao Wang
2026-07-17 13:21 ` sashiko-bot
2026-07-17 13:04 ` [RFC PATCH v2 05/13] mm/kwatch: add watch expression parser and dereference engine Jinchao Wang
2026-07-17 13:15 ` sashiko-bot
2026-07-17 13:04 ` [RFC PATCH v2 06/13] mm/kwatch: add lockless per-task context pool Jinchao Wang
2026-07-17 13:19 ` sashiko-bot
2026-07-17 13:04 ` [RFC PATCH v2 07/13] stacktrace: export stack_trace_save_regs() Jinchao Wang
2026-07-17 13:05 ` [RFC PATCH v2 08/13] mm/kwatch: add hardware breakpoint backend Jinchao Wang
2026-07-17 13:24 ` sashiko-bot
2026-07-17 13:05 ` [RFC PATCH v2 09/13] mm/kwatch: add probe lifecycle runtime Jinchao Wang
2026-07-17 13:20 ` sashiko-bot [this message]
2026-07-17 13:06 ` [RFC PATCH v2 10/13] mm/kwatch: add anchor thread for global watchpoints Jinchao Wang
2026-07-17 13:20 ` sashiko-bot
2026-07-17 13:06 ` [RFC PATCH v2 11/13] mm/kwatch: add debugfs control plane Jinchao Wang
2026-07-17 13:27 ` sashiko-bot
2026-07-17 13:07 ` [RFC PATCH v2 12/13] mm/kwatch: add KUnit tests for the watch expression parser Jinchao Wang
2026-07-17 13:07 ` [RFC PATCH v2 13/13] Documentation/dev-tools: document KWatch Jinchao Wang
2026-07-17 13:30 ` sashiko-bot
2026-07-17 13:41 ` [RFC PATCH v2 00/13] mm/kwatch: dynamic hardware watchpoints for hunting memory corruption Dave Hansen
2026-07-17 18:10 ` Borislav Petkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260717132000.D61631F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=wangjinchao600@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.