Re: [PATCH bpf-next v4 2/8] bpf: Introduce global percpu data

Alexei Starovoitov
2026-04-15T02:19:15Z

On Tue, Apr 14, 2026 at 10:19:22PM +0800, Leon Hwang wrote:
> On 2026/4/14 22:10, bot+bpf-ci@kernel.org wrote:
> >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> >> index 1757c5720503..8ec24d63a2c4 100644
> >> --- a/kernel/bpf/verifier.c
> >> +++ b/kernel/bpf/verifier.c
> >> @@ -6362,7 +6362,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
> >> if (tnum_is_const(reg->var_off) &&
> >> bpf_map_is_rdonly(map) &&
> >> map->ops->map_direct_value_addr &&
> >> - map->map_type != BPF_MAP_TYPE_INSN_ARRAY) {
> >> + map->map_type != BPF_MAP_TYPE_INSN_ARRAY &&
> >> + map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY) {
> >
> > This correctly prevents constant folding of percpu array values in
> > check_mem_access(). However, should the same exclusion also be
> > added to const_reg_xfer() in kernel/bpf/const_fold.c?
> >
> > That function has a parallel constant folding path via
> > bpf_map_direct_read() that only excludes BPF_MAP_TYPE_INSN_ARRAY:
> >
> > kernel/bpf/const_fold.c:const_reg_xfer() {
> > ...
> > case BPF_LDX:
> > ...
> > if (!bpf_map_is_rdonly(map) ||
> > !map->ops->map_direct_value_addr ||
> > map->map_type == BPF_MAP_TYPE_INSN_ARRAY ||
> > off < 0 || off + size > map->value_size ||
> > bpf_map_direct_read(map, off, size, &val, is_ldsx)) {
> > *dst = unknown;
> > break;
> > }
> > ...
> > }
> >
> > Since percpu_array_map_ops now has map_direct_value_addr set,
> > bpf_map_direct_read() would dereference the raw percpu base pointer
> > directly, rather than the actual per-cpu address. For a frozen
> > read-only percpu array, the constant-folded value could differ from
> > what the program reads at runtime after the BPF_MOV64_PERCPU_REG
> > fixup converts the address to the correct per-cpu copy.
> >
> > In the v3 series, bpf_map_direct_read() itself had a guard
> > (map->map_type != BPF_MAP_TYPE_ARRAY), which protected all callers.
> > The v4 moved this to caller-side checks but appears to have missed
> > const_reg_xfer().
> >
> >
> Correct.
>
> Will add a guard in bpf_map_direct_read() in the next revision:
>
> if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
> return -EINVAL;

hold on.
map->ops->map_direct_value_addr &&
- map->map_type != BPF_MAP_TYPE_INSN_ARRAY) {
+ map->map_type != BPF_MAP_TYPE_INSN_ARRAY &&
+ map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY) {

map_direct_value_addr() is set, but then immediately disallowed ?
Where else it's used?

Even if value_addr is working, then map_direct_value_meta() looks broken.