Re: [PATCH v5] tracepoint: Do not fail unregistering a probe due to memory failure

From: Alexey Kardashevskiy
Date: Sat Jan 30 2021 - 07:35:12 EST




On 28/01/2021 09:07, Steven Rostedt wrote:
From: "Steven Rostedt (VMware)" <rostedt@xxxxxxxxxxx>

The list of tracepoint callbacks is managed by an array that is protected
by RCU. To update this array, a new array is allocated, the updates are
copied over to the new array, and then the list of functions for the
tracepoint is switched over to the new array. After a completion of an RCU
grace period, the old array is freed.

This process happens for both adding a callback as well as removing one.
But on removing a callback, if the new array fails to be allocated, the
callback is not removed, and may be used after it is freed by the clients
of the tracepoint.

The handling of a failed allocation for removing an event can break use
cases as the error report is not propagated up to the original callers. To
make matters worse, there's some paths that can not handle error cases.

Instead of allocating a new array for removing a tracepoint, allocate twice
the needed size when adding tracepoints to the array. On removing, use the
second half of the allocated array. This removes the need to allocate memory
for removing a tracepoint, as the allocation for removals will already have
been done.

Link: https://lkml.kernel.org/r/20201115055256.65625-1-mmullins@xxxxxxx
Link: https://lkml.kernel.org/r/20201116175107.02db396d@xxxxxxxxxxxxxxxxxx
Link: https://lkml.kennel.org/r/20201118093405.7a6d2290@xxxxxxxxxxxxxxxxxx

Reported-by: Matt Mullins <mmullins@xxxxxxx>
Signed-off-by: Steven Rostedt (VMware) <rostedt@xxxxxxxxxxx>


I still need the following chunk (same "if (it_func_ptr)" as in the v2's reply) in order to stop crashes:



diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 82eba6a05a1c..b7cf7a5a4f43 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -311,6 +311,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
\
it_func_ptr = \

rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
+ if (it_func_ptr) \
do { \
it_func = (it_func_ptr)->func; \
__data = (it_func_ptr)->data; \




--
Alexey