forked from mirrors/linux
		
	bpf: Introduce ARG_PTR_TO_{INT,LONG} arg types
Currently the way to pass result from BPF helper to BPF program is to provide memory area defined by pointer and size: func(void *, size_t). It works great for generic use-case, but for simple types, such as int, it's overkill and consumes two arguments when it could use just one. Introduce new argument types ARG_PTR_TO_INT and ARG_PTR_TO_LONG to be able to pass result from helper to program via pointer to int and long correspondingly: func(int *) or func(long *). New argument types are similar to ARG_PTR_TO_MEM with the following differences: * they don't require corresponding ARG_CONST_SIZE argument, predefined access sizes are used instead (32bit for int, 64bit for long); * it's possible to use more than one such an argument in a helper; * provided pointers have to be aligned. It's easy to introduce similar ARG_PTR_TO_CHAR and ARG_PTR_TO_SHORT argument types. It's not done due to lack of use-case though. Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									9a1027e525
								
							
						
					
					
						commit
						57c3bb725a
					
				
					 2 changed files with 31 additions and 0 deletions
				
			
		|  | @ -202,6 +202,8 @@ enum bpf_arg_type { | ||||||
| 	ARG_ANYTHING,		/* any (initialized) argument is ok */ | 	ARG_ANYTHING,		/* any (initialized) argument is ok */ | ||||||
| 	ARG_PTR_TO_SPIN_LOCK,	/* pointer to bpf_spin_lock */ | 	ARG_PTR_TO_SPIN_LOCK,	/* pointer to bpf_spin_lock */ | ||||||
| 	ARG_PTR_TO_SOCK_COMMON,	/* pointer to sock_common */ | 	ARG_PTR_TO_SOCK_COMMON,	/* pointer to sock_common */ | ||||||
|  | 	ARG_PTR_TO_INT,		/* pointer to int */ | ||||||
|  | 	ARG_PTR_TO_LONG,	/* pointer to long */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* type of values returned from helper functions */ | /* type of values returned from helper functions */ | ||||||
|  |  | ||||||
|  | @ -2462,6 +2462,22 @@ static bool arg_type_is_mem_size(enum bpf_arg_type type) | ||||||
| 	       type == ARG_CONST_SIZE_OR_ZERO; | 	       type == ARG_CONST_SIZE_OR_ZERO; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool arg_type_is_int_ptr(enum bpf_arg_type type) | ||||||
|  | { | ||||||
|  | 	return type == ARG_PTR_TO_INT || | ||||||
|  | 	       type == ARG_PTR_TO_LONG; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int int_ptr_type_to_size(enum bpf_arg_type type) | ||||||
|  | { | ||||||
|  | 	if (type == ARG_PTR_TO_INT) | ||||||
|  | 		return sizeof(u32); | ||||||
|  | 	else if (type == ARG_PTR_TO_LONG) | ||||||
|  | 		return sizeof(u64); | ||||||
|  | 
 | ||||||
|  | 	return -EINVAL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | ||||||
| 			  enum bpf_arg_type arg_type, | 			  enum bpf_arg_type arg_type, | ||||||
| 			  struct bpf_call_arg_meta *meta) | 			  struct bpf_call_arg_meta *meta) | ||||||
|  | @ -2554,6 +2570,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | ||||||
| 			 type != expected_type) | 			 type != expected_type) | ||||||
| 			goto err_type; | 			goto err_type; | ||||||
| 		meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM; | 		meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM; | ||||||
|  | 	} else if (arg_type_is_int_ptr(arg_type)) { | ||||||
|  | 		expected_type = PTR_TO_STACK; | ||||||
|  | 		if (!type_is_pkt_pointer(type) && | ||||||
|  | 		    type != PTR_TO_MAP_VALUE && | ||||||
|  | 		    type != expected_type) | ||||||
|  | 			goto err_type; | ||||||
| 	} else { | 	} else { | ||||||
| 		verbose(env, "unsupported arg_type %d\n", arg_type); | 		verbose(env, "unsupported arg_type %d\n", arg_type); | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
|  | @ -2635,6 +2657,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, | ||||||
| 		err = check_helper_mem_access(env, regno - 1, | 		err = check_helper_mem_access(env, regno - 1, | ||||||
| 					      reg->umax_value, | 					      reg->umax_value, | ||||||
| 					      zero_size_allowed, meta); | 					      zero_size_allowed, meta); | ||||||
|  | 	} else if (arg_type_is_int_ptr(arg_type)) { | ||||||
|  | 		int size = int_ptr_type_to_size(arg_type); | ||||||
|  | 
 | ||||||
|  | 		err = check_helper_mem_access(env, regno, size, false, meta); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | 		err = check_ptr_alignment(env, reg, 0, size, true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return err; | 	return err; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Andrey Ignatov
						Andrey Ignatov