[PATCH] trace/trace_stat: fix a race condition in register_stat_tracer

From: Luis Henriques
Date: Tue Sep 09 2014 - 17:49:44 EST


A race condition exits (at least theoretically) if a tracer_stat
registration is interrupted after verifying it hasn't been registered yet
but before being added to the all_stat_sessions list.

This patch fixes this race by making both operations atomic (protected by
the all_stat_sessions_mutex mutex).

Signed-off-by: Luis Henriques <luis.henriques@xxxxxxxxxxxxx>
---
kernel/trace/trace_stat.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 7af67360b330..cb70ac12cfe4 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -310,16 +310,6 @@ int register_stat_tracer(struct tracer_stat *trace)
if (!trace->stat_start || !trace->stat_next || !trace->stat_show)
return -EINVAL;

- /* Already registered? */
- mutex_lock(&all_stat_sessions_mutex);
- list_for_each_entry(node, &all_stat_sessions, session_list) {
- if (node->ts == trace) {
- mutex_unlock(&all_stat_sessions_mutex);
- return -EINVAL;
- }
- }
- mutex_unlock(&all_stat_sessions_mutex);
-
/* Init the session */
session = kzalloc(sizeof(*session), GFP_KERNEL);
if (!session)
@@ -337,10 +327,21 @@ int register_stat_tracer(struct tracer_stat *trace)

/* Register */
mutex_lock(&all_stat_sessions_mutex);
+ /* Already registered? */
+ list_for_each_entry(node, &all_stat_sessions, session_list) {
+ if (node->ts == trace) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
list_add_tail(&session->session_list, &all_stat_sessions);
+
+out:
mutex_unlock(&all_stat_sessions_mutex);
+ if (ret)
+ destroy_session(session);

- return 0;
+ return ret;
}

void unregister_stat_tracer(struct tracer_stat *trace)
--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/