Linux Trace Kernel
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: wen.yang@linux.dev
Cc: linux-trace-kernel@vger.kernel.org
Subject: Re: [PATCH v7 11/14] rv: Add tlob hybrid automaton monitor
Date: Sun, 11 Oct 2026 19:58:07 +0000	[thread overview]
Message-ID: <sashiko-outbox-167433@kernel.org> (raw)
In-Reply-To: <96c7ee8abbe9b9b840ca6e112744b5c74f0e9b8f.1791745088.git.wen.yang@linux.dev>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] rv: TOCTOU race in ha_setup_invariants allows hrtimer Use-After-Free
- [High] rv: deadlock in tlob_binding_lock between process context and RCU softirq
- [High] rv: tlob: list corruption due to lockless da_destroy_storage() calls
- [Medium] rv: race between tlob_stop_task and timer callback causes INVALID_STATE error
--

commit 90ea80dda3503cc5ac796d8401bafbbd97a373b9
Author: Wen Yang <wen.yang@linux.dev>

rv: Add tlob hybrid automaton monitor

tlob (task latency over budget) is a per-task hybrid automaton RV
monitor that tracks wall-clock time across a user-delimited code
section and emits an error when the elapsed time exceeds a configurable
budget.

> diff --git a/kernel/trace/rv/monitors/tlob/tlob.c b/kernel/trace/rv/monitors/tlob/tlob.c
> --- /dev/null
> +++ b/kernel/trace/rv/monitors/tlob/tlob.c
[ ... ]
> +static inline void tlob_detach_from_binding(struct tlob_record *rec)
> +{
> +	guard(spinlock)(&tlob_binding_lock);
> +
> +	if (!rec->binding)
> +		return;
> +	rec->binding = NULL;
> +	list_del_init(&rec->started_node);
> +}
> +
> +/*
> + * Per-record teardown during monitor disable.  TLOB_RETIRED claims it, so an
> + * exit or unbind racing disable frees the record once.
> + */
> +static inline void tlob_extra_cleanup(struct da_monitor *da_mon)
> +{
> +	struct ha_monitor *ha_mon = to_ha_monitor(da_mon);
> +	struct tlob_record *rec = ha_get_target(ha_mon);
> +
> +	if (!rec)
> +		return;
> +
> +	if (atomic_xchg(&rec->state, TLOB_RETIRED) == TLOB_RETIRED)
> +		return;
> +
> +	tlob_detach_from_binding(rec);
> +	call_rcu(&rec->rcu, tlob_rec_return_cb);
> +}

[Severity: High]
Does this lock acquisition risk a deadlock between process context and RCU
softirq?

The tlob_binding_lock is acquired in process context functions like
tlob_start_task() using scoped_guard(spinlock, &tlob_binding_lock), which
does not disable softirqs.

During monitor teardown, the RV framework's da_destroy_storage() frees the
monitor record via call_rcu(). The RCU callback executes in RCU_SOFTIRQ
context and invokes tlob_extra_cleanup(), which calls
tlob_detach_from_binding() and acquires the same lock.

If a process holding the lock is interrupted by the RCU softirq on the same
CPU, the softirq will deadlock attempting to acquire it. Should
tlob_binding_lock be acquired using spin_lock_bh() in all process-context
paths?

[ ... ]
> +static inline void ha_setup_invariants(struct ha_monitor *ha_mon,
> +				       enum states curr_state,
> +				       enum events event,
> +				       enum states next_state,
> +				       u64 time_ns)
> +{
> +	struct tlob_record *rec = ha_get_target(ha_mon);
> +
> +	if (next_state == stopped_tlob)
> +		return;
> +
> +	if (next_state >= state_max_tlob) {
> +		ha_cancel_timer(ha_mon);
> +		return;
> +	}
> +
> +	if (event != start_tlob) {
> +		/* A sched event racing the window end must not re-arm. */
> +		if (atomic_read_acquire(&rec->state) != TLOB_OPEN)
> +			return;
> +		ha_start_timer_ns(ha_mon, clk_elapsed_tlob,
> +				  BUDGET_NS(ha_mon), time_ns);
> +		return;
> +	}
> +
> +	ha_reset_clk_ns(ha_mon, clk_elapsed_tlob, time_ns);
> +	ha_start_timer_ns(ha_mon, clk_elapsed_tlob, BUDGET_NS(ha_mon),
> +			  time_ns);
> +	/* Reopen only a closed record; a teardown claim keeps it closed. */
> +	atomic_cmpxchg_release(&rec->state, TLOB_CLOSED, TLOB_OPEN);
> +}

[Severity: Critical]
Can this sequence allow a use-after-free of the hrtimer?

There appears to be a race between the state check and arming the timer.
A teardown path can concurrently claim the record by setting its state to
TLOB_RETIRED, cancel the timer, and queue the record for freeing via
call_rcu().

If the teardown occurs between ha_setup_invariants() checking the state and
calling ha_start_timer_ns(), the timer will be freshly re-armed on a record
that has already been queued for destruction.

Even in the start_tlob path, ha_start_timer_ns() is called unconditionally
before atomic_cmpxchg_release(). If the cmpxchg fails because of a
concurrent teardown, the armed timer is never rolled back.

Once the RCU grace period elapses, the record is freed. The still-armed
timer remains on the hrtimer rbtree, leading to a use-after-free when it
expires.

[ ... ]
> +static void tlob_stop_task(struct task_struct *task,
> +			   struct tlob_uprobe_binding *binding)
> +{
> +	struct ha_monitor *ha_mon;
> +	struct tlob_record *rec;
> +
> +	scoped_guard(rcu) {
> +		ha_mon = ha_get_monitor(task->pid, NULL);
> +		if (!ha_mon)
> +			return;
> +
> +		rec = ha_get_target(ha_mon);
> +		if (WARN_ON_ONCE(!rec))
> +			return;
> +
> +		/* Only the opener may end it; NULL (task exit) skips. */
> +		if (binding && READ_ONCE(rec->binding) != binding)
> +			return;
> +
> +		/* Claim the window end; the timer may have taken it first. */
> +		if (atomic_cmpxchg_release(&rec->state, TLOB_OPEN,
> +					   TLOB_CLOSED) != TLOB_OPEN)
> +			return;
> +
> +		ha_cancel_timer_sync(ha_mon);
> +	}
> +
> +	/* The DA returns to stopped; the record stays closed. */
> +	da_handle_event(task->pid, NULL, stop_tlob);
> +}

[Severity: Medium]
Will this result in an invalid state error if tlob_stop_task() races with
the timer callback?

tlob_stop_task() claims the window closure and then calls
ha_cancel_timer_sync(). If the hrtimer just expired and its callback is
running concurrently on another CPU, ha_cancel_timer_sync() spin-waits for
it to complete.

The generic timer callback will unconditionally emit a budget violation error
and reset the automaton to stopped_tlob. After ha_cancel_timer_sync()
returns, tlob_stop_task() injects the stop_tlob event.

Since the automaton defines stop_tlob from the stopped_tlob state as
invalid, this causes the framework to incorrectly flag an invalid transition
despite tlob_stop_task() legitimately ending the window.

[ ... ]
> +static void tlob_destroy_claimed(struct tlob_record *rec)
> +{
> +	pid_t id = rec->id;
> +
> +	tlob_detach_from_binding(rec);
> +
> +	scoped_guard(rcu) {
> +		struct ha_monitor *ha_mon = ha_get_monitor(id, NULL);
> +
> +		if (!WARN_ON_ONCE(!ha_mon))
> +			da_monitor_reset(&ha_mon->da_mon);
> +	}
> +	da_destroy_storage(id);
> +
> +	/* Readers may still hold rec; the pool slot returns after a GP. */
> +	call_rcu(&rec->rcu, tlob_rec_return_cb);
> +}

[Severity: High]
Does this code corrupt the hash table list pointers?

da_monitor_ht is a global hash table without internal locking. The function
da_destroy_storage() uses hash_del_rcu(), which modifies hlist pointers and
requires the caller to hold a writer lock to serialize against concurrent
writers.

While tlob_start_task() acquires tlob_binding_lock to serialize additions,
tlob_destroy_claimed() and the error path of tlob_start_task() call
da_destroy_storage() without holding tlob_binding_lock or any other
bucket-level lock.

Concurrent task exits or unbind operations that map to the same hash bucket
could corrupt the hash table's linked list.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791745088.git.wen.yang@linux.dev?part=11

  reply	other threads:[~2026-10-11 19:58 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-11 19:39 [PATCH v7 00/14] rv: Add task latency over budget RV monitor wen.yang
2026-10-11 19:39 ` [PATCH v7 01/14] rv: Force environment reset action on HA monitor start wen.yang
2026-10-11 19:39 ` [PATCH v7 02/14] rv: Fix ha_monitor timer and invariant underflow wen.yang
2026-10-11 19:39 ` [PATCH v7 03/14] rv: Add a KUnit test for the HA timer underflow wen.yang
2026-10-11 19:52   ` sashiko-bot
2026-10-12  7:47   ` kernel test robot
2026-10-12  9:27   ` kernel test robot
2026-10-12 11:18   ` kernel test robot
2026-10-11 19:39 ` [PATCH v7 04/14] rv: Disarm HA timers on the storage free path wen.yang
2026-10-11 19:51   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 05/14] rv: Add a KUnit test for " wen.yang
2026-10-11 19:50   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 06/14] rv: Make da_monitor_reset_hook and EVENT_NONE_LBL overridable wen.yang
2026-10-11 19:53   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 07/14] rv: Introduce DA_MON_ALLOCATION_STRATEGY wen.yang
2026-10-11 19:57   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 08/14] rv: Add per-object teardown hook da_extra_cleanup wen.yang
2026-10-11 19:54   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 09/14] rv: Add generic uprobe infrastructure for RV monitors wen.yang
2026-10-11 19:49   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 10/14] rv: Add tlob model DOT file wen.yang
2026-10-11 19:39 ` [PATCH v7 11/14] rv: Add tlob hybrid automaton monitor wen.yang
2026-10-11 19:58   ` sashiko-bot [this message]
2026-10-11 19:39 ` [PATCH v7 12/14] rv: Add KUnit tests for the tlob monitor wen.yang
2026-10-11 19:39 ` [PATCH v7 13/14] selftests/verification: Add tlob selftests wen.yang
2026-10-11 19:51   ` sashiko-bot
2026-10-11 19:39 ` [PATCH v7 14/14] selftests/ftrace: Walk up parent dirs to find test.d/functions wen.yang
2026-10-12 11:58 ` [PATCH v7 00/14] rv: Add task latency over budget RV monitor Gabriele Monaco

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=sashiko-outbox-167433@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=wen.yang@linux.dev \
    /path/to/YOUR_REPLY

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

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