Sashiko discussions
 help / color / mirror / Atom feed
* Re: [PATCH bpf-next v2 10/23] bpf: Reject stack arguments in non-JITed programs
       [not found] ` <20260509021019.9F580C2BCB0@smtp.kernel.org>
@ 2026-05-10 16:59   ` Yonghong Song
  0 siblings, 0 replies; only message in thread
From: Yonghong Song @ 2026-05-10 16:59 UTC (permalink / raw)
  To: sashiko; +Cc: bpf



On 5/9/26 4:10 AM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The BPF verifier fails to reject the interpreter for a main program (i = 0) with stack arguments, leading to an uninitialized memory read of R11.
> --
>
> commit 4a48796d8e4e4607bc163fc6b59a84f3495c3d5c
> Author: Yonghong Song <yonghong.song@linux.dev>
>
> bpf: Reject stack arguments in non-JITed programs
>
> This commit aims to prevent non-JITed programs from running if they use
> stack arguments, since the BPF interpreter does not populate the register
> used for stack arguments (R11). It updates the runtime selection and fixups
> phases to reject such programs.
>
>> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
>> index ae10b9ca018df..6f94b0ef3659f 100644
>> --- a/kernel/bpf/core.c
>> +++ b/kernel/bpf/core.c
> [ ... ]
>> @@ -2599,7 +2599,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct
>>   		goto finalize;
>>   
>>   	if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) ||
>> -	    bpf_prog_has_kfunc_call(fp))
>> +	    bpf_prog_has_kfunc_call(fp) || fp->aux->stack_arg_cnt)
> Is fp->aux->stack_arg_cnt guaranteed to be initialized at this stage?

I would say yes. The main program is coverred in bpf_jit_subprogs():

         if (env->subprog_cnt <= 1) {
                 env->prog->aux->stack_arg_cnt = env->subprog_info[0].stack_arg_cnt;
                 return 0;
         }

For >= 2 number of subprogs, the stack_arg_cnt will set up in jit_subprogs().

>
> If JIT is disabled system-wide (e.g. sysctl net.core.bpf_jit_enable=0),
> bpf_jit_subprogs() is skipped, leaving the count at 0. Furthermore, even if
> JIT is enabled but the program has multiple subprograms, bpf_jit_subprogs()
> only populates the cloned subprograms' auxiliary data, leaving the main
> program's prog->aux->stack_arg_cnt as 0.
>
> Could this allow the check to be bypassed for the main program?

If JIT is disabled, we have

         for (i = 1; i < env->subprog_cnt; i++) {
                 if (bpf_in_stack_arg_cnt(&env->subprog_info[i])) {
                         verbose(env, "stack args are not supported in non-JITed programs\n");
                         return -EINVAL;
                 }
         }

So for any subprog having >5 arguments, interpreter will not run.

For main program, the above env->prog->aux->stack_arg_cnt later will
be used in core.c to decide whether interpreter can run or not.

>
>>   		jit_needed = true;
>>   
>>   	if (!bpf_prog_select_interpreter(fp))
>> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
>> index 0ff8cdf4394f4..4c630d97eaade 100644
>> --- a/kernel/bpf/fixups.c
>> +++ b/kernel/bpf/fixups.c
> [ ... ]
>> @@ -1412,6 +1412,12 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
>>   		verbose(env, "calling kernel functions are not allowed in non-JITed programs\n");
>>   		return -EINVAL;
>>   	}
>> +	for (i = 1; i < env->subprog_cnt; i++) {
> This loop explicitly starts at i = 1, which skips checking the main program.
>
> If an extension program (BPF_PROG_TYPE_EXT) attaches to a function with more
> than 5 arguments and has BTF_FUNC_STATIC linkage, it will inherit the incoming
> stack arguments. Since the check in core.c might fail to catch the main
> program due to the uninitialized stack_arg_cnt, can this extension program
> bypass both rejection mechanisms and fall back to the interpreter?

Currently, BPF_PROG_TYPE_EXT programs does not support more than 5 arguments.

>
>> +		if (bpf_in_stack_arg_cnt(&env->subprog_info[i])) {
>> +			verbose(env, "stack args are not supported in non-JITed programs\n");
>> +			return -EINVAL;
>> +		}
>> +	}
> If the main program bypasses these checks and is run by the interpreter, it
> will attempt to read incoming stack arguments from regs[11]. Because the
> interpreter's setup in ___bpf_prog_run() only initializes R1-R5 and the frame
> pointer, would reading regs[11] leak uninitialized kernel stack memory or
> cause a crash if the uninitialized value is dereferenced as a pointer?

In the new revision, we will have

@@ -18160,8 +18347,11 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
                  */
                 if (env->prog->aux->func_info_aux) {
                         ret = btf_prepare_func_args(env, 0);
-                       if (ret || sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_PTR_TO_CTX)
+                       if (ret || sub->arg_cnt != 1 || sub->args[0].arg_type != ARG_PTR_TO_CTX) {
                                 env->prog->aux->func_info_aux[0].unreliable = true;
+                               sub->arg_cnt = 1;
+                               sub->stack_arg_cnt = 0;
+                       }
                 }

In this case, stack_arg_cnt = 0 means incoming stack argumnet cnt is 0, so
any reading incoming stack arguments will cause verification failure.

>
>>   	if (env->subprog_cnt > 1 && env->prog->aux->tail_call_reachable) {
>>   		/* When JIT fails the progs with bpf2bpf calls and tail_calls
>>   		 * have to be rejected, since interpreter doesn't support them yet.


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-05-10 16:59 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260507213034.1130443-1-yonghong.song@linux.dev>
     [not found] ` <20260509021019.9F580C2BCB0@smtp.kernel.org>
2026-05-10 16:59   ` [PATCH bpf-next v2 10/23] bpf: Reject stack arguments in non-JITed programs Yonghong Song

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox