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_PTR_TO_SPIN_LOCK,	/* pointer to bpf_spin_lock */ | ||||
| 	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 */ | ||||
|  |  | |||
|  | @ -2462,6 +2462,22 @@ static bool arg_type_is_mem_size(enum bpf_arg_type type) | |||
| 	       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, | ||||
| 			  enum bpf_arg_type arg_type, | ||||
| 			  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) | ||||
| 			goto err_type; | ||||
| 		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 { | ||||
| 		verbose(env, "unsupported arg_type %d\n", arg_type); | ||||
| 		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, | ||||
| 					      reg->umax_value, | ||||
| 					      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; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Andrey Ignatov
						Andrey Ignatov