dup_utask() installs the new uprobe_task in t->utask before copying return_instances. If dup_return_instance() fails, the partially copied utask is left attached to the child task.
Free the partially copied utask before returning -ENOMEM. Also, dup_return_instance() copies the return_instance before fixing up extra_consumers. Here, if no deep copy is needed, clear the copied extra_consumers pointer. Signed-off-by: Keke Ming <[email protected]> --- v2 changes: - Clear ri->extra_consumers = NULL when old->cons_cnt <= 1 in dup_return_instance(), fixing a potential double free during cleanup. - Keep the dup_utask() error cleanup from v1. kernel/events/uprobes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index b25531331902..73a6620c5701 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -2118,6 +2118,8 @@ static struct return_instance *dup_return_instance(struct return_instance *old) kfree(ri); return NULL; } + } else { + ri->extra_consumers = NULL; } return ri; @@ -2140,8 +2142,10 @@ static int dup_utask(struct task_struct *t, struct uprobe_task *o_utask) p = &n_utask->return_instances; for (o = o_utask->return_instances; o; o = o->next) { n = dup_return_instance(o); - if (!n) + if (!n) { + uprobe_free_utask(t); return -ENOMEM; + } /* if uprobe is non-NULL, we'll have an extra refcount for uprobe */ uprobe = hprobe_expire(&o->hprobe, true); -- 2.43.0
