diff options
Diffstat (limited to 'kernel/bpf/core.c')
| -rw-r--r-- | kernel/bpf/core.c | 45 | 
1 files changed, 29 insertions, 16 deletions
| diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index d315b393abdd..ba03ec39efb3 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1572,13 +1572,32 @@ int bpf_prog_array_length(struct bpf_prog_array __rcu *progs)  	return cnt;  } +static bool bpf_prog_array_copy_core(struct bpf_prog **prog, +				     u32 *prog_ids, +				     u32 request_cnt) +{ +	int i = 0; + +	for (; *prog; prog++) { +		if (*prog == &dummy_bpf_prog.prog) +			continue; +		prog_ids[i] = (*prog)->aux->id; +		if (++i == request_cnt) { +			prog++; +			break; +		} +	} + +	return !!(*prog); +} +  int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,  				__u32 __user *prog_ids, u32 cnt)  {  	struct bpf_prog **prog;  	unsigned long err = 0; -	u32 i = 0, *ids;  	bool nospc; +	u32 *ids;  	/* users of this function are doing:  	 * cnt = bpf_prog_array_length(); @@ -1595,16 +1614,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,  		return -ENOMEM;  	rcu_read_lock();  	prog = rcu_dereference(progs)->progs; -	for (; *prog; prog++) { -		if (*prog == &dummy_bpf_prog.prog) -			continue; -		ids[i] = (*prog)->aux->id; -		if (++i == cnt) { -			prog++; -			break; -		} -	} -	nospc = !!(*prog); +	nospc = bpf_prog_array_copy_core(prog, ids, cnt);  	rcu_read_unlock();  	err = copy_to_user(prog_ids, ids, cnt * sizeof(u32));  	kfree(ids); @@ -1683,22 +1693,25 @@ int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,  }  int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array, -			     __u32 __user *prog_ids, u32 request_cnt, -			     __u32 __user *prog_cnt) +			     u32 *prog_ids, u32 request_cnt, +			     u32 *prog_cnt)  { +	struct bpf_prog **prog;  	u32 cnt = 0;  	if (array)  		cnt = bpf_prog_array_length(array); -	if (copy_to_user(prog_cnt, &cnt, sizeof(cnt))) -		return -EFAULT; +	*prog_cnt = cnt;  	/* return early if user requested only program count or nothing to copy */  	if (!request_cnt || !cnt)  		return 0; -	return bpf_prog_array_copy_to_user(array, prog_ids, request_cnt); +	/* this function is called under trace/bpf_trace.c: bpf_event_mutex */ +	prog = rcu_dereference_check(array, 1)->progs; +	return bpf_prog_array_copy_core(prog, prog_ids, request_cnt) ? -ENOSPC +								     : 0;  }  static void bpf_prog_free_deferred(struct work_struct *work) |