* [PATCH bpf 0/2] Keep dynamic inner array lookups nullable @ 2026-06-04 15:11 Nuiqi Gui 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui 2026-06-04 15:11 ` [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability Nuiqi Gui 0 siblings, 2 replies; 7+ messages in thread From: Nuiqi Gui @ 2026-06-04 15:11 UTC (permalink / raw) To: ast, daniel, andrii; +Cc: dxu, Nuiqi Gui, bpf An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its inner map template. The flag allows a concrete inner array with a different max_entries value to replace the template. The verifier currently uses the template's max_entries to elide nullness for a constant-key lookup through the inner map pointer. At runtime, the lookup uses the concrete inner array's max_entries instead. The verifier can therefore accept an unchecked dereference even though the runtime helper returns NULL. Patch 1 keeps lookups through BPF_F_INNER_MAP array templates nullable. Patch 2 adds a verifier regression test for the unchecked dereference. Before the fix, the regression program is accepted and the runtime reproducer triggers a NULL dereference. With the fix, both programs are rejected with an invalid map_value_or_null access. Tested by compiling kernel/bpf/verifier.o and verifier_map_in_map.bpf.o, and by running the regression program and runtime reproducer in QEMU before and after the fix. Nuiqi Gui (2): bpf: Keep dynamic inner array lookups nullable selftests/bpf: Cover dynamic inner array lookup nullability kernel/bpf/verifier.c | 13 +++--- .../selftests/bpf/progs/verifier_map_in_map.c | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf 1/2] bpf: Keep dynamic inner array lookups nullable 2026-06-04 15:11 [PATCH bpf 0/2] Keep dynamic inner array lookups nullable Nuiqi Gui @ 2026-06-04 15:11 ` Nuiqi Gui 2026-06-04 18:13 ` Magneto ` (2 more replies) 2026-06-04 15:11 ` [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability Nuiqi Gui 1 sibling, 3 replies; 7+ messages in thread From: Nuiqi Gui @ 2026-06-04 15:11 UTC (permalink / raw) To: ast, daniel, andrii Cc: dxu, Nuiqi Gui, stable, John Fastabend, Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its inner map template. A concrete inner array with a different max_entries value can then replace the template. After a successful outer map lookup, the verifier represents the resulting map pointer using the inner map template. Const-key lookup nullness elision consequently uses the template max_entries even though the runtime helper uses the concrete inner map max_entries. Do not elide lookup result nullness for maps marked with BPF_F_INNER_MAP, because the template max_entries does not prove that the key is in bounds for the concrete runtime map. Fixes: d2102f2f5d75 ("bpf: verifier: Support eliding map lookup nullness") Cc: stable@vger.kernel.org Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> --- kernel/bpf/verifier.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7fb88e1cd7c4d..bffe12d0bb289 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8471,7 +8471,7 @@ static int get_constant_map_key(struct bpf_verifier_env *env, return 0; } -static bool can_elide_value_nullness(enum bpf_map_type type); +static bool can_elide_value_nullness(const struct bpf_map *map); static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_call_arg_meta *meta, @@ -8621,7 +8621,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL); if (err) return err; - if (can_elide_value_nullness(meta->map.ptr->map_type)) { + if (can_elide_value_nullness(meta->map.ptr)) { err = get_constant_map_key(env, reg, key_size, &meta->const_map_key); if (err < 0) { meta->const_map_key = -1; @@ -10225,9 +10225,12 @@ static void update_loop_inline_state(struct bpf_verifier_env *env, u32 subprogno * lookup return value nullness check. This is possible if the key * is statically known. */ -static bool can_elide_value_nullness(enum bpf_map_type type) +static bool can_elide_value_nullness(const struct bpf_map *map) { - switch (type) { + if (map->map_flags & BPF_F_INNER_MAP) + return false; + + switch (map->map_type) { case BPF_MAP_TYPE_ARRAY: case BPF_MAP_TYPE_PERCPU_ARRAY: return true; @@ -10589,7 +10592,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn } if (func_id == BPF_FUNC_map_lookup_elem && - can_elide_value_nullness(meta.map.ptr->map_type) && + can_elide_value_nullness(meta.map.ptr) && meta.const_map_key >= 0 && meta.const_map_key < meta.map.ptr->max_entries) ret_flag &= ~PTR_MAYBE_NULL; -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Keep dynamic inner array lookups nullable 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui @ 2026-06-04 18:13 ` Magneto 2026-06-04 18:35 ` Suchit Karunakaran 2026-06-05 9:47 ` Eduard Zingerman 2 siblings, 0 replies; 7+ messages in thread From: Magneto @ 2026-06-04 18:13 UTC (permalink / raw) To: Nuiqi Gui Cc: ast, daniel, andrii, dxu, stable, John Fastabend, Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel On Thu, Jun 4, 2026 at 9:00 PM Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> wrote: > > An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its > inner map template. A concrete inner array with a different max_entries > value can then replace the template. > > After a successful outer map lookup, the verifier represents the > resulting map pointer using the inner map template. Const-key lookup > nullness elision consequently uses the template max_entries even though > the runtime helper uses the concrete inner map max_entries. > > Do not elide lookup result nullness for maps marked with BPF_F_INNER_MAP, > because the template max_entries does not prove that the key is in bounds > for the concrete runtime map. > > Fixes: d2102f2f5d75 ("bpf: verifier: Support eliding map lookup nullness") > Cc: stable@vger.kernel.org > Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> > --- > kernel/bpf/verifier.c | 13 ++++++++----- > 1 file changed, 8 insertions(+), 5 deletions(-) > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 7fb88e1cd7c4d..bffe12d0bb289 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -8471,7 +8471,7 @@ static int get_constant_map_key(struct bpf_verifier_env *env, > return 0; > } > > -static bool can_elide_value_nullness(enum bpf_map_type type); > +static bool can_elide_value_nullness(const struct bpf_map *map); > > static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > struct bpf_call_arg_meta *meta, > @@ -8621,7 +8621,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL); > if (err) > return err; > - if (can_elide_value_nullness(meta->map.ptr->map_type)) { > + if (can_elide_value_nullness(meta->map.ptr)) { > err = get_constant_map_key(env, reg, key_size, &meta->const_map_key); > if (err < 0) { > meta->const_map_key = -1; > @@ -10225,9 +10225,12 @@ static void update_loop_inline_state(struct bpf_verifier_env *env, u32 subprogno > * lookup return value nullness check. This is possible if the key > * is statically known. > */ > -static bool can_elide_value_nullness(enum bpf_map_type type) > +static bool can_elide_value_nullness(const struct bpf_map *map) > { > - switch (type) { > + if (map->map_flags & BPF_F_INNER_MAP) > + return false; One small nit: the can_elide_value_nullness() function comment appears to be out of sync with the updated parameter. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Keep dynamic inner array lookups nullable 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui 2026-06-04 18:13 ` Magneto @ 2026-06-04 18:35 ` Suchit Karunakaran 2026-06-05 9:47 ` Eduard Zingerman 2 siblings, 0 replies; 7+ messages in thread From: Suchit Karunakaran @ 2026-06-04 18:35 UTC (permalink / raw) To: Nuiqi Gui Cc: ast, daniel, andrii, dxu, stable, John Fastabend, Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel On Thu, Jun 04, 2026 at 11:11:52PM +0800, Nuiqi Gui wrote: > An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its > inner map template. A concrete inner array with a different max_entries > value can then replace the template. > > After a successful outer map lookup, the verifier represents the > resulting map pointer using the inner map template. Const-key lookup > nullness elision consequently uses the template max_entries even though > the runtime helper uses the concrete inner map max_entries. > > Do not elide lookup result nullness for maps marked with BPF_F_INNER_MAP, > because the template max_entries does not prove that the key is in bounds > for the concrete runtime map. > > Fixes: d2102f2f5d75 ("bpf: verifier: Support eliding map lookup nullness") > Cc: stable@vger.kernel.org > Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> > --- > kernel/bpf/verifier.c | 13 ++++++++----- > 1 file changed, 8 insertions(+), 5 deletions(-) > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 7fb88e1cd7c4d..bffe12d0bb289 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -8471,7 +8471,7 @@ static int get_constant_map_key(struct bpf_verifier_env *env, > return 0; > } > > -static bool can_elide_value_nullness(enum bpf_map_type type); > +static bool can_elide_value_nullness(const struct bpf_map *map); > > static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > struct bpf_call_arg_meta *meta, > @@ -8621,7 +8621,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL); > if (err) > return err; > - if (can_elide_value_nullness(meta->map.ptr->map_type)) { > + if (can_elide_value_nullness(meta->map.ptr)) { > err = get_constant_map_key(env, reg, key_size, &meta->const_map_key); > if (err < 0) { > meta->const_map_key = -1; > @@ -10225,9 +10225,12 @@ static void update_loop_inline_state(struct bpf_verifier_env *env, u32 subprogno > * lookup return value nullness check. This is possible if the key > * is statically known. > */ > -static bool can_elide_value_nullness(enum bpf_map_type type) > +static bool can_elide_value_nullness(const struct bpf_map *map) > { > - switch (type) { > + if (map->map_flags & BPF_F_INNER_MAP) > + return false; One small nit: the can_elide_value_nullness() function comment appears to be out of sync with the updated parameter. Resending because somehow my mutt config got messed up with my other email address. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Keep dynamic inner array lookups nullable 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui 2026-06-04 18:13 ` Magneto 2026-06-04 18:35 ` Suchit Karunakaran @ 2026-06-05 9:47 ` Eduard Zingerman 2 siblings, 0 replies; 7+ messages in thread From: Eduard Zingerman @ 2026-06-05 9:47 UTC (permalink / raw) To: Nuiqi Gui, ast, daniel, andrii Cc: dxu, stable, John Fastabend, Martin KaFai Lau, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel On Thu, 2026-06-04 at 23:11 +0800, Nuiqi Gui wrote: > An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its > inner map template. A concrete inner array with a different max_entries > value can then replace the template. > > After a successful outer map lookup, the verifier represents the > resulting map pointer using the inner map template. Const-key lookup > nullness elision consequently uses the template max_entries even though > the runtime helper uses the concrete inner map max_entries. > > Do not elide lookup result nullness for maps marked with BPF_F_INNER_MAP, > because the template max_entries does not prove that the key is in bounds > for the concrete runtime map. > > Fixes: d2102f2f5d75 ("bpf: verifier: Support eliding map lookup nullness") > Cc: stable@vger.kernel.org > Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> > --- Thank you for spotting this issue. Acked-by: Eduard Zingerman <eddyz87@gmail.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability 2026-06-04 15:11 [PATCH bpf 0/2] Keep dynamic inner array lookups nullable Nuiqi Gui 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui @ 2026-06-04 15:11 ` Nuiqi Gui 2026-06-05 9:48 ` Eduard Zingerman 1 sibling, 1 reply; 7+ messages in thread From: Nuiqi Gui @ 2026-06-04 15:11 UTC (permalink / raw) To: ast, daniel, andrii Cc: dxu, Nuiqi Gui, Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Ihor Solodrai, bpf, linux-kselftest, linux-kernel Add a verifier regression test that looks up a constant key through a dynamic inner array template and dereferences the result without a NULL check. The verifier must reject the program because BPF_F_INNER_MAP allows the concrete runtime array to have fewer entries than the template. Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> --- .../selftests/bpf/progs/verifier_map_in_map.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c index 16b761e510f0d..b606b5dca7340 100644 --- a/tools/testing/selftests/bpf/progs/verifier_map_in_map.c +++ b/tools/testing/selftests/bpf/progs/verifier_map_in_map.c @@ -18,6 +18,20 @@ struct { }); } map_in_map SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); + __array(values, struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(map_flags, BPF_F_INNER_MAP); + __uint(max_entries, 8); + __type(key, int); + __type(value, long); + }); +} map_in_map_dyn SEC(".maps"); + SEC("socket") __description("map in map access") __success __success_unpriv __retval(0) @@ -45,6 +59,32 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("socket") +__description("map in map dynamic inner array lookup is nullable") +__failure __msg("invalid mem access 'map_value_or_null'") +__naked void map_in_map_dynamic_inner_array_lookup_is_nullable(void) +{ + asm volatile (" \ + r1 = 0; \ + *(u32*)(r10 - 4) = r1; \ + r2 = r10; \ + r2 += -4; \ + r1 = %[map_in_map_dyn] ll; \ + call %[bpf_map_lookup_elem]; \ + if r0 == 0 goto l0_%=; \ + *(u32*)(r10 - 8) = 4; \ + r2 = r10; \ + r2 += -8; \ + r1 = r0; \ + call %[bpf_map_lookup_elem]; \ + r0 = *(u64 *)(r0 + 0); \ +l0_%=: exit; \ +" : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_in_map_dyn) + : __clobber_all); +} + SEC("xdp") __description("map in map state pruning") __success __msg("processed 15 insns") -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability 2026-06-04 15:11 ` [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability Nuiqi Gui @ 2026-06-05 9:48 ` Eduard Zingerman 0 siblings, 0 replies; 7+ messages in thread From: Eduard Zingerman @ 2026-06-05 9:48 UTC (permalink / raw) To: Nuiqi Gui, ast, daniel, andrii Cc: dxu, Martin KaFai Lau, Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Ihor Solodrai, bpf, linux-kselftest, linux-kernel On Thu, 2026-06-04 at 23:11 +0800, Nuiqi Gui wrote: > Add a verifier regression test that looks up a constant key through a > dynamic inner array template and dereferences the result without a NULL > check. > > The verifier must reject the program because BPF_F_INNER_MAP allows the > concrete runtime array to have fewer entries than the template. > > Signed-off-by: Nuiqi Gui <gnq25@mails.tsinghua.edu.cn> > --- Acked-by: Eduard Zingerman <eddyz87@gmail.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-05 9:48 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-04 15:11 [PATCH bpf 0/2] Keep dynamic inner array lookups nullable Nuiqi Gui 2026-06-04 15:11 ` [PATCH bpf 1/2] bpf: " Nuiqi Gui 2026-06-04 18:13 ` Magneto 2026-06-04 18:35 ` Suchit Karunakaran 2026-06-05 9:47 ` Eduard Zingerman 2026-06-04 15:11 ` [PATCH bpf 2/2] selftests/bpf: Cover dynamic inner array lookup nullability Nuiqi Gui 2026-06-05 9:48 ` Eduard Zingerman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox