From: Daniel Borkmann <daniel@iogearbox.net> mainline inclusion from mainline-v7.1-rc1 commit 9f118095dd341885dbc3f1cd6a028414da099aba category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9180 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- When a pkt pointer acquires AT_PKT_END or BEYOND_PKT_END range from a comparison, and then, known-constant arithmetic is performed, adjust_ptr_min_max_vals() copies the stale range via dst_reg->raw = ptr_reg->raw without clearing the negative reg->range sentinel values. This lets is_pkt_ptr_branch_taken() choose one branch direction and skip going through the other. Fix this by clearing negative pkt range values (that is, AT_PKT_END and BEYOND_PKT_END) after arithmetic on pkt pointers. This ensures is_pkt_ptr_branch_taken() returns unknown and both branches are properly verified. Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.") Reported-by: STAR Labs SG <info@starlabs.sg> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/r/20260409155016.536608-1-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org> Conflicts: kernel/bpf/verifier.c [Not merged commit 022ac0750883] Signed-off-by: Pu Lehui <pulehui@huawei.com> --- kernel/bpf/verifier.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7ad363512643..e9cfb22d4a31 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12881,6 +12881,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, dst_reg->var_off = ptr_reg->var_off; dst_reg->off = ptr_reg->off + smin_val; dst_reg->raw = ptr_reg->raw; + + if (reg_is_pkt_pointer(ptr_reg)) { + /* + * Clear AT_PKT_END / BEYOND_PKT_END from prior comparison + * as any pointer arithmetic invalidates them. + */ + if (dst_reg->range < 0) + memset(&dst_reg->raw, 0, sizeof(dst_reg->raw)); + } break; } /* A new variable offset is created. Note that off_reg->off @@ -12913,7 +12922,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, dst_reg->raw = ptr_reg->raw; if (reg_is_pkt_pointer(ptr_reg)) { dst_reg->id = ++env->id_gen; - /* something was added to pkt_ptr, set range to zero */ + /* + * Clear range for unknown addends since we can't know + * where the pkt pointer ended up. + */ memset(&dst_reg->raw, 0, sizeof(dst_reg->raw)); } break; @@ -12944,6 +12956,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, dst_reg->id = ptr_reg->id; dst_reg->off = ptr_reg->off - smin_val; dst_reg->raw = ptr_reg->raw; + + if (reg_is_pkt_pointer(ptr_reg)) { + /* + * Clear AT_PKT_END / BEYOND_PKT_END from prior comparison + * as arithmetic invalidates them. + */ + if (dst_reg->range < 0) + memset(&dst_reg->raw, 0, sizeof(dst_reg->raw)); + } break; } /* A new variable offset is created. If the subtrahend is known @@ -12972,8 +12993,14 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, dst_reg->raw = ptr_reg->raw; if (reg_is_pkt_pointer(ptr_reg)) { dst_reg->id = ++env->id_gen; - /* something was added to pkt_ptr, set range to zero */ - if (smin_val < 0) + /* + * Clear range if the subtrahend may be negative since + * pkt pointer could move past its bounds. A positive + * subtrahend moves it backwards keeping positive range + * intact. Also clear AT_PKT_END / BEYOND_PKT_END from + * prior comparison as arithmetic invalidates them. + */ + if (smin_val < 0 || dst_reg->range < 0) memset(&dst_reg->raw, 0, sizeof(dst_reg->raw)); } break; -- 2.34.1