diff --git a/kernel/events/core.c b/kernel/events/core.c
index f47fcac5bba2e409936cb780b96737e4aa9ae8f5..64dacbfa06d02e8fe73d5498462af85ebd15aa42 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2104,6 +2104,28 @@ static void perf_remove_from_context(struct perf_event *event, unsigned long fla
 
 	event_function_call(event, __perf_remove_from_context, (void *)flags);
 
+	/*
+	 * This is as passable as any hw.target handling out there;
+	 * hw.target implies task context, therefore, no migration.
+	 * Which together with DETACH_GROUP means that this is the
+	 * final remove_from_context of a task event.
+	 */
+	if (event->hw.target && (flags & DETACH_GROUP)) {
+		/*
+		 * Now, the problem with, say uprobes, is that they
+		 * use hw.target for context in their ->destroy()
+		 * callbacks. Supposedly, they may need to poke at
+		 * its contents, so better call it while we still
+		 * have the task.
+		 */
+		if (event->destroy) {
+			event->destroy(event);
+			event->destroy = NULL;
+		}
+		put_task_struct(event->hw.target);
+		event->hw.target = NULL;
+	}
+
 	/*
 	 * The above event_function_call() can NO-OP when it hits
 	 * TASK_TOMBSTONE. In that case we must already have been detached