Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8058bd0f authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Steven Rostedt
Browse files

tracepoint: Fix use of tracepoint funcs after rcu free

Commit de7b2973 "tracepoint: Use struct pointer instead of name hash
for reg/unreg tracepoints" introduces a use after free by calling
release_probes on the old struct tracepoint array before the newly
allocated array is published with rcu_assign_pointer. There is a race
window where tracepoints (RCU readers) can perform a
"use-after-grace-period-after-free", which shows up as a GPF in
stress-tests.

Link: http://lkml.kernel.org/r/53698021.5020108@oracle.com
Link: http://lkml.kernel.org/p/1399549669-25465-1-git-send-email-mathieu.desnoyers@efficios.com



Reported-by: default avatarSasha Levin <sasha.levin@oracle.com>
CC: Oleg Nesterov <oleg@redhat.com>
CC: Dave Jones <davej@redhat.com>
Fixes: de7b2973 "tracepoint: Use struct pointer instead of name hash for reg/unreg tracepoints"
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 098507ae
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -188,7 +188,6 @@ static int tracepoint_add_func(struct tracepoint *tp,
		WARN_ON_ONCE(1);
		return PTR_ERR(old);
	}
	release_probes(old);

	/*
	 * rcu_assign_pointer has a smp_wmb() which makes sure that the new
@@ -200,6 +199,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
	rcu_assign_pointer(tp->funcs, tp_funcs);
	if (!static_key_enabled(&tp->key))
		static_key_slow_inc(&tp->key);
	release_probes(old);
	return 0;
}

@@ -221,7 +221,6 @@ static int tracepoint_remove_func(struct tracepoint *tp,
		WARN_ON_ONCE(1);
		return PTR_ERR(old);
	}
	release_probes(old);

	if (!tp_funcs) {
		/* Removed last function */
@@ -232,6 +231,7 @@ static int tracepoint_remove_func(struct tracepoint *tp,
			static_key_slow_dec(&tp->key);
	}
	rcu_assign_pointer(tp->funcs, tp_funcs);
	release_probes(old);
	return 0;
}