Skip to content

Commit

Permalink
tracing/timerlat: Only clear timer if a kthread exists
Browse files Browse the repository at this point in the history
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/[email protected]/

Cc: [email protected]
Cc: Masami Hiramatsu <[email protected]>
Cc: Mathieu Desnoyers <[email protected]>
Cc: "Luis Claudio R. Goncalves" <[email protected]>
Link: https://lore.kernel.org/[email protected]
Fixes: e88ed22 ("tracing/timerlat: Add user-space interface")
Reported-by: Tomas Glozar <[email protected]>
Signed-off-by: Steven Rostedt (Google) <[email protected]>
  • Loading branch information
rostedt committed Sep 5, 2024
1 parent 177e1cc commit e6a5348
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions kernel/trace/trace_osnoise.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,21 +252,32 @@ static inline struct timerlat_variables *this_cpu_tmr_var(void)
return this_cpu_ptr(&per_cpu_timerlat_var);
}

/*
* Protect the interface.
*/
static struct mutex interface_lock;

/*
* tlat_var_reset - Reset the values of the given timerlat_variables
*/
static inline void tlat_var_reset(void)
{
struct timerlat_variables *tlat_var;
int cpu;

/* Synchronize with the timerlat interfaces */
mutex_lock(&interface_lock);
/*
* So far, all the values are initialized as 0, so
* zeroing the structure is perfect.
*/
for_each_cpu(cpu, cpu_online_mask) {
tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu);
if (tlat_var->kthread)
hrtimer_cancel(&tlat_var->timer);
memset(tlat_var, 0, sizeof(*tlat_var));
}
mutex_unlock(&interface_lock);
}
#else /* CONFIG_TIMERLAT_TRACER */
#define tlat_var_reset() do {} while (0)
Expand Down Expand Up @@ -331,11 +342,6 @@ struct timerlat_sample {
};
#endif

/*
* Protect the interface.
*/
static struct mutex interface_lock;

/*
* Tracer data.
*/
Expand Down Expand Up @@ -2591,7 +2597,8 @@ static int timerlat_fd_release(struct inode *inode, struct file *file)
osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu);
tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu);

hrtimer_cancel(&tlat_var->timer);
if (tlat_var->kthread)
hrtimer_cancel(&tlat_var->timer);
memset(tlat_var, 0, sizeof(*tlat_var));

osn_var->sampling = 0;
Expand Down

0 comments on commit e6a5348

Please sign in to comment.