lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8d219c57-28d7-42be-93ec-7252b32239fb@huaweicloud.com>
Date: Thu, 15 Jan 2026 15:37:52 +0800
From: Xu Kuohai <xukuohai@...weicloud.com>
To: Anton Protopopov <a.s.protopopov@...il.com>
Cc: bpf@...r.kernel.org, linux-kernel@...r.kernel.org,
 linux-arm-kernel@...ts.infradead.org, Alexei Starovoitov <ast@...nel.org>,
 Daniel Borkmann <daniel@...earbox.net>, Andrii Nakryiko <andrii@...nel.org>,
 Martin KaFai Lau <martin.lau@...ux.dev>, Eduard Zingerman
 <eddyz87@...il.com>, Yonghong Song <yonghong.song@...ux.dev>,
 Puranjay Mohan <puranjay@...nel.org>
Subject: Re: [PATCH bpf-next v4 2/4] bpf: Add helper to detect indirect jump
 targets

On 1/14/2026 7:00 PM, Anton Protopopov wrote:

[...]

>> +
>> +bool bpf_insn_is_indirect_target(const struct bpf_prog *prog, int idx)
>> +{
>> +	return prog->aux->insn_aux && prog->aux->insn_aux[idx].indirect_target;
> 
> Is there a case when insn_aux is NULL?
>

It is NULL when there is no indirect jump targets for the bpf prog, see the
has_indirect_target test in clone_insn_aux_data.

>> +}
>>   #endif /* CONFIG_BPF_JIT */
>>   
>>   /* Base function for offset calculation. Needs to go into .text section,
>> @@ -2540,24 +2579,24 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
>>   	if (!bpf_prog_is_offloaded(fp->aux)) {
>>   		*err = bpf_prog_alloc_jited_linfo(fp);
>>   		if (*err)
>> -			return fp;
>> +			goto free_insn_aux;
>>   
>>   		fp = bpf_int_jit_compile(fp);
>>   		bpf_prog_jit_attempt_done(fp);
>>   		if (!fp->jited && jit_needed) {
>>   			*err = -ENOTSUPP;
>> -			return fp;
>> +			goto free_insn_aux;
>>   		}
>>   	} else {
>>   		*err = bpf_prog_offload_compile(fp);
>>   		if (*err)
>> -			return fp;
>> +			goto free_insn_aux;
>>   	}
>>   
>>   finalize:
>>   	*err = bpf_prog_lock_ro(fp);
>>   	if (*err)
>> -		return fp;
>> +		goto free_insn_aux;
>>   
>>   	/* The tail call compatibility check can only be done at
>>   	 * this late stage as we need to determine, if we deal
>> @@ -2566,6 +2605,10 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
>>   	 */
>>   	*err = bpf_check_tail_call(fp);
>>   
>> +free_insn_aux:
>> +	vfree(fp->aux->insn_aux);
>> +	fp->aux->insn_aux = NULL;
>> +
>>   	return fp;
>>   }
>>   EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 22605d9e0ffa..f2fe6baeceb9 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -3852,6 +3852,11 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx)
>>   	return env->insn_aux_data[insn_idx].jmp_point;
>>   }
>>   
>> +static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
>> +{
>> +	env->insn_aux_data[idx].indirect_target = true;
>> +}
>> +
>>   #define LR_FRAMENO_BITS	3
>>   #define LR_SPI_BITS	6
>>   #define LR_ENTRY_BITS	(LR_SPI_BITS + LR_FRAMENO_BITS + 1)
>> @@ -20337,6 +20342,7 @@ static int check_indirect_jump(struct bpf_verifier_env *env, struct bpf_insn *in
>>   	}
>>   
>>   	for (i = 0; i < n; i++) {
> 
> ^ n -> n-1
>

ACK

>> +		mark_indirect_target(env, env->gotox_tmp_buf->items[i]);
>>   		other_branch = push_stack(env, env->gotox_tmp_buf->items[i],
>>   					  env->insn_idx, env->cur_state->speculative);
>>   		if (IS_ERR(other_branch))
>> @@ -21243,6 +21249,37 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
>>   	}
> 
> mark_indirect_target(n-1)
> 
>>   }
>>   
>> +static int clone_insn_aux_data(struct bpf_prog *prog, struct bpf_verifier_env *env, u32 off)
>> +{
>> +	u32 i;
>> +	size_t size;
>> +	bool has_indirect_target = false;
>> +	struct bpf_insn_aux_data *insn_aux;
>> +
>> +	for (i = 0; i < prog->len; i++) {
>> +		if (env->insn_aux_data[off + i].indirect_target) {
>> +			has_indirect_target = true;
>> +			break;
>> +		}
>> +	}
>> +
>> +	/* insn_aux is copied into bpf_prog so the JIT can check whether an instruction is an
>> +	 * indirect jump target. If no indirect jump targets exist, copying is unnecessary.
>> +	 */
>> +	if (!has_indirect_target)
>> +		return 0;
>> +
>> +	size = array_size(sizeof(struct bpf_insn_aux_data), prog->len);
>> +	insn_aux = vzalloc(size);
>> +	if (!insn_aux)
>> +		return -ENOMEM;
>> +
>> +	memcpy(insn_aux, env->insn_aux_data + off, size);
>> +	prog->aux->insn_aux = insn_aux;
>> +
>> +	return 0;
>> +}
>> +
>>   /* single env->prog->insni[off] instruction was replaced with the range
>>    * insni[off, off + cnt).  Adjust corresponding insn_aux_data by copying
>>    * [0, off) and [off, end) to new locations, so the patched range stays zero
>> @@ -22239,6 +22276,10 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>>   		if (!i)
>>   			func[i]->aux->exception_boundary = env->seen_exception;
>>   
>> +		err = clone_insn_aux_data(func[i], env, subprog_start);
>> +		if (err < 0)
>> +			goto out_free;
>> +
>>   		/*
>>   		 * To properly pass the absolute subprog start to jit
>>   		 * all instruction adjustments should be accumulated
>> @@ -22306,6 +22347,8 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>>   	for (i = 0; i < env->subprog_cnt; i++) {
>>   		func[i]->aux->used_maps = NULL;
>>   		func[i]->aux->used_map_cnt = 0;
>> +		vfree(func[i]->aux->insn_aux);
>> +		func[i]->aux->insn_aux = NULL;
>>   	}
>>   
>>   	/* finally lock prog and jit images for all functions and
>> @@ -22367,6 +22410,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>>   	for (i = 0; i < env->subprog_cnt; i++) {
>>   		if (!func[i])
>>   			continue;
>> +		vfree(func[i]->aux->insn_aux);
>>   		func[i]->aux->poke_tab = NULL;
>>   		bpf_jit_free(func[i]);
>>   	}
>> @@ -25350,6 +25394,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
>>   	env->verification_time = ktime_get_ns() - start_time;
>>   	print_verification_stats(env);
>>   	env->prog->aux->verified_insns = env->insn_processed;
>> +	env->prog->aux->insn_aux = env->insn_aux_data;
>>   
>>   	/* preserve original error even if log finalization is successful */
>>   	err = bpf_vlog_finalize(&env->log, &log_true_size);
>> @@ -25428,7 +25473,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
>>   	if (!is_priv)
>>   		mutex_unlock(&bpf_verifier_lock);
>>   	clear_insn_aux_data(env, 0, env->prog->len);
>> -	vfree(env->insn_aux_data);
>> +	/* on success, insn_aux_data will be freed by bpf_prog_select_runtime */
>> +	if (ret) {
>> +		vfree(env->insn_aux_data);
>> +		env->prog->aux->insn_aux = NULL;
>> +	}
>>   err_free_env:
>>   	bpf_stack_liveness_free(env);
>>   	kvfree(env->cfg.insn_postorder);
>> -- 
>> 2.47.3
>>
> 
> LGTM, just in case, could you please tell how you have tested
> this patchset exactly?

I ran test_progs-cpuv4 on machines supporting x86 CET/IBT and arm64 BTI. I tested in three
environments: an arm64 physical machine with BTI support (CPU: Hisilicon KP920B), an arm64
QEMU VM using cpu=max for BTI support, and a Bochs VM with model=arrow_lake for x86 CET/IBT
support.


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ