Commit fe58e3dd6e119c6d41fd535429b0f1e83b5433d2
Committed by
Greg Kroah-Hartman
1 parent
43c390b751
bpf: Fix map leak in HASH_OF_MAPS map
[ 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>
Showing 1 changed file with 9 additions and 3 deletions Side-by-side Diff
kernel/bpf/hashtab.c
... | ... | @@ -675,16 +675,21 @@ |
675 | 675 | preempt_enable(); |
676 | 676 | } |
677 | 677 | |
678 | -static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l) | |
678 | +static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l) | |
679 | 679 | { |
680 | 680 | struct bpf_map *map = &htab->map; |
681 | + void *ptr; | |
681 | 682 | |
682 | 683 | if (map->ops->map_fd_put_ptr) { |
683 | - void *ptr = fd_htab_map_get_ptr(map, l); | |
684 | - | |
684 | + ptr = fd_htab_map_get_ptr(map, l); | |
685 | 685 | map->ops->map_fd_put_ptr(ptr); |
686 | 686 | } |
687 | +} | |
687 | 688 | |
689 | +static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l) | |
690 | +{ | |
691 | + htab_put_fd_value(htab, l); | |
692 | + | |
688 | 693 | if (htab_is_prealloc(htab)) { |
689 | 694 | __pcpu_freelist_push(&htab->freelist, &l->fnode); |
690 | 695 | } else { |
... | ... | @@ -735,6 +740,7 @@ |
735 | 740 | */ |
736 | 741 | pl_new = this_cpu_ptr(htab->extra_elems); |
737 | 742 | l_new = *pl_new; |
743 | + htab_put_fd_value(htab, old_elem); | |
738 | 744 | *pl_new = old_elem; |
739 | 745 | } else { |
740 | 746 | struct pcpu_freelist_node *l; |