mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	bpf: Replace PTR_TO_XXX_OR_NULL with PTR_TO_XXX | PTR_MAYBE_NULL
We have introduced a new type to make bpf_reg composable, by allocating bits in the type to represent flags. One of the flags is PTR_MAYBE_NULL which indicates a pointer may be NULL. This patch switches the qualified reg_types to use this flag. The reg_types changed in this patch include: 1. PTR_TO_MAP_VALUE_OR_NULL 2. PTR_TO_SOCKET_OR_NULL 3. PTR_TO_SOCK_COMMON_OR_NULL 4. PTR_TO_TCP_SOCK_OR_NULL 5. PTR_TO_BTF_ID_OR_NULL 6. PTR_TO_MEM_OR_NULL 7. PTR_TO_RDONLY_BUF_OR_NULL 8. PTR_TO_RDWR_BUF_OR_NULL Signed-off-by: Hao Luo <haoluo@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/r/20211217003152.48334-5-haoluo@google.com
This commit is contained in:
		
							parent
							
								
									3c48073226
								
							
						
					
					
						commit
						c25b2ae136
					
				
					 7 changed files with 147 additions and 188 deletions
				
			
		|  | @ -465,18 +465,15 @@ enum bpf_reg_type { | |||
| 	PTR_TO_CTX,		 /* reg points to bpf_context */ | ||||
| 	CONST_PTR_TO_MAP,	 /* reg points to struct bpf_map */ | ||||
| 	PTR_TO_MAP_VALUE,	 /* reg points to map element value */ | ||||
| 	PTR_TO_MAP_VALUE_OR_NULL,/* points to map elem value or NULL */ | ||||
| 	PTR_TO_MAP_KEY,		 /* reg points to a map element key */ | ||||
| 	PTR_TO_STACK,		 /* reg == frame_pointer + offset */ | ||||
| 	PTR_TO_PACKET_META,	 /* skb->data - meta_len */ | ||||
| 	PTR_TO_PACKET,		 /* reg points to skb->data */ | ||||
| 	PTR_TO_PACKET_END,	 /* skb->data + headlen */ | ||||
| 	PTR_TO_FLOW_KEYS,	 /* reg points to bpf_flow_keys */ | ||||
| 	PTR_TO_SOCKET,		 /* reg points to struct bpf_sock */ | ||||
| 	PTR_TO_SOCKET_OR_NULL,	 /* reg points to struct bpf_sock or NULL */ | ||||
| 	PTR_TO_SOCK_COMMON,	 /* reg points to sock_common */ | ||||
| 	PTR_TO_SOCK_COMMON_OR_NULL, /* reg points to sock_common or NULL */ | ||||
| 	PTR_TO_TCP_SOCK,	 /* reg points to struct tcp_sock */ | ||||
| 	PTR_TO_TCP_SOCK_OR_NULL, /* reg points to struct tcp_sock or NULL */ | ||||
| 	PTR_TO_TP_BUFFER,	 /* reg points to a writable raw tp's buffer */ | ||||
| 	PTR_TO_XDP_SOCK,	 /* reg points to struct xdp_sock */ | ||||
| 	/* PTR_TO_BTF_ID points to a kernel struct that does not need
 | ||||
|  | @ -494,18 +491,21 @@ enum bpf_reg_type { | |||
| 	 * been checked for null. Used primarily to inform the verifier | ||||
| 	 * an explicit null check is required for this struct. | ||||
| 	 */ | ||||
| 	PTR_TO_BTF_ID_OR_NULL, | ||||
| 	PTR_TO_MEM,		 /* reg points to valid memory region */ | ||||
| 	PTR_TO_MEM_OR_NULL,	 /* reg points to valid memory region or NULL */ | ||||
| 	PTR_TO_RDONLY_BUF,	 /* reg points to a readonly buffer */ | ||||
| 	PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */ | ||||
| 	PTR_TO_RDWR_BUF,	 /* reg points to a read/write buffer */ | ||||
| 	PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */ | ||||
| 	PTR_TO_PERCPU_BTF_ID,	 /* reg points to a percpu kernel variable */ | ||||
| 	PTR_TO_FUNC,		 /* reg points to a bpf program function */ | ||||
| 	PTR_TO_MAP_KEY,		 /* reg points to a map element key */ | ||||
| 	__BPF_REG_TYPE_MAX, | ||||
| 
 | ||||
| 	/* Extended reg_types. */ | ||||
| 	PTR_TO_MAP_VALUE_OR_NULL	= PTR_MAYBE_NULL | PTR_TO_MAP_VALUE, | ||||
| 	PTR_TO_SOCKET_OR_NULL		= PTR_MAYBE_NULL | PTR_TO_SOCKET, | ||||
| 	PTR_TO_SOCK_COMMON_OR_NULL	= PTR_MAYBE_NULL | PTR_TO_SOCK_COMMON, | ||||
| 	PTR_TO_TCP_SOCK_OR_NULL		= PTR_MAYBE_NULL | PTR_TO_TCP_SOCK, | ||||
| 	PTR_TO_BTF_ID_OR_NULL		= PTR_MAYBE_NULL | PTR_TO_BTF_ID, | ||||
| 	PTR_TO_MEM_OR_NULL		= PTR_MAYBE_NULL | PTR_TO_MEM, | ||||
| 
 | ||||
| 	/* This must be the last entry. Its purpose is to ensure the enum is
 | ||||
| 	 * wide enough to hold the higher bits reserved for bpf_type_flag. | ||||
| 	 */ | ||||
|  |  | |||
|  | @ -18,6 +18,8 @@ | |||
|  * that converting umax_value to int cannot overflow. | ||||
|  */ | ||||
| #define BPF_MAX_VAR_SIZ	(1 << 29) | ||||
| /* size of type_str_buf in bpf_verifier. */ | ||||
| #define TYPE_STR_BUF_LEN 64 | ||||
| 
 | ||||
| /* Liveness marks, used for registers and spilled-regs (in stack slots).
 | ||||
|  * Read marks propagate upwards until they find a write mark; they record that | ||||
|  | @ -484,6 +486,8 @@ struct bpf_verifier_env { | |||
| 	/* Same as scratched_regs but for stack slots */ | ||||
| 	u64 scratched_stack_slots; | ||||
| 	u32 prev_log_len, prev_insn_print_len; | ||||
| 	/* buffer used in reg_type_str() to generate reg_type string */ | ||||
| 	char type_str_buf[TYPE_STR_BUF_LEN]; | ||||
| }; | ||||
| 
 | ||||
| __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, | ||||
|  |  | |||
|  | @ -4940,10 +4940,13 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, | |||
| 	/* check for PTR_TO_RDONLY_BUF_OR_NULL or PTR_TO_RDWR_BUF_OR_NULL */ | ||||
| 	for (i = 0; i < prog->aux->ctx_arg_info_size; i++) { | ||||
| 		const struct bpf_ctx_arg_aux *ctx_arg_info = &prog->aux->ctx_arg_info[i]; | ||||
| 		u32 type, flag; | ||||
| 
 | ||||
| 		type = base_type(ctx_arg_info->reg_type); | ||||
| 		flag = type_flag(ctx_arg_info->reg_type); | ||||
| 		if (ctx_arg_info->offset == off && | ||||
| 		    (ctx_arg_info->reg_type == PTR_TO_RDONLY_BUF_OR_NULL || | ||||
| 		     ctx_arg_info->reg_type == PTR_TO_RDWR_BUF_OR_NULL)) { | ||||
| 		    (type == PTR_TO_RDWR_BUF || type == PTR_TO_RDONLY_BUF) && | ||||
| 		    (flag & PTR_MAYBE_NULL)) { | ||||
| 			info->reg_type = ctx_arg_info->reg_type; | ||||
| 			return true; | ||||
| 		} | ||||
|  |  | |||
|  | @ -174,9 +174,9 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = { | |||
| 	.ctx_arg_info_size	= 2, | ||||
| 	.ctx_arg_info		= { | ||||
| 		{ offsetof(struct bpf_iter__bpf_map_elem, key), | ||||
| 		  PTR_TO_RDONLY_BUF_OR_NULL }, | ||||
| 		  PTR_TO_RDONLY_BUF | PTR_MAYBE_NULL }, | ||||
| 		{ offsetof(struct bpf_iter__bpf_map_elem, value), | ||||
| 		  PTR_TO_RDWR_BUF_OR_NULL }, | ||||
| 		  PTR_TO_RDWR_BUF | PTR_MAYBE_NULL }, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -442,18 +442,6 @@ static bool reg_type_not_null(enum bpf_reg_type type) | |||
| 		type == PTR_TO_SOCK_COMMON; | ||||
| } | ||||
| 
 | ||||
| static bool reg_type_may_be_null(enum bpf_reg_type type) | ||||
| { | ||||
| 	return type == PTR_TO_MAP_VALUE_OR_NULL || | ||||
| 	       type == PTR_TO_SOCKET_OR_NULL || | ||||
| 	       type == PTR_TO_SOCK_COMMON_OR_NULL || | ||||
| 	       type == PTR_TO_TCP_SOCK_OR_NULL || | ||||
| 	       type == PTR_TO_BTF_ID_OR_NULL || | ||||
| 	       type == PTR_TO_MEM_OR_NULL || | ||||
| 	       type == PTR_TO_RDONLY_BUF_OR_NULL || | ||||
| 	       type == PTR_TO_RDWR_BUF_OR_NULL; | ||||
| } | ||||
| 
 | ||||
| static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) | ||||
| { | ||||
| 	return reg->type == PTR_TO_MAP_VALUE && | ||||
|  | @ -462,12 +450,9 @@ static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) | |||
| 
 | ||||
| static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type) | ||||
| { | ||||
| 	return type == PTR_TO_SOCKET || | ||||
| 		type == PTR_TO_SOCKET_OR_NULL || | ||||
| 		type == PTR_TO_TCP_SOCK || | ||||
| 		type == PTR_TO_TCP_SOCK_OR_NULL || | ||||
| 		type == PTR_TO_MEM || | ||||
| 		type == PTR_TO_MEM_OR_NULL; | ||||
| 	return base_type(type) == PTR_TO_SOCKET || | ||||
| 		base_type(type) == PTR_TO_TCP_SOCK || | ||||
| 		base_type(type) == PTR_TO_MEM; | ||||
| } | ||||
| 
 | ||||
| static bool arg_type_may_be_refcounted(enum bpf_arg_type type) | ||||
|  | @ -537,39 +522,52 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn) | |||
| 	       insn->imm == BPF_CMPXCHG; | ||||
| } | ||||
| 
 | ||||
| /* string representation of 'enum bpf_reg_type' */ | ||||
| static const char * const reg_type_str[] = { | ||||
| 	[NOT_INIT]		= "?", | ||||
| 	[SCALAR_VALUE]		= "inv", | ||||
| 	[PTR_TO_CTX]		= "ctx", | ||||
| 	[CONST_PTR_TO_MAP]	= "map_ptr", | ||||
| 	[PTR_TO_MAP_VALUE]	= "map_value", | ||||
| 	[PTR_TO_MAP_VALUE_OR_NULL] = "map_value_or_null", | ||||
| 	[PTR_TO_STACK]		= "fp", | ||||
| 	[PTR_TO_PACKET]		= "pkt", | ||||
| 	[PTR_TO_PACKET_META]	= "pkt_meta", | ||||
| 	[PTR_TO_PACKET_END]	= "pkt_end", | ||||
| 	[PTR_TO_FLOW_KEYS]	= "flow_keys", | ||||
| 	[PTR_TO_SOCKET]		= "sock", | ||||
| 	[PTR_TO_SOCKET_OR_NULL] = "sock_or_null", | ||||
| 	[PTR_TO_SOCK_COMMON]	= "sock_common", | ||||
| 	[PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null", | ||||
| 	[PTR_TO_TCP_SOCK]	= "tcp_sock", | ||||
| 	[PTR_TO_TCP_SOCK_OR_NULL] = "tcp_sock_or_null", | ||||
| 	[PTR_TO_TP_BUFFER]	= "tp_buffer", | ||||
| 	[PTR_TO_XDP_SOCK]	= "xdp_sock", | ||||
| 	[PTR_TO_BTF_ID]		= "ptr_", | ||||
| 	[PTR_TO_BTF_ID_OR_NULL]	= "ptr_or_null_", | ||||
| 	[PTR_TO_PERCPU_BTF_ID]	= "percpu_ptr_", | ||||
| 	[PTR_TO_MEM]		= "mem", | ||||
| 	[PTR_TO_MEM_OR_NULL]	= "mem_or_null", | ||||
| 	[PTR_TO_RDONLY_BUF]	= "rdonly_buf", | ||||
| 	[PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null", | ||||
| 	[PTR_TO_RDWR_BUF]	= "rdwr_buf", | ||||
| 	[PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null", | ||||
| 	[PTR_TO_FUNC]		= "func", | ||||
| 	[PTR_TO_MAP_KEY]	= "map_key", | ||||
| }; | ||||
| /* string representation of 'enum bpf_reg_type'
 | ||||
|  * | ||||
|  * Note that reg_type_str() can not appear more than once in a single verbose() | ||||
|  * statement. | ||||
|  */ | ||||
| static const char *reg_type_str(struct bpf_verifier_env *env, | ||||
| 				enum bpf_reg_type type) | ||||
| { | ||||
| 	char postfix[16] = {0}; | ||||
| 	static const char * const str[] = { | ||||
| 		[NOT_INIT]		= "?", | ||||
| 		[SCALAR_VALUE]		= "inv", | ||||
| 		[PTR_TO_CTX]		= "ctx", | ||||
| 		[CONST_PTR_TO_MAP]	= "map_ptr", | ||||
| 		[PTR_TO_MAP_VALUE]	= "map_value", | ||||
| 		[PTR_TO_STACK]		= "fp", | ||||
| 		[PTR_TO_PACKET]		= "pkt", | ||||
| 		[PTR_TO_PACKET_META]	= "pkt_meta", | ||||
| 		[PTR_TO_PACKET_END]	= "pkt_end", | ||||
| 		[PTR_TO_FLOW_KEYS]	= "flow_keys", | ||||
| 		[PTR_TO_SOCKET]		= "sock", | ||||
| 		[PTR_TO_SOCK_COMMON]	= "sock_common", | ||||
| 		[PTR_TO_TCP_SOCK]	= "tcp_sock", | ||||
| 		[PTR_TO_TP_BUFFER]	= "tp_buffer", | ||||
| 		[PTR_TO_XDP_SOCK]	= "xdp_sock", | ||||
| 		[PTR_TO_BTF_ID]		= "ptr_", | ||||
| 		[PTR_TO_PERCPU_BTF_ID]	= "percpu_ptr_", | ||||
| 		[PTR_TO_MEM]		= "mem", | ||||
| 		[PTR_TO_RDONLY_BUF]	= "rdonly_buf", | ||||
| 		[PTR_TO_RDWR_BUF]	= "rdwr_buf", | ||||
| 		[PTR_TO_FUNC]		= "func", | ||||
| 		[PTR_TO_MAP_KEY]	= "map_key", | ||||
| 	}; | ||||
| 
 | ||||
| 	if (type & PTR_MAYBE_NULL) { | ||||
| 		if (base_type(type) == PTR_TO_BTF_ID || | ||||
| 		    base_type(type) == PTR_TO_PERCPU_BTF_ID) | ||||
| 			strncpy(postfix, "or_null_", 16); | ||||
| 		else | ||||
| 			strncpy(postfix, "_or_null", 16); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s", | ||||
| 		 str[base_type(type)], postfix); | ||||
| 	return env->type_str_buf; | ||||
| } | ||||
| 
 | ||||
| static char slot_type_char[] = { | ||||
| 	[STACK_INVALID]	= '?', | ||||
|  | @ -675,7 +673,7 @@ static void print_verifier_state(struct bpf_verifier_env *env, | |||
| 			continue; | ||||
| 		verbose(env, " R%d", i); | ||||
| 		print_liveness(env, reg->live); | ||||
| 		verbose(env, "=%s", reg_type_str[t]); | ||||
| 		verbose(env, "=%s", reg_type_str(env, t)); | ||||
| 		if (t == SCALAR_VALUE && reg->precise) | ||||
| 			verbose(env, "P"); | ||||
| 		if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && | ||||
|  | @ -683,9 +681,8 @@ static void print_verifier_state(struct bpf_verifier_env *env, | |||
| 			/* reg->off should be 0 for SCALAR_VALUE */ | ||||
| 			verbose(env, "%lld", reg->var_off.value + reg->off); | ||||
| 		} else { | ||||
| 			if (t == PTR_TO_BTF_ID || | ||||
| 			    t == PTR_TO_BTF_ID_OR_NULL || | ||||
| 			    t == PTR_TO_PERCPU_BTF_ID) | ||||
| 			if (base_type(t) == PTR_TO_BTF_ID || | ||||
| 			    base_type(t) == PTR_TO_PERCPU_BTF_ID) | ||||
| 				verbose(env, "%s", kernel_type_name(reg->btf, reg->btf_id)); | ||||
| 			verbose(env, "(id=%d", reg->id); | ||||
| 			if (reg_type_may_be_refcounted_or_null(t)) | ||||
|  | @ -694,10 +691,9 @@ static void print_verifier_state(struct bpf_verifier_env *env, | |||
| 				verbose(env, ",off=%d", reg->off); | ||||
| 			if (type_is_pkt_pointer(t)) | ||||
| 				verbose(env, ",r=%d", reg->range); | ||||
| 			else if (t == CONST_PTR_TO_MAP || | ||||
| 				 t == PTR_TO_MAP_KEY || | ||||
| 				 t == PTR_TO_MAP_VALUE || | ||||
| 				 t == PTR_TO_MAP_VALUE_OR_NULL) | ||||
| 			else if (base_type(t) == CONST_PTR_TO_MAP || | ||||
| 				 base_type(t) == PTR_TO_MAP_KEY || | ||||
| 				 base_type(t) == PTR_TO_MAP_VALUE) | ||||
| 				verbose(env, ",ks=%d,vs=%d", | ||||
| 					reg->map_ptr->key_size, | ||||
| 					reg->map_ptr->value_size); | ||||
|  | @ -769,7 +765,7 @@ static void print_verifier_state(struct bpf_verifier_env *env, | |||
| 		if (is_spilled_reg(&state->stack[i])) { | ||||
| 			reg = &state->stack[i].spilled_ptr; | ||||
| 			t = reg->type; | ||||
| 			verbose(env, "=%s", reg_type_str[t]); | ||||
| 			verbose(env, "=%s", reg_type_str(env, t)); | ||||
| 			if (t == SCALAR_VALUE && reg->precise) | ||||
| 				verbose(env, "P"); | ||||
| 			if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) | ||||
|  | @ -1202,8 +1198,7 @@ static void mark_reg_known_zero(struct bpf_verifier_env *env, | |||
| 
 | ||||
| static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) | ||||
| { | ||||
| 	switch (reg->type) { | ||||
| 	case PTR_TO_MAP_VALUE_OR_NULL: { | ||||
| 	if (base_type(reg->type) == PTR_TO_MAP_VALUE) { | ||||
| 		const struct bpf_map *map = reg->map_ptr; | ||||
| 
 | ||||
| 		if (map->inner_map_meta) { | ||||
|  | @ -1222,32 +1217,10 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) | |||
| 		} else { | ||||
| 			reg->type = PTR_TO_MAP_VALUE; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	case PTR_TO_SOCKET_OR_NULL: | ||||
| 		reg->type = PTR_TO_SOCKET; | ||||
| 		break; | ||||
| 	case PTR_TO_SOCK_COMMON_OR_NULL: | ||||
| 		reg->type = PTR_TO_SOCK_COMMON; | ||||
| 		break; | ||||
| 	case PTR_TO_TCP_SOCK_OR_NULL: | ||||
| 		reg->type = PTR_TO_TCP_SOCK; | ||||
| 		break; | ||||
| 	case PTR_TO_BTF_ID_OR_NULL: | ||||
| 		reg->type = PTR_TO_BTF_ID; | ||||
| 		break; | ||||
| 	case PTR_TO_MEM_OR_NULL: | ||||
| 		reg->type = PTR_TO_MEM; | ||||
| 		break; | ||||
| 	case PTR_TO_RDONLY_BUF_OR_NULL: | ||||
| 		reg->type = PTR_TO_RDONLY_BUF; | ||||
| 		break; | ||||
| 	case PTR_TO_RDWR_BUF_OR_NULL: | ||||
| 		reg->type = PTR_TO_RDWR_BUF; | ||||
| 		break; | ||||
| 	default: | ||||
| 		WARN_ONCE(1, "unknown nullable register type"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	reg->type &= ~PTR_MAYBE_NULL; | ||||
| } | ||||
| 
 | ||||
| static bool reg_is_pkt_pointer(const struct bpf_reg_state *reg) | ||||
|  | @ -2103,7 +2076,7 @@ static int mark_reg_read(struct bpf_verifier_env *env, | |||
| 			break; | ||||
| 		if (parent->live & REG_LIVE_DONE) { | ||||
| 			verbose(env, "verifier BUG type %s var_off %lld off %d\n", | ||||
| 				reg_type_str[parent->type], | ||||
| 				reg_type_str(env, parent->type), | ||||
| 				parent->var_off.value, parent->off); | ||||
| 			return -EFAULT; | ||||
| 		} | ||||
|  | @ -2768,9 +2741,8 @@ static int mark_chain_precision_stack(struct bpf_verifier_env *env, int spi) | |||
| 
 | ||||
| static bool is_spillable_regtype(enum bpf_reg_type type) | ||||
| { | ||||
| 	switch (type) { | ||||
| 	switch (base_type(type)) { | ||||
| 	case PTR_TO_MAP_VALUE: | ||||
| 	case PTR_TO_MAP_VALUE_OR_NULL: | ||||
| 	case PTR_TO_STACK: | ||||
| 	case PTR_TO_CTX: | ||||
| 	case PTR_TO_PACKET: | ||||
|  | @ -2779,21 +2751,14 @@ static bool is_spillable_regtype(enum bpf_reg_type type) | |||
| 	case PTR_TO_FLOW_KEYS: | ||||
| 	case CONST_PTR_TO_MAP: | ||||
| 	case PTR_TO_SOCKET: | ||||
| 	case PTR_TO_SOCKET_OR_NULL: | ||||
| 	case PTR_TO_SOCK_COMMON: | ||||
| 	case PTR_TO_SOCK_COMMON_OR_NULL: | ||||
| 	case PTR_TO_TCP_SOCK: | ||||
| 	case PTR_TO_TCP_SOCK_OR_NULL: | ||||
| 	case PTR_TO_XDP_SOCK: | ||||
| 	case PTR_TO_BTF_ID: | ||||
| 	case PTR_TO_BTF_ID_OR_NULL: | ||||
| 	case PTR_TO_RDONLY_BUF: | ||||
| 	case PTR_TO_RDONLY_BUF_OR_NULL: | ||||
| 	case PTR_TO_RDWR_BUF: | ||||
| 	case PTR_TO_RDWR_BUF_OR_NULL: | ||||
| 	case PTR_TO_PERCPU_BTF_ID: | ||||
| 	case PTR_TO_MEM: | ||||
| 	case PTR_TO_MEM_OR_NULL: | ||||
| 	case PTR_TO_FUNC: | ||||
| 	case PTR_TO_MAP_KEY: | ||||
| 		return true; | ||||
|  | @ -3633,7 +3598,7 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, | |||
| 		 */ | ||||
| 		*reg_type = info.reg_type; | ||||
| 
 | ||||
| 		if (*reg_type == PTR_TO_BTF_ID || *reg_type == PTR_TO_BTF_ID_OR_NULL) { | ||||
| 		if (base_type(*reg_type) == PTR_TO_BTF_ID) { | ||||
| 			*btf = info.btf; | ||||
| 			*btf_id = info.btf_id; | ||||
| 		} else { | ||||
|  | @ -3701,7 +3666,7 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, | |||
| 	} | ||||
| 
 | ||||
| 	verbose(env, "R%d invalid %s access off=%d size=%d\n", | ||||
| 		regno, reg_type_str[reg->type], off, size); | ||||
| 		regno, reg_type_str(env, reg->type), off, size); | ||||
| 
 | ||||
| 	return -EACCES; | ||||
| } | ||||
|  | @ -4466,7 +4431,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
| 			} else { | ||||
| 				mark_reg_known_zero(env, regs, | ||||
| 						    value_regno); | ||||
| 				if (reg_type_may_be_null(reg_type)) | ||||
| 				if (type_may_be_null(reg_type)) | ||||
| 					regs[value_regno].id = ++env->id_gen; | ||||
| 				/* A load of ctx field could have different
 | ||||
| 				 * actual load size with the one encoded in the | ||||
|  | @ -4474,8 +4439,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
| 				 * a sub-register. | ||||
| 				 */ | ||||
| 				regs[value_regno].subreg_def = DEF_NOT_SUBREG; | ||||
| 				if (reg_type == PTR_TO_BTF_ID || | ||||
| 				    reg_type == PTR_TO_BTF_ID_OR_NULL) { | ||||
| 				if (base_type(reg_type) == PTR_TO_BTF_ID) { | ||||
| 					regs[value_regno].btf = btf; | ||||
| 					regs[value_regno].btf_id = btf_id; | ||||
| 				} | ||||
|  | @ -4528,7 +4492,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
| 	} else if (type_is_sk_pointer(reg->type)) { | ||||
| 		if (t == BPF_WRITE) { | ||||
| 			verbose(env, "R%d cannot write into %s\n", | ||||
| 				regno, reg_type_str[reg->type]); | ||||
| 				regno, reg_type_str(env, reg->type)); | ||||
| 			return -EACCES; | ||||
| 		} | ||||
| 		err = check_sock_access(env, insn_idx, regno, off, size, t); | ||||
|  | @ -4547,7 +4511,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
| 	} else if (reg->type == PTR_TO_RDONLY_BUF) { | ||||
| 		if (t == BPF_WRITE) { | ||||
| 			verbose(env, "R%d cannot write into %s\n", | ||||
| 				regno, reg_type_str[reg->type]); | ||||
| 				regno, reg_type_str(env, reg->type)); | ||||
| 			return -EACCES; | ||||
| 		} | ||||
| 		err = check_buffer_access(env, reg, regno, off, size, false, | ||||
|  | @ -4563,7 +4527,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn | |||
| 			mark_reg_unknown(env, regs, value_regno); | ||||
| 	} else { | ||||
| 		verbose(env, "R%d invalid mem access '%s'\n", regno, | ||||
| 			reg_type_str[reg->type]); | ||||
| 			reg_type_str(env, reg->type)); | ||||
| 		return -EACCES; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -4630,7 +4594,7 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i | |||
| 	    is_sk_reg(env, insn->dst_reg)) { | ||||
| 		verbose(env, "BPF_ATOMIC stores into R%d %s is not allowed\n", | ||||
| 			insn->dst_reg, | ||||
| 			reg_type_str[reg_state(env, insn->dst_reg)->type]); | ||||
| 			reg_type_str(env, reg_state(env, insn->dst_reg)->type)); | ||||
| 		return -EACCES; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -4850,9 +4814,9 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno, | |||
| 		    register_is_null(reg)) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		verbose(env, "R%d type=%s expected=%s\n", regno, | ||||
| 			reg_type_str[reg->type], | ||||
| 			reg_type_str[PTR_TO_STACK]); | ||||
| 		verbose(env, "R%d type=%s ", regno, | ||||
| 			reg_type_str(env, reg->type)); | ||||
| 		verbose(env, "expected=%s\n", reg_type_str(env, PTR_TO_STACK)); | ||||
| 		return -EACCES; | ||||
| 	} | ||||
| } | ||||
|  | @ -4863,7 +4827,7 @@ int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg, | |||
| 	if (register_is_null(reg)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (reg_type_may_be_null(reg->type)) { | ||||
| 	if (type_may_be_null(reg->type)) { | ||||
| 		/* Assuming that the register contains a value check if the memory
 | ||||
| 		 * access is safe. Temporarily save and restore the register's state as | ||||
| 		 * the conversion shouldn't be visible to a caller. | ||||
|  | @ -5197,10 +5161,10 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno, | |||
| 			goto found; | ||||
| 	} | ||||
| 
 | ||||
| 	verbose(env, "R%d type=%s expected=", regno, reg_type_str[type]); | ||||
| 	verbose(env, "R%d type=%s expected=", regno, reg_type_str(env, type)); | ||||
| 	for (j = 0; j + 1 < i; j++) | ||||
| 		verbose(env, "%s, ", reg_type_str[compatible->types[j]]); | ||||
| 	verbose(env, "%s\n", reg_type_str[compatible->types[j]]); | ||||
| 		verbose(env, "%s, ", reg_type_str(env, compatible->types[j])); | ||||
| 	verbose(env, "%s\n", reg_type_str(env, compatible->types[j])); | ||||
| 	return -EACCES; | ||||
| 
 | ||||
| found: | ||||
|  | @ -6474,6 +6438,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| { | ||||
| 	const struct bpf_func_proto *fn = NULL; | ||||
| 	enum bpf_return_type ret_type; | ||||
| 	enum bpf_type_flag ret_flag; | ||||
| 	struct bpf_reg_state *regs; | ||||
| 	struct bpf_call_arg_meta meta; | ||||
| 	int insn_idx = *insn_idx_p; | ||||
|  | @ -6614,6 +6579,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 
 | ||||
| 	/* update return register (already marked as written above) */ | ||||
| 	ret_type = fn->ret_type; | ||||
| 	ret_flag = type_flag(fn->ret_type); | ||||
| 	if (ret_type == RET_INTEGER) { | ||||
| 		/* sets type to SCALAR_VALUE */ | ||||
| 		mark_reg_unknown(env, regs, BPF_REG_0); | ||||
|  | @ -6633,25 +6599,23 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 		} | ||||
| 		regs[BPF_REG_0].map_ptr = meta.map_ptr; | ||||
| 		regs[BPF_REG_0].map_uid = meta.map_uid; | ||||
| 		if (type_may_be_null(ret_type)) { | ||||
| 			regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL; | ||||
| 		} else { | ||||
| 			regs[BPF_REG_0].type = PTR_TO_MAP_VALUE; | ||||
| 			if (map_value_has_spin_lock(meta.map_ptr)) | ||||
| 				regs[BPF_REG_0].id = ++env->id_gen; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_MAP_VALUE | ret_flag; | ||||
| 		if (!type_may_be_null(ret_type) && | ||||
| 		    map_value_has_spin_lock(meta.map_ptr)) { | ||||
| 			regs[BPF_REG_0].id = ++env->id_gen; | ||||
| 		} | ||||
| 	} else if (base_type(ret_type) == RET_PTR_TO_SOCKET) { | ||||
| 		mark_reg_known_zero(env, regs, BPF_REG_0); | ||||
| 		regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_SOCKET | ret_flag; | ||||
| 	} else if (base_type(ret_type) == RET_PTR_TO_SOCK_COMMON) { | ||||
| 		mark_reg_known_zero(env, regs, BPF_REG_0); | ||||
| 		regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON_OR_NULL; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON | ret_flag; | ||||
| 	} else if (base_type(ret_type) == RET_PTR_TO_TCP_SOCK) { | ||||
| 		mark_reg_known_zero(env, regs, BPF_REG_0); | ||||
| 		regs[BPF_REG_0].type = PTR_TO_TCP_SOCK_OR_NULL; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_TCP_SOCK | ret_flag; | ||||
| 	} else if (base_type(ret_type) == RET_PTR_TO_ALLOC_MEM) { | ||||
| 		mark_reg_known_zero(env, regs, BPF_REG_0); | ||||
| 		regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag; | ||||
| 		regs[BPF_REG_0].mem_size = meta.mem_size; | ||||
| 	} else if (base_type(ret_type) == RET_PTR_TO_MEM_OR_BTF_ID) { | ||||
| 		const struct btf_type *t; | ||||
|  | @ -6671,14 +6635,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 					tname, PTR_ERR(ret)); | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			regs[BPF_REG_0].type = | ||||
| 				(ret_type & PTR_MAYBE_NULL) ? | ||||
| 				PTR_TO_MEM_OR_NULL : PTR_TO_MEM; | ||||
| 			regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag; | ||||
| 			regs[BPF_REG_0].mem_size = tsize; | ||||
| 		} else { | ||||
| 			regs[BPF_REG_0].type = | ||||
| 				(ret_type & PTR_MAYBE_NULL) ? | ||||
| 				PTR_TO_BTF_ID_OR_NULL : PTR_TO_BTF_ID; | ||||
| 			regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag; | ||||
| 			regs[BPF_REG_0].btf = meta.ret_btf; | ||||
| 			regs[BPF_REG_0].btf_id = meta.ret_btf_id; | ||||
| 		} | ||||
|  | @ -6686,9 +6646,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 		int ret_btf_id; | ||||
| 
 | ||||
| 		mark_reg_known_zero(env, regs, BPF_REG_0); | ||||
| 		regs[BPF_REG_0].type = (ret_type & PTR_MAYBE_NULL) ? | ||||
| 						     PTR_TO_BTF_ID_OR_NULL : | ||||
| 						     PTR_TO_BTF_ID; | ||||
| 		regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag; | ||||
| 		ret_btf_id = *fn->ret_btf_id; | ||||
| 		if (ret_btf_id == 0) { | ||||
| 			verbose(env, "invalid return type %u of func %s#%d\n", | ||||
|  | @ -6707,7 +6665,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn | |||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (reg_type_may_be_null(regs[BPF_REG_0].type)) | ||||
| 	if (type_may_be_null(regs[BPF_REG_0].type)) | ||||
| 		regs[BPF_REG_0].id = ++env->id_gen; | ||||
| 
 | ||||
| 	if (is_ptr_cast_function(func_id)) { | ||||
|  | @ -6916,25 +6874,25 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env, | |||
| 
 | ||||
| 	if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) { | ||||
| 		verbose(env, "math between %s pointer and %lld is not allowed\n", | ||||
| 			reg_type_str[type], val); | ||||
| 			reg_type_str(env, type), val); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) { | ||||
| 		verbose(env, "%s pointer offset %d is not allowed\n", | ||||
| 			reg_type_str[type], reg->off); | ||||
| 			reg_type_str(env, type), reg->off); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (smin == S64_MIN) { | ||||
| 		verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n", | ||||
| 			reg_type_str[type]); | ||||
| 			reg_type_str(env, type)); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { | ||||
| 		verbose(env, "value %lld makes %s pointer be out of bounds\n", | ||||
| 			smin, reg_type_str[type]); | ||||
| 			smin, reg_type_str(env, type)); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -7311,11 +7269,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
| 		return -EACCES; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (ptr_reg->type) { | ||||
| 	case PTR_TO_MAP_VALUE_OR_NULL: | ||||
| 	if (ptr_reg->type & PTR_MAYBE_NULL) { | ||||
| 		verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", | ||||
| 			dst, reg_type_str[ptr_reg->type]); | ||||
| 			dst, reg_type_str(env, ptr_reg->type)); | ||||
| 		return -EACCES; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (base_type(ptr_reg->type)) { | ||||
| 	case CONST_PTR_TO_MAP: | ||||
| 		/* smin_val represents the known value */ | ||||
| 		if (known && smin_val == 0 && opcode == BPF_ADD) | ||||
|  | @ -7323,14 +7283,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
| 		fallthrough; | ||||
| 	case PTR_TO_PACKET_END: | ||||
| 	case PTR_TO_SOCKET: | ||||
| 	case PTR_TO_SOCKET_OR_NULL: | ||||
| 	case PTR_TO_SOCK_COMMON: | ||||
| 	case PTR_TO_SOCK_COMMON_OR_NULL: | ||||
| 	case PTR_TO_TCP_SOCK: | ||||
| 	case PTR_TO_TCP_SOCK_OR_NULL: | ||||
| 	case PTR_TO_XDP_SOCK: | ||||
| 		verbose(env, "R%d pointer arithmetic on %s prohibited\n", | ||||
| 			dst, reg_type_str[ptr_reg->type]); | ||||
| 			dst, reg_type_str(env, ptr_reg->type)); | ||||
| 		return -EACCES; | ||||
| 	default: | ||||
| 		break; | ||||
|  | @ -9049,7 +9006,7 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state, | |||
| 				 struct bpf_reg_state *reg, u32 id, | ||||
| 				 bool is_null) | ||||
| { | ||||
| 	if (reg_type_may_be_null(reg->type) && reg->id == id && | ||||
| 	if (type_may_be_null(reg->type) && reg->id == id && | ||||
| 	    !WARN_ON_ONCE(!reg->id)) { | ||||
| 		/* Old offset (both fixed and variable parts) should
 | ||||
| 		 * have been known-zero, because we don't allow pointer | ||||
|  | @ -9427,7 +9384,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, | |||
| 	 */ | ||||
| 	if (!is_jmp32 && BPF_SRC(insn->code) == BPF_K && | ||||
| 	    insn->imm == 0 && (opcode == BPF_JEQ || opcode == BPF_JNE) && | ||||
| 	    reg_type_may_be_null(dst_reg->type)) { | ||||
| 	    type_may_be_null(dst_reg->type)) { | ||||
| 		/* Mark all identical registers in each branch as either
 | ||||
| 		 * safe or unknown depending R == 0 or R != 0 conditional. | ||||
| 		 */ | ||||
|  | @ -9681,7 +9638,7 @@ static int check_return_code(struct bpf_verifier_env *env) | |||
| 		/* enforce return zero from async callbacks like timer */ | ||||
| 		if (reg->type != SCALAR_VALUE) { | ||||
| 			verbose(env, "In async callback the register R0 is not a known value (%s)\n", | ||||
| 				reg_type_str[reg->type]); | ||||
| 				reg_type_str(env, reg->type)); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -9695,7 +9652,7 @@ static int check_return_code(struct bpf_verifier_env *env) | |||
| 	if (is_subprog) { | ||||
| 		if (reg->type != SCALAR_VALUE) { | ||||
| 			verbose(env, "At subprogram exit the register R0 is not a scalar value (%s)\n", | ||||
| 				reg_type_str[reg->type]); | ||||
| 				reg_type_str(env, reg->type)); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		return 0; | ||||
|  | @ -9759,7 +9716,7 @@ static int check_return_code(struct bpf_verifier_env *env) | |||
| 
 | ||||
| 	if (reg->type != SCALAR_VALUE) { | ||||
| 		verbose(env, "At program exit the register R0 is not a known value (%s)\n", | ||||
| 			reg_type_str[reg->type]); | ||||
| 			reg_type_str(env, reg->type)); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -10616,7 +10573,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, | |||
| 		return true; | ||||
| 	if (rcur->type == NOT_INIT) | ||||
| 		return false; | ||||
| 	switch (rold->type) { | ||||
| 	switch (base_type(rold->type)) { | ||||
| 	case SCALAR_VALUE: | ||||
| 		if (env->explore_alu_limits) | ||||
| 			return false; | ||||
|  | @ -10638,6 +10595,22 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, | |||
| 		} | ||||
| 	case PTR_TO_MAP_KEY: | ||||
| 	case PTR_TO_MAP_VALUE: | ||||
| 		/* a PTR_TO_MAP_VALUE could be safe to use as a
 | ||||
| 		 * PTR_TO_MAP_VALUE_OR_NULL into the same map. | ||||
| 		 * However, if the old PTR_TO_MAP_VALUE_OR_NULL then got NULL- | ||||
| 		 * checked, doing so could have affected others with the same | ||||
| 		 * id, and we can't check for that because we lost the id when | ||||
| 		 * we converted to a PTR_TO_MAP_VALUE. | ||||
| 		 */ | ||||
| 		if (type_may_be_null(rold->type)) { | ||||
| 			if (!type_may_be_null(rcur->type)) | ||||
| 				return false; | ||||
| 			if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, id))) | ||||
| 				return false; | ||||
| 			/* Check our ids match any regs they're supposed to */ | ||||
| 			return check_ids(rold->id, rcur->id, idmap); | ||||
| 		} | ||||
| 
 | ||||
| 		/* If the new min/max/var_off satisfy the old ones and
 | ||||
| 		 * everything else matches, we are OK. | ||||
| 		 * 'id' is not compared, since it's only used for maps with | ||||
|  | @ -10649,20 +10622,6 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, | |||
| 		return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && | ||||
| 		       range_within(rold, rcur) && | ||||
| 		       tnum_in(rold->var_off, rcur->var_off); | ||||
| 	case PTR_TO_MAP_VALUE_OR_NULL: | ||||
| 		/* a PTR_TO_MAP_VALUE could be safe to use as a
 | ||||
| 		 * PTR_TO_MAP_VALUE_OR_NULL into the same map. | ||||
| 		 * However, if the old PTR_TO_MAP_VALUE_OR_NULL then got NULL- | ||||
| 		 * checked, doing so could have affected others with the same | ||||
| 		 * id, and we can't check for that because we lost the id when | ||||
| 		 * we converted to a PTR_TO_MAP_VALUE. | ||||
| 		 */ | ||||
| 		if (rcur->type != PTR_TO_MAP_VALUE_OR_NULL) | ||||
| 			return false; | ||||
| 		if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, id))) | ||||
| 			return false; | ||||
| 		/* Check our ids match any regs they're supposed to */ | ||||
| 		return check_ids(rold->id, rcur->id, idmap); | ||||
| 	case PTR_TO_PACKET_META: | ||||
| 	case PTR_TO_PACKET: | ||||
| 		if (rcur->type != rold->type) | ||||
|  | @ -10691,11 +10650,8 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, | |||
| 	case PTR_TO_PACKET_END: | ||||
| 	case PTR_TO_FLOW_KEYS: | ||||
| 	case PTR_TO_SOCKET: | ||||
| 	case PTR_TO_SOCKET_OR_NULL: | ||||
| 	case PTR_TO_SOCK_COMMON: | ||||
| 	case PTR_TO_SOCK_COMMON_OR_NULL: | ||||
| 	case PTR_TO_TCP_SOCK: | ||||
| 	case PTR_TO_TCP_SOCK_OR_NULL: | ||||
| 	case PTR_TO_XDP_SOCK: | ||||
| 		/* Only valid matches are exact, which memcmp() above
 | ||||
| 		 * would have accepted | ||||
|  | @ -11221,17 +11177,13 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) | |||
| /* Return true if it's OK to have the same insn return a different type. */ | ||||
| static bool reg_type_mismatch_ok(enum bpf_reg_type type) | ||||
| { | ||||
| 	switch (type) { | ||||
| 	switch (base_type(type)) { | ||||
| 	case PTR_TO_CTX: | ||||
| 	case PTR_TO_SOCKET: | ||||
| 	case PTR_TO_SOCKET_OR_NULL: | ||||
| 	case PTR_TO_SOCK_COMMON: | ||||
| 	case PTR_TO_SOCK_COMMON_OR_NULL: | ||||
| 	case PTR_TO_TCP_SOCK: | ||||
| 	case PTR_TO_TCP_SOCK_OR_NULL: | ||||
| 	case PTR_TO_XDP_SOCK: | ||||
| 	case PTR_TO_BTF_ID: | ||||
| 	case PTR_TO_BTF_ID_OR_NULL: | ||||
| 		return false; | ||||
| 	default: | ||||
| 		return true; | ||||
|  | @ -11457,7 +11409,7 @@ static int do_check(struct bpf_verifier_env *env) | |||
| 			if (is_ctx_reg(env, insn->dst_reg)) { | ||||
| 				verbose(env, "BPF_ST stores into R%d %s is not allowed\n", | ||||
| 					insn->dst_reg, | ||||
| 					reg_type_str[reg_state(env, insn->dst_reg)->type]); | ||||
| 					reg_type_str(env, reg_state(env, insn->dst_reg)->type)); | ||||
| 				return -EACCES; | ||||
| 			} | ||||
| 
 | ||||
|  |  | |||
|  | @ -929,7 +929,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = { | |||
| 		{ offsetof(struct bpf_iter__bpf_sk_storage_map, sk), | ||||
| 		  PTR_TO_BTF_ID_OR_NULL }, | ||||
| 		{ offsetof(struct bpf_iter__bpf_sk_storage_map, value), | ||||
| 		  PTR_TO_RDWR_BUF_OR_NULL }, | ||||
| 		  PTR_TO_RDWR_BUF | PTR_MAYBE_NULL }, | ||||
| 	}, | ||||
| 	.seq_info		= &iter_seq_info, | ||||
| }; | ||||
|  |  | |||
|  | @ -1564,7 +1564,7 @@ static struct bpf_iter_reg sock_map_iter_reg = { | |||
| 	.ctx_arg_info_size	= 2, | ||||
| 	.ctx_arg_info		= { | ||||
| 		{ offsetof(struct bpf_iter__sockmap, key), | ||||
| 		  PTR_TO_RDONLY_BUF_OR_NULL }, | ||||
| 		  PTR_TO_RDONLY_BUF | PTR_MAYBE_NULL }, | ||||
| 		{ offsetof(struct bpf_iter__sockmap, sk), | ||||
| 		  PTR_TO_BTF_ID_OR_NULL }, | ||||
| 	}, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Hao Luo
						Hao Luo