Skip to content

Commit 460f1f8

Browse files
rostedtgregkh
authored andcommitted
tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing
commit 9913d57 upstream. All internal use cases for tracepoint_probe_register() is set to not ever be called with the same function and data. If it is, it is considered a bug, as that means the accounting of handling tracepoints is corrupted. If the function and data for a tracepoint is already registered when tracepoint_probe_register() is called, it will call WARN_ON_ONCE() and return with EEXISTS. The BPF system call can end up calling tracepoint_probe_register() with the same data, which now means that this can trigger the warning because of a user space process. As WARN_ON_ONCE() should not be called because user space called a system call with bad data, there needs to be a way to register a tracepoint without triggering a warning. Enter tracepoint_probe_register_may_exist(), which can be called, but will not cause a WARN_ON() if the probe already exists. It will still error out with EEXIST, which will then be sent to the user space that performed the BPF system call. This keeps the previous testing for issues with other users of the tracepoint code, while letting BPF call it with duplicated data and not warn about it. Link: https://lore.kernel.org/lkml/[email protected]/ Link: https://syzkaller.appspot.com/bug?id=41f4318cf01762389f4d1c1c459da4f542fe5153 Cc: [email protected] Fixes: c4f6699 ("bpf: introduce BPF_RAW_TRACEPOINT") Reported-by: syzbot <[email protected]> Reported-by: Tetsuo Handa <[email protected]> Tested-by: [email protected] Signed-off-by: Steven Rostedt (VMware) <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7267f2a commit 460f1f8

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

include/linux/tracepoint.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,17 @@ extern int
4141
tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data,
4242
int prio);
4343
extern int
44+
tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data,
45+
int prio);
46+
extern int
4447
tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
48+
static inline int
49+
tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe,
50+
void *data)
51+
{
52+
return tracepoint_probe_register_prio_may_exist(tp, probe, data,
53+
TRACEPOINT_DEFAULT_PRIO);
54+
}
4555
extern void
4656
for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv),
4757
void *priv);

kernel/trace/bpf_trace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2143,7 +2143,8 @@ static int __bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *
21432143
if (prog->aux->max_tp_access > btp->writable_size)
21442144
return -EINVAL;
21452145

2146-
return tracepoint_probe_register(tp, (void *)btp->bpf_func, prog);
2146+
return tracepoint_probe_register_may_exist(tp, (void *)btp->bpf_func,
2147+
prog);
21472148
}
21482149

21492150
int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)

kernel/tracepoint.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ static void tracepoint_update_call(struct tracepoint *tp, struct tracepoint_func
273273
* Add the probe function to a tracepoint.
274274
*/
275275
static int tracepoint_add_func(struct tracepoint *tp,
276-
struct tracepoint_func *func, int prio)
276+
struct tracepoint_func *func, int prio,
277+
bool warn)
277278
{
278279
struct tracepoint_func *old, *tp_funcs;
279280
int ret;
@@ -288,7 +289,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
288289
lockdep_is_held(&tracepoints_mutex));
289290
old = func_add(&tp_funcs, func, prio);
290291
if (IS_ERR(old)) {
291-
WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
292+
WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM);
292293
return PTR_ERR(old);
293294
}
294295

@@ -343,6 +344,32 @@ static int tracepoint_remove_func(struct tracepoint *tp,
343344
return 0;
344345
}
345346

347+
/**
348+
* tracepoint_probe_register_prio_may_exist - Connect a probe to a tracepoint with priority
349+
* @tp: tracepoint
350+
* @probe: probe handler
351+
* @data: tracepoint data
352+
* @prio: priority of this function over other registered functions
353+
*
354+
* Same as tracepoint_probe_register_prio() except that it will not warn
355+
* if the tracepoint is already registered.
356+
*/
357+
int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe,
358+
void *data, int prio)
359+
{
360+
struct tracepoint_func tp_func;
361+
int ret;
362+
363+
mutex_lock(&tracepoints_mutex);
364+
tp_func.func = probe;
365+
tp_func.data = data;
366+
tp_func.prio = prio;
367+
ret = tracepoint_add_func(tp, &tp_func, prio, false);
368+
mutex_unlock(&tracepoints_mutex);
369+
return ret;
370+
}
371+
EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist);
372+
346373
/**
347374
* tracepoint_probe_register_prio - Connect a probe to a tracepoint with priority
348375
* @tp: tracepoint
@@ -366,7 +393,7 @@ int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe,
366393
tp_func.func = probe;
367394
tp_func.data = data;
368395
tp_func.prio = prio;
369-
ret = tracepoint_add_func(tp, &tp_func, prio);
396+
ret = tracepoint_add_func(tp, &tp_func, prio, true);
370397
mutex_unlock(&tracepoints_mutex);
371398
return ret;
372399
}

0 commit comments

Comments
 (0)