Skip to content

Commit 0c5c89e

Browse files
rostedtyhamamachi
authored andcommitted
tracing/timerlat: Only clear timer if a kthread exists
The timerlat tracer can use user space threads to check for osnoise and timer latency. If the program using this is killed via a SIGTERM, the threads are shutdown one at a time and another tracing instance can start up resetting the threads before they are fully closed. That causes the hrtimer assigned to the kthread to be shutdown and freed twice when the dying thread finally closes the file descriptors, causing a use-after-free bug. Only cancel the hrtimer if the associated thread is still around. Also add the interface_lock around the resetting of the tlat_var->kthread. Note, this is just a quick fix that can be backported to stable. A real fix is to have a better synchronization between the shutdown of old threads and the starting of new ones. Link: https://lore.kernel.org/all/20240820130001.124768-1-tglozar@redhat.com/ Cc: stable@vger.kernel.org Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: "Luis Claudio R. Goncalves" <lgoncalv@redhat.com> Link: https://lore.kernel.org/20240905085330.45985730@gandalf.local.home Fixes: e88ed22 ("tracing/timerlat: Add user-space interface") Reported-by: Tomas Glozar <tglozar@redhat.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 782f336 commit 0c5c89e

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

kernel/trace/trace_osnoise.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,21 +252,32 @@ static inline struct timerlat_variables *this_cpu_tmr_var(void)
252252
return this_cpu_ptr(&per_cpu_timerlat_var);
253253
}
254254

255+
/*
256+
* Protect the interface.
257+
*/
258+
static struct mutex interface_lock;
259+
255260
/*
256261
* tlat_var_reset - Reset the values of the given timerlat_variables
257262
*/
258263
static inline void tlat_var_reset(void)
259264
{
260265
struct timerlat_variables *tlat_var;
261266
int cpu;
267+
268+
/* Synchronize with the timerlat interfaces */
269+
mutex_lock(&interface_lock);
262270
/*
263271
* So far, all the values are initialized as 0, so
264272
* zeroing the structure is perfect.
265273
*/
266274
for_each_cpu(cpu, cpu_online_mask) {
267275
tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu);
276+
if (tlat_var->kthread)
277+
hrtimer_cancel(&tlat_var->timer);
268278
memset(tlat_var, 0, sizeof(*tlat_var));
269279
}
280+
mutex_unlock(&interface_lock);
270281
}
271282
#else /* CONFIG_TIMERLAT_TRACER */
272283
#define tlat_var_reset() do {} while (0)
@@ -331,11 +342,6 @@ struct timerlat_sample {
331342
};
332343
#endif
333344

334-
/*
335-
* Protect the interface.
336-
*/
337-
static struct mutex interface_lock;
338-
339345
/*
340346
* Tracer data.
341347
*/
@@ -2591,7 +2597,8 @@ static int timerlat_fd_release(struct inode *inode, struct file *file)
25912597
osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu);
25922598
tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu);
25932599

2594-
hrtimer_cancel(&tlat_var->timer);
2600+
if (tlat_var->kthread)
2601+
hrtimer_cancel(&tlat_var->timer);
25952602
memset(tlat_var, 0, sizeof(*tlat_var));
25962603

25972604
osn_var->sampling = 0;

0 commit comments

Comments
 (0)