mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	bpf: Add bpf_dynptr_from_mem for local dynptrs
This patch adds a new api bpf_dynptr_from_mem: long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr); which initializes a dynptr to point to a bpf program's local memory. For now only local memory that is of reg type PTR_TO_MAP_VALUE is supported. Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20220523210712.3641569-3-joannelkoong@gmail.com
This commit is contained in:
		
							parent
							
								
									97e03f5210
								
							
						
					
					
						commit
						263ae152e9
					
				
					 4 changed files with 95 additions and 0 deletions
				
			
		|  | @ -5178,6 +5178,17 @@ union bpf_attr { | |||
|  *		Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. | ||||
|  *	Return | ||||
|  *		*sk* if casting is valid, or **NULL** otherwise. | ||||
|  * | ||||
|  * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr) | ||||
|  *	Description | ||||
|  *		Get a dynptr to local memory *data*. | ||||
|  * | ||||
|  *		*data* must be a ptr to a map value. | ||||
|  *		The maximum *size* supported is DYNPTR_MAX_SIZE. | ||||
|  *		*flags* is currently unused. | ||||
|  *	Return | ||||
|  *		0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, | ||||
|  *		-EINVAL if flags is not 0. | ||||
|  */ | ||||
| #define __BPF_FUNC_MAPPER(FN)		\ | ||||
| 	FN(unspec),			\ | ||||
|  | @ -5377,6 +5388,7 @@ union bpf_attr { | |||
| 	FN(kptr_xchg),			\ | ||||
| 	FN(map_lookup_percpu_elem),     \ | ||||
| 	FN(skc_to_mptcp_sock),		\ | ||||
| 	FN(dynptr_from_mem),		\ | ||||
| 	/* */ | ||||
| 
 | ||||
| /* integer value in 'imm' field of BPF_CALL instruction selects which helper
 | ||||
|  |  | |||
|  | @ -1412,6 +1412,69 @@ const struct bpf_func_proto bpf_kptr_xchg_proto = { | |||
| 	.arg2_btf_id  = BPF_PTR_POISON, | ||||
| }; | ||||
| 
 | ||||
| /* Since the upper 8 bits of dynptr->size is reserved, the
 | ||||
|  * maximum supported size is 2^24 - 1. | ||||
|  */ | ||||
| #define DYNPTR_MAX_SIZE	((1UL << 24) - 1) | ||||
| #define DYNPTR_TYPE_SHIFT	28 | ||||
| 
 | ||||
| static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type) | ||||
| { | ||||
| 	ptr->size |= type << DYNPTR_TYPE_SHIFT; | ||||
| } | ||||
| 
 | ||||
| static int bpf_dynptr_check_size(u32 size) | ||||
| { | ||||
| 	return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; | ||||
| } | ||||
| 
 | ||||
| static void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, | ||||
| 			    enum bpf_dynptr_type type, u32 offset, u32 size) | ||||
| { | ||||
| 	ptr->data = data; | ||||
| 	ptr->offset = offset; | ||||
| 	ptr->size = size; | ||||
| 	bpf_dynptr_set_type(ptr, type); | ||||
| } | ||||
| 
 | ||||
| static void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) | ||||
| { | ||||
| 	memset(ptr, 0, sizeof(*ptr)); | ||||
| } | ||||
| 
 | ||||
| BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = bpf_dynptr_check_size(size); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* flags is currently unsupported */ | ||||
| 	if (flags) { | ||||
| 		err = -EINVAL; | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	bpf_dynptr_init(ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, size); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| error: | ||||
| 	bpf_dynptr_set_null(ptr); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| const struct bpf_func_proto bpf_dynptr_from_mem_proto = { | ||||
| 	.func		= bpf_dynptr_from_mem, | ||||
| 	.gpl_only	= false, | ||||
| 	.ret_type	= RET_INTEGER, | ||||
| 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM, | ||||
| 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO, | ||||
| 	.arg3_type	= ARG_ANYTHING, | ||||
| 	.arg4_type	= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT, | ||||
| }; | ||||
| 
 | ||||
| const struct bpf_func_proto bpf_get_current_task_proto __weak; | ||||
| const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; | ||||
| const struct bpf_func_proto bpf_probe_read_user_proto __weak; | ||||
|  | @ -1466,6 +1529,8 @@ bpf_base_func_proto(enum bpf_func_id func_id) | |||
| 		return &bpf_loop_proto; | ||||
| 	case BPF_FUNC_strncmp: | ||||
| 		return &bpf_strncmp_proto; | ||||
| 	case BPF_FUNC_dynptr_from_mem: | ||||
| 		return &bpf_dynptr_from_mem_proto; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  |  | |||
|  | @ -7204,6 +7204,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 		err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, | ||||
| 					set_loop_callback_state); | ||||
| 		break; | ||||
| 	case BPF_FUNC_dynptr_from_mem: | ||||
| 		if (regs[BPF_REG_1].type != PTR_TO_MAP_VALUE) { | ||||
| 			verbose(env, "Unsupported reg type %s for bpf_dynptr_from_mem data\n", | ||||
| 				reg_type_str(env, regs[BPF_REG_1].type)); | ||||
| 			return -EACCES; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (err) | ||||
|  |  | |||
|  | @ -5178,6 +5178,17 @@ union bpf_attr { | |||
|  *		Dynamically cast a *sk* pointer to a *mptcp_sock* pointer. | ||||
|  *	Return | ||||
|  *		*sk* if casting is valid, or **NULL** otherwise. | ||||
|  * | ||||
|  * long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr) | ||||
|  *	Description | ||||
|  *		Get a dynptr to local memory *data*. | ||||
|  * | ||||
|  *		*data* must be a ptr to a map value. | ||||
|  *		The maximum *size* supported is DYNPTR_MAX_SIZE. | ||||
|  *		*flags* is currently unused. | ||||
|  *	Return | ||||
|  *		0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE, | ||||
|  *		-EINVAL if flags is not 0. | ||||
|  */ | ||||
| #define __BPF_FUNC_MAPPER(FN)		\ | ||||
| 	FN(unspec),			\ | ||||
|  | @ -5377,6 +5388,7 @@ union bpf_attr { | |||
| 	FN(kptr_xchg),			\ | ||||
| 	FN(map_lookup_percpu_elem),     \ | ||||
| 	FN(skc_to_mptcp_sock),		\ | ||||
| 	FN(dynptr_from_mem),		\ | ||||
| 	/* */ | ||||
| 
 | ||||
| /* integer value in 'imm' field of BPF_CALL instruction selects which helper
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Joanne Koong
						Joanne Koong