Skip to content

Commit

Permalink
bpf: one perf event close won't free bpf program attached by another …
Browse files Browse the repository at this point in the history
…perf event

[ Upstream commit ec9dd35 ]

This patch fixes a bug exhibited by the following scenario:
  1. fd1 = perf_event_open with attr.config = ID1
  2. attach bpf program prog1 to fd1
  3. fd2 = perf_event_open with attr.config = ID1
     <this will be successful>
  4. user program closes fd2 and prog1 is detached from the tracepoint.
  5. user program with fd1 does not work properly as tracepoint
     no output any more.

The issue happens at step 4. Multiple perf_event_open can be called
successfully, but only one bpf prog pointer in the tp_event. In the
current logic, any fd release for the same tp_event will free
the tp_event->prog.

The fix is to free tp_event->prog only when the closing fd
corresponds to the one which registered the program.

Signed-off-by: Yonghong Song <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
yonghong-song authored and gregkh committed Oct 12, 2017
1 parent 6f7cdd4 commit 0dee549
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/linux/trace_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ struct trace_event_call {
int perf_refcount;
struct hlist_head __percpu *perf_events;
struct bpf_prog *prog;
struct perf_event *bpf_prog_owner;

int (*perf_perm)(struct trace_event_call *,
struct perf_event *);
Expand Down
3 changes: 2 additions & 1 deletion kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -7871,6 +7871,7 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
}
}
event->tp_event->prog = prog;
event->tp_event->bpf_prog_owner = event;

return 0;
}
Expand All @@ -7885,7 +7886,7 @@ static void perf_event_free_bpf_prog(struct perf_event *event)
return;

prog = event->tp_event->prog;
if (prog) {
if (prog && event->tp_event->bpf_prog_owner == event) {
event->tp_event->prog = NULL;
bpf_prog_put(prog);
}
Expand Down

0 comments on commit 0dee549

Please sign in to comment.