Skip to content

Commit 636666a

Browse files
anakryikoIngo Molnar
authored andcommitted
uprobes: Decouple return_instance list traversal and freeing
free_ret_instance() has two unrelated responsibilities: actually cleaning up return_instance's resources and freeing memory, and also helping with utask->return_instances list traversal by returning the next alive pointer. There is no reason why these two aspects have to be mixed together, so turn free_ret_instance() into void-returning function and make callers do list traversal on their own. We'll use this simplification in the next patch that will guarantee that to-be-freed return_instance isn't reachable from utask->return_instances list. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Oleg Nesterov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2ff913a commit 636666a

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

kernel/events/uprobes.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,10 +1888,8 @@ unsigned long uprobe_get_trap_addr(struct pt_regs *regs)
18881888
return instruction_pointer(regs);
18891889
}
18901890

1891-
static struct return_instance *free_ret_instance(struct return_instance *ri, bool cleanup_hprobe)
1891+
static void free_ret_instance(struct return_instance *ri, bool cleanup_hprobe)
18921892
{
1893-
struct return_instance *next = ri->next;
1894-
18951893
if (cleanup_hprobe) {
18961894
enum hprobe_state hstate;
18971895

@@ -1901,7 +1899,6 @@ static struct return_instance *free_ret_instance(struct return_instance *ri, boo
19011899

19021900
kfree(ri->extra_consumers);
19031901
kfree_rcu(ri, rcu);
1904-
return next;
19051902
}
19061903

19071904
/*
@@ -1911,7 +1908,7 @@ static struct return_instance *free_ret_instance(struct return_instance *ri, boo
19111908
void uprobe_free_utask(struct task_struct *t)
19121909
{
19131910
struct uprobe_task *utask = t->utask;
1914-
struct return_instance *ri;
1911+
struct return_instance *ri, *ri_next;
19151912

19161913
if (!utask)
19171914
return;
@@ -1921,8 +1918,11 @@ void uprobe_free_utask(struct task_struct *t)
19211918
timer_delete_sync(&utask->ri_timer);
19221919

19231920
ri = utask->return_instances;
1924-
while (ri)
1925-
ri = free_ret_instance(ri, true /* cleanup_hprobe */);
1921+
while (ri) {
1922+
ri_next = ri->next;
1923+
free_ret_instance(ri, true /* cleanup_hprobe */);
1924+
ri = ri_next;
1925+
}
19261926

19271927
kfree(utask);
19281928
t->utask = NULL;
@@ -2111,12 +2111,15 @@ unsigned long uprobe_get_trampoline_vaddr(void)
21112111
static void cleanup_return_instances(struct uprobe_task *utask, bool chained,
21122112
struct pt_regs *regs)
21132113
{
2114-
struct return_instance *ri = utask->return_instances;
2114+
struct return_instance *ri = utask->return_instances, *ri_next;
21152115
enum rp_check ctx = chained ? RP_CHECK_CHAIN_CALL : RP_CHECK_CALL;
21162116

21172117
while (ri && !arch_uretprobe_is_alive(ri, ctx, regs)) {
2118-
ri = free_ret_instance(ri, true /* cleanup_hprobe */);
2118+
ri_next = ri->next;
21192119
utask->depth--;
2120+
2121+
free_ret_instance(ri, true /* cleanup_hprobe */);
2122+
ri = ri_next;
21202123
}
21212124
rcu_assign_pointer(utask->return_instances, ri);
21222125
}
@@ -2508,7 +2511,7 @@ static struct return_instance *find_next_ret_chain(struct return_instance *ri)
25082511
void uprobe_handle_trampoline(struct pt_regs *regs)
25092512
{
25102513
struct uprobe_task *utask;
2511-
struct return_instance *ri, *next;
2514+
struct return_instance *ri, *ri_next, *next_chain;
25122515
struct uprobe *uprobe;
25132516
enum hprobe_state hstate;
25142517
bool valid;
@@ -2528,8 +2531,8 @@ void uprobe_handle_trampoline(struct pt_regs *regs)
25282531
* or NULL; the latter case means that nobody but ri->func
25292532
* could hit this trampoline on return. TODO: sigaltstack().
25302533
*/
2531-
next = find_next_ret_chain(ri);
2532-
valid = !next || arch_uretprobe_is_alive(next, RP_CHECK_RET, regs);
2534+
next_chain = find_next_ret_chain(ri);
2535+
valid = !next_chain || arch_uretprobe_is_alive(next_chain, RP_CHECK_RET, regs);
25332536

25342537
instruction_pointer_set(regs, ri->orig_ret_vaddr);
25352538
do {
@@ -2541,17 +2544,19 @@ void uprobe_handle_trampoline(struct pt_regs *regs)
25412544
* trampoline addresses on the stack are replaced with correct
25422545
* original return addresses
25432546
*/
2544-
rcu_assign_pointer(utask->return_instances, ri->next);
2547+
ri_next = ri->next;
2548+
rcu_assign_pointer(utask->return_instances, ri_next);
2549+
utask->depth--;
25452550

25462551
uprobe = hprobe_consume(&ri->hprobe, &hstate);
25472552
if (valid)
25482553
handle_uretprobe_chain(ri, uprobe, regs);
25492554
hprobe_finalize(&ri->hprobe, hstate);
25502555

25512556
/* We already took care of hprobe, no need to waste more time on that. */
2552-
ri = free_ret_instance(ri, false /* !cleanup_hprobe */);
2553-
utask->depth--;
2554-
} while (ri != next);
2557+
free_ret_instance(ri, false /* !cleanup_hprobe */);
2558+
ri = ri_next;
2559+
} while (ri != next_chain);
25552560
} while (!valid);
25562561

25572562
return;

0 commit comments

Comments
 (0)