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: [email protected]
Signed-off-by: Nuoqi Gui <[email protected]>
Acked-by: Eduard Zingerman <[email protected]>
---
 kernel/bpf/verifier.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7fb88e1cd7c4d..ff9b1f68ceca4 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;
@@ -10221,13 +10221,16 @@ static void update_loop_inline_state(struct 
bpf_verifier_env *env, u32 subprogno
                                 state->callback_subprogno == subprogno);
 }
 
-/* Returns whether or not the given map type can potentially elide
+/* Returns whether or not the given map can potentially elide
  * 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


Reply via email to