Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing

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/20210626135845.4080-1-penguin-kernel@I-love.SAKURA.ne.jp/
Link: https://syzkaller.appspot.com/bug?id=41f4318cf01762389f4d1c1c459da4f542fe5153

Cc: stable@vger.kernel.org
Fixes: c4f6699dfcb85 ("bpf: introduce BPF_RAW_TRACEPOINT")
Reported-by: syzbot <syzbot+721aa903751db87aa244@syzkaller.appspotmail.com>
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Tested-by: syzbot+721aa903751db87aa244@syzkaller.appspotmail.com
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

+42 -4
+10
include/linux/tracepoint.h
··· 41 41 tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, 42 42 int prio); 43 43 extern int 44 + tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, 45 + int prio); 46 + extern int 44 47 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 + } 45 55 extern void 46 56 for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), 47 57 void *priv);
+2 -1
kernel/trace/bpf_trace.c
··· 1840 1840 if (prog->aux->max_tp_access > btp->writable_size) 1841 1841 return -EINVAL; 1842 1842 1843 - return tracepoint_probe_register(tp, (void *)btp->bpf_func, prog); 1843 + return tracepoint_probe_register_may_exist(tp, (void *)btp->bpf_func, 1844 + prog); 1844 1845 } 1845 1846 1846 1847 int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
+30 -3
kernel/tracepoint.c
··· 273 273 * Add the probe function to a tracepoint. 274 274 */ 275 275 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) 277 278 { 278 279 struct tracepoint_func *old, *tp_funcs; 279 280 int ret; ··· 289 288 lockdep_is_held(&tracepoints_mutex)); 290 289 old = func_add(&tp_funcs, func, prio); 291 290 if (IS_ERR(old)) { 292 - WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); 291 + WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM); 293 292 return PTR_ERR(old); 294 293 } 295 294 ··· 345 344 } 346 345 347 346 /** 347 + * tracepoint_probe_register_prio_may_exist - Connect a probe to a tracepoint with priority 348 + * @tp: tracepoint 349 + * @probe: probe handler 350 + * @data: tracepoint data 351 + * @prio: priority of this function over other registered functions 352 + * 353 + * Same as tracepoint_probe_register_prio() except that it will not warn 354 + * if the tracepoint is already registered. 355 + */ 356 + int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, 357 + void *data, int prio) 358 + { 359 + struct tracepoint_func tp_func; 360 + int ret; 361 + 362 + mutex_lock(&tracepoints_mutex); 363 + tp_func.func = probe; 364 + tp_func.data = data; 365 + tp_func.prio = prio; 366 + ret = tracepoint_add_func(tp, &tp_func, prio, false); 367 + mutex_unlock(&tracepoints_mutex); 368 + return ret; 369 + } 370 + EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist); 371 + 372 + /** 348 373 * tracepoint_probe_register_prio - Connect a probe to a tracepoint with priority 349 374 * @tp: tracepoint 350 375 * @probe: probe handler ··· 393 366 tp_func.func = probe; 394 367 tp_func.data = data; 395 368 tp_func.prio = prio; 396 - ret = tracepoint_add_func(tp, &tp_func, prio); 369 + ret = tracepoint_add_func(tp, &tp_func, prio, true); 397 370 mutex_unlock(&tracepoints_mutex); 398 371 return ret; 399 372 }