Re: [PATCH bpf-next v5 2/3] bpf: Add validation for bpf_set_retval argument

From: Xu Kuohai

Date: Sat Jun 06 2026 - 06:05:01 EST


On 6/5/2026 11:19 PM, bot+bpf-ci@xxxxxxxxxx wrote:
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8ed484cb1a8a..a50280bb0d45 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9790,6 +9792,29 @@ static int do_refine_retval_range(struct bpf_verifier_env *env,
reg_set_urange32(ret_reg, 0, nr_cpu_ids - 1);
reg_bounds_sync(ret_reg);
break;
+ case BPF_FUNC_get_retval:
+ /*
+ * bpf_get_retval may see arbitrary value passed by bpf_prog_run_array_cg for
+ * CGROUP_GETSOCKOPT type.
+ */
+ if (prog_type == BPF_PROG_TYPE_CGROUP_SOCKOPT &&
+ env->prog->expected_attach_type == BPF_CGROUP_GETSOCKOPT)
+ break;
+
+ if (prog_type == BPF_PROG_TYPE_LSM &&
+ env->prog->expected_attach_type == BPF_LSM_CGROUP) {
+ if (!env->prog->aux->attach_func_proto->type)
+ break;
+ bpf_lsm_get_retval_range(env->prog, &range);

For a boolean LSM hook, bpf_lsm_get_retval_range() returns the range
[0, 1], and this code refines the bpf_get_retval() return register to
that range.

Can that static range be violated at runtime when multiple programs are
attached to the same cgroup hook with BPF_F_ALLOW_MULTI?

In bpf_prog_run_array_cg(), if an earlier program returns 0 the retval
is translated to an error:

if (!func_ret && !IS_ERR_VALUE((long)run_ctx.retval))
run_ctx.retval = -EPERM;

A later program that calls bpf_get_retval() would then receive -EPERM
(-1) at runtime, which is outside the [0, 1] range the verifier assumed
here.

Does this static-versus-runtime mismatch let the verifier reason about
bounds that the value can actually fall outside of?

This was raised on the v5 posting and does not appear to have a reply
yet:

https://lore.kernel.org/bpf/20260605144232.95A141F00893@xxxxxxxxxxxxxxx/


Yes, returning -EPERM for a boolean hook breaks the verifier assumption.
I will create a follow-up patch to fix it, as the current patchset has
already been applied.

+ } else {
+ range.minval = -MAX_ERRNO;
+ range.maxval = 0;
+ }
+
+ reg_set_srange64(ret_reg, range.minval, range.maxval);
+ reg_set_srange32(ret_reg, range.minval, range.maxval);
+ reg_bounds_sync(ret_reg);
+ break;
}

return reg_bounds_sanity_check(env, ret_reg, "retval");


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27021279696