Skip to content

Commit 9a3236c

Browse files
committed
Merge tag 'probes-fixes-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull probes fixes from Masami Hiramatsu: - Fix fprobe's rethook release issues: - Release rethook after ftrace_ops is unregistered so that the rethook is not accessed after free. - Stop rethook before ftrace_ops is unregistered so that the rethook is NOT used after exiting unregister_fprobe() - Fix eprobe cleanup logic. If it attaches to multiple events and failes to enable one of them, rollback all enabled events correctly. - Fix fprobe to unlock ftrace recursion lock correctly when it missed by another running kprobe. - Cleanup kprobe to remove unnecessary NULL. - Cleanup kprobe to remove unnecessary 0 initializations. * tag 'probes-fixes-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: fprobe: Ensure running fprobe_exit_handler() finished before calling rethook_free() kernel: kprobes: Remove unnecessary ‘0’ values kprobes: Remove unnecessary ‘NULL’ values from correct_ret_addr fprobe: add unlock to match a succeeded ftrace_test_recursion_trylock kernel/trace: Fix cleanup logic of enable_trace_eprobe fprobe: Release rethook after the ftrace_ops is unregistered
2 parents 1d75460 + 195b9cb commit 9a3236c

File tree

5 files changed

+41
-14
lines changed

5 files changed

+41
-14
lines changed

include/linux/rethook.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct rethook_node {
5959
};
6060

6161
struct rethook *rethook_alloc(void *data, rethook_handler_t handler);
62+
void rethook_stop(struct rethook *rh);
6263
void rethook_free(struct rethook *rh);
6364
void rethook_add_node(struct rethook *rh, struct rethook_node *node);
6465
struct rethook_node *rethook_try_get(struct rethook *rh);

kernel/kprobes.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ static int kprobe_ftrace_enabled;
10721072
static int __arm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
10731073
int *cnt)
10741074
{
1075-
int ret = 0;
1075+
int ret;
10761076

10771077
lockdep_assert_held(&kprobe_mutex);
10781078

@@ -1110,7 +1110,7 @@ static int arm_kprobe_ftrace(struct kprobe *p)
11101110
static int __disarm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
11111111
int *cnt)
11121112
{
1113-
int ret = 0;
1113+
int ret;
11141114

11151115
lockdep_assert_held(&kprobe_mutex);
11161116

@@ -2007,9 +2007,9 @@ void __weak arch_kretprobe_fixup_return(struct pt_regs *regs,
20072007
unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
20082008
void *frame_pointer)
20092009
{
2010-
kprobe_opcode_t *correct_ret_addr = NULL;
20112010
struct kretprobe_instance *ri = NULL;
20122011
struct llist_node *first, *node = NULL;
2012+
kprobe_opcode_t *correct_ret_addr;
20132013
struct kretprobe *rp;
20142014

20152015
/* Find correct address and all nodes for this frame. */
@@ -2693,7 +2693,7 @@ void kprobe_free_init_mem(void)
26932693

26942694
static int __init init_kprobes(void)
26952695
{
2696-
int i, err = 0;
2696+
int i, err;
26972697

26982698
/* FIXME allocate the probe table, currently defined statically */
26992699
/* initialize all list heads */

kernel/trace/fprobe.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
102102

103103
if (unlikely(kprobe_running())) {
104104
fp->nmissed++;
105-
return;
105+
goto recursion_unlock;
106106
}
107107

108108
kprobe_busy_begin();
109109
__fprobe_handler(ip, parent_ip, ops, fregs);
110110
kprobe_busy_end();
111+
112+
recursion_unlock:
111113
ftrace_test_recursion_unlock(bit);
112114
}
113115

@@ -371,19 +373,16 @@ int unregister_fprobe(struct fprobe *fp)
371373
if (!fprobe_is_registered(fp))
372374
return -EINVAL;
373375

374-
/*
375-
* rethook_free() starts disabling the rethook, but the rethook handlers
376-
* may be running on other processors at this point. To make sure that all
377-
* current running handlers are finished, call unregister_ftrace_function()
378-
* after this.
379-
*/
380376
if (fp->rethook)
381-
rethook_free(fp->rethook);
377+
rethook_stop(fp->rethook);
382378

383379
ret = unregister_ftrace_function(&fp->ops);
384380
if (ret < 0)
385381
return ret;
386382

383+
if (fp->rethook)
384+
rethook_free(fp->rethook);
385+
387386
ftrace_free_filter(&fp->ops);
388387

389388
return ret;

kernel/trace/rethook.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,19 @@ static void rethook_free_rcu(struct rcu_head *head)
5353
kfree(rh);
5454
}
5555

56+
/**
57+
* rethook_stop() - Stop using a rethook.
58+
* @rh: the struct rethook to stop.
59+
*
60+
* Stop using a rethook to prepare for freeing it. If you want to wait for
61+
* all running rethook handler before calling rethook_free(), you need to
62+
* call this first and wait RCU, and call rethook_free().
63+
*/
64+
void rethook_stop(struct rethook *rh)
65+
{
66+
WRITE_ONCE(rh->handler, NULL);
67+
}
68+
5669
/**
5770
* rethook_free() - Free struct rethook.
5871
* @rh: the struct rethook to be freed.

kernel/trace/trace_eprobe.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ static int enable_trace_eprobe(struct trace_event_call *call,
644644
struct trace_eprobe *ep;
645645
bool enabled;
646646
int ret = 0;
647+
int cnt = 0;
647648

648649
tp = trace_probe_primary_from_call(call);
649650
if (WARN_ON_ONCE(!tp))
@@ -667,12 +668,25 @@ static int enable_trace_eprobe(struct trace_event_call *call,
667668
if (ret)
668669
break;
669670
enabled = true;
671+
cnt++;
670672
}
671673

672674
if (ret) {
673675
/* Failed to enable one of them. Roll back all */
674-
if (enabled)
675-
disable_eprobe(ep, file->tr);
676+
if (enabled) {
677+
/*
678+
* It's a bug if one failed for something other than memory
679+
* not being available but another eprobe succeeded.
680+
*/
681+
WARN_ON_ONCE(ret != -ENOMEM);
682+
683+
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
684+
ep = container_of(pos, struct trace_eprobe, tp);
685+
disable_eprobe(ep, file->tr);
686+
if (!--cnt)
687+
break;
688+
}
689+
}
676690
if (file)
677691
trace_probe_remove_file(tp, file);
678692
else

0 commit comments

Comments
 (0)