bpf: Fix map leak in HASH_OF_MAPS map
authorAndrii Nakryiko <andriin@fb.com>
Wed, 29 Jul 2020 04:09:12 +0000 (21:09 -0700)
committerCosmin Tanislav <demonsingur@gmail.com>
Thu, 16 May 2024 07:58:23 +0000 (10:58 +0300)
[ Upstream commit 1d4e1eab456e1ee92a94987499b211db05f900ea ]

Fix HASH_OF_MAPS bug of not putting inner map pointer on bpf_map_elem_update()
operation. This is due to per-cpu extra_elems optimization, which bypassed
free_htab_elem() logic doing proper clean ups. Make sure that inner map is put
properly in optimized case as well.

Fixes: 8c290e60fa2a ("bpf: fix hashmap extra_elems logic")
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20200729040913.2815687-1-andriin@fb.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
kernel/bpf/hashtab.c

index cb1b144a191c1474e91325a6b5ff559377611a94..adb302d04ab366798c7a182904b5eb28aba0a503 100644 (file)
@@ -657,15 +657,20 @@ static void htab_elem_free_rcu(struct rcu_head *head)
        preempt_enable();
 }
 
-static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)
+static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l)
 {
        struct bpf_map *map = &htab->map;
+       void *ptr;
 
        if (map->ops->map_fd_put_ptr) {
-               void *ptr = fd_htab_map_get_ptr(map, l);
-
+               ptr = fd_htab_map_get_ptr(map, l);
                map->ops->map_fd_put_ptr(ptr);
        }
+}
+
+static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)
+{
+       htab_put_fd_value(htab, l);
 
        if (htab_is_prealloc(htab)) {
                __pcpu_freelist_push(&htab->freelist, &l->fnode);
@@ -726,6 +731,7 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
                         */
                        pl_new = this_cpu_ptr(htab->extra_elems);
                        l_new = *pl_new;
+                       htab_put_fd_value(htab, old_elem);
                        *pl_new = old_elem;
                } else {
                        struct pcpu_freelist_node *l;