diff options
Diffstat (limited to 'net/bpf/test_run.c')
| -rw-r--r-- | net/bpf/test_run.c | 39 | 
1 files changed, 35 insertions, 4 deletions
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 80e6f3a6864d..1153bbcdff72 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -377,6 +377,22 @@ out:  	return ret;  } +static int verify_user_bpf_flow_keys(struct bpf_flow_keys *ctx) +{ +	/* make sure the fields we don't use are zeroed */ +	if (!range_is_zero(ctx, 0, offsetof(struct bpf_flow_keys, flags))) +		return -EINVAL; + +	/* flags is allowed */ + +	if (!range_is_zero(ctx, offsetof(struct bpf_flow_keys, flags) + +			   FIELD_SIZEOF(struct bpf_flow_keys, flags), +			   sizeof(struct bpf_flow_keys))) +		return -EINVAL; + +	return 0; +} +  int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  				     const union bpf_attr *kattr,  				     union bpf_attr __user *uattr) @@ -384,9 +400,11 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  	u32 size = kattr->test.data_size_in;  	struct bpf_flow_dissector ctx = {};  	u32 repeat = kattr->test.repeat; +	struct bpf_flow_keys *user_ctx;  	struct bpf_flow_keys flow_keys;  	u64 time_start, time_spent = 0;  	const struct ethhdr *eth; +	unsigned int flags = 0;  	u32 retval, duration;  	void *data;  	int ret; @@ -395,9 +413,6 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  	if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)  		return -EINVAL; -	if (kattr->test.ctx_in || kattr->test.ctx_out) -		return -EINVAL; -  	if (size < ETH_HLEN)  		return -EINVAL; @@ -410,6 +425,18 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  	if (!repeat)  		repeat = 1; +	user_ctx = bpf_ctx_init(kattr, sizeof(struct bpf_flow_keys)); +	if (IS_ERR(user_ctx)) { +		kfree(data); +		return PTR_ERR(user_ctx); +	} +	if (user_ctx) { +		ret = verify_user_bpf_flow_keys(user_ctx); +		if (ret) +			goto out; +		flags = user_ctx->flags; +	} +  	ctx.flow_keys = &flow_keys;  	ctx.data = data;  	ctx.data_end = (__u8 *)data + size; @@ -419,7 +446,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  	time_start = ktime_get_ns();  	for (i = 0; i < repeat; i++) {  		retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN, -					  size); +					  size, flags);  		if (signal_pending(current)) {  			preempt_enable(); @@ -450,8 +477,12 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,  	ret = bpf_test_finish(kattr, uattr, &flow_keys, sizeof(flow_keys),  			      retval, duration); +	if (!ret) +		ret = bpf_ctx_finish(kattr, uattr, user_ctx, +				     sizeof(struct bpf_flow_keys));  out: +	kfree(user_ctx);  	kfree(data);  	return ret;  }  |