diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
| -rw-r--r-- | kernel/bpf/syscall.c | 30 | 
1 files changed, 18 insertions, 12 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 5d141f16f6fa..272071e9112f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1707,20 +1707,26 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)  	if (err)  		goto free_used_maps; -	err = bpf_prog_new_fd(prog); -	if (err < 0) { -		/* failed to allocate fd. -		 * bpf_prog_put() is needed because the above -		 * bpf_prog_alloc_id() has published the prog -		 * to the userspace and the userspace may -		 * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. -		 */ -		bpf_prog_put(prog); -		return err; -	} - +	/* Upon success of bpf_prog_alloc_id(), the BPF prog is +	 * effectively publicly exposed. However, retrieving via +	 * bpf_prog_get_fd_by_id() will take another reference, +	 * therefore it cannot be gone underneath us. +	 * +	 * Only for the time /after/ successful bpf_prog_new_fd() +	 * and before returning to userspace, we might just hold +	 * one reference and any parallel close on that fd could +	 * rip everything out. Hence, below notifications must +	 * happen before bpf_prog_new_fd(). +	 * +	 * Also, any failure handling from this point onwards must +	 * be using bpf_prog_put() given the program is exposed. +	 */  	bpf_prog_kallsyms_add(prog);  	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); + +	err = bpf_prog_new_fd(prog); +	if (err < 0) +		bpf_prog_put(prog);  	return err;  free_used_maps:  | 
