Re: [PATCH bpf-next 1/4] bpf: Keep fault protection when merging pointer types

Eduard Zingerman <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <[email protected]>
On Thu, 2026-08-13 at 22:40 +0200, Daniel Borkmann wrote:

...

> +static bool may_fault_on_deref(enum bpf_reg_type type)
> +{
> +	/*
> +	 * The pointer types which must not be dereferenced without fault
> +	 * protection, that is, the ones bpf_convert_ctx_accesses() has to
> +	 * turn a BPF_LDX into a BPF_PROBE_MEM one for. Slightly wider than
> +	 * the list matched there, which relies on an untrusted PTR_TO_MEM
> +	 * always carrying MEM_RDONLY as well.
> +	 */
> +	return type == PTR_TO_BTF_ID || (type_flag(type) & PTR_UNTRUSTED);
> +}
> +
>  static bool is_load_acq_unsafe(struct bpf_verifier_env *env, int regno,
>  			       struct bpf_insn *insn)
>  {

...

> @@ -17021,11 +17025,24 @@ static bool is_ptr_to_mem(enum bpf_reg_type type)
>  	return base_type(type) == PTR_TO_MEM;
>  }
>  
> +static enum bpf_reg_type merge_ptr_types(enum bpf_reg_type type_a,
> +					 enum bpf_reg_type type_b)
> +{
> +	bool to_mem = is_ptr_to_mem(type_a) || is_ptr_to_mem(type_b);
> +	enum bpf_reg_type type_merged = to_mem ? PTR_TO_MEM : PTR_TO_BTF_ID;
> +
> +	if (may_fault_on_deref(type_a) || may_fault_on_deref(type_b))
> +		type_merged |= to_mem ? MEM_RDONLY | PTR_UNTRUSTED :
> +					PTR_UNTRUSTED;
> +	else
> +		type_merged |= ((type_a | type_b) & MEM_RDONLY);
> +	return type_merged;
> +}
> +
>  static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type type,
>  			     bool allow_trust_mismatch)
>  {
>  	enum bpf_reg_type *prev_type = &env->insn_aux_data[env->insn_idx].ptr_type;
> -	enum bpf_reg_type merged_type;
>  
>  	if (*prev_type == NOT_INIT) {
>  		/* Saw a valid insn
> @@ -17046,20 +17063,12 @@ static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type typ
>  		    is_ptr_to_mem_or_btf_id(*prev_type)) {
>  			/*
>  			 * Have to support a use case when one path through
> -			 * the program yields TRUSTED pointer while another
> -			 * is UNTRUSTED. Fallback to UNTRUSTED to generate
> -			 * BPF_PROBE_MEM/BPF_PROBE_MEMSX.
> -			 * Same behavior of MEM_RDONLY flag.
> +			 * the program yields a TRUSTED pointer while another
> +			 * is UNTRUSTED. Merge them into a type which keeps
> +			 * the BPF_PROBE_MEM/BPF_PROBE_MEMSX rewrite when
> +			 * either side needs it.
>  			 */
> -			if (is_ptr_to_mem(type) || is_ptr_to_mem(*prev_type))
> -				merged_type = PTR_TO_MEM;
> -			else
> -				merged_type = PTR_TO_BTF_ID;
> -			if ((type & PTR_UNTRUSTED) || (*prev_type & PTR_UNTRUSTED))
> -				merged_type |= PTR_UNTRUSTED;
> -			if ((type & MEM_RDONLY) || (*prev_type & MEM_RDONLY))
> -				merged_type |= MEM_RDONLY;
> -			*prev_type = merged_type;
> +			*prev_type = merge_ptr_types(type, *prev_type);
>  		} else {
>  			verbose(env, "same insn cannot be used with different pointers\n");
>  			return -EINVAL;

Given that we don't document the list of all valid flag and type
combinations, I think that extending bpf_convert_ctx_accesses() to
match base type and checking UNTRUSTED flag on it is more future proof
solution.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.