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