aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-08-22 18:06:09 -0400
committerDavid S. Miller <davem@davemloft.net>2017-08-22 19:31:00 -0400
commitcd36c3a21a400cac9c457394b9adf94e0027c136 (patch)
tree06372773dccdb4e2673a06610f901d3af523e1d8
parent4a00aa057759d713e1296ecbc614fa560d569977 (diff)
bpf: fix map value attribute for hash of maps
Currently, iproute2's BPF ELF loader works fine with array of maps when retrieving the fd from a pinned node and doing a selfcheck against the provided map attributes from the object file, but we fail to do the same for hash of maps and thus refuse to get the map from pinned node. Reason is that when allocating hash of maps, fd_htab_map_alloc() will set the value size to sizeof(void *), and any user space map creation requests are forced to set 4 bytes as value size. Thus, selfcheck will complain about exposed 8 bytes on 64 bit archs vs. 4 bytes from object file as value size. Contract is that fdinfo or BPF_MAP_GET_FD_BY_ID returns the value size used to create the map. Fix it by handling it the same way as we do for array of maps, which means that we leave value size at 4 bytes and in the allocation phase round up value size to 8 bytes. alloc_htab_elem() needs an adjustment in order to copy rounded up 8 bytes due to bpf_fd_htab_map_update_elem() calling into htab_map_update_elem() with the pointer of the map pointer as value. Unlike array of maps where we just xchg(), we're using the generic htab_map_update_elem() callback also used from helper calls, which published the key/value already on return, so we need to ensure to memcpy() the right size. Fixes: bcc6b1b7ebf8 ("bpf: Add hash of maps support") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--kernel/bpf/hashtab.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index ae822de4a90a..d246905f2bb1 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -662,12 +662,27 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr,
662 } 662 }
663} 663}
664 664
665static bool fd_htab_map_needs_adjust(const struct bpf_htab *htab)
666{
667 return htab->map.map_type == BPF_MAP_TYPE_HASH_OF_MAPS &&
668 BITS_PER_LONG == 64;
669}
670
671static u32 htab_size_value(const struct bpf_htab *htab, bool percpu)
672{
673 u32 size = htab->map.value_size;
674
675 if (percpu || fd_htab_map_needs_adjust(htab))
676 size = round_up(size, 8);
677 return size;
678}
679
665static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key, 680static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
666 void *value, u32 key_size, u32 hash, 681 void *value, u32 key_size, u32 hash,
667 bool percpu, bool onallcpus, 682 bool percpu, bool onallcpus,
668 struct htab_elem *old_elem) 683 struct htab_elem *old_elem)
669{ 684{
670 u32 size = htab->map.value_size; 685 u32 size = htab_size_value(htab, percpu);
671 bool prealloc = htab_is_prealloc(htab); 686 bool prealloc = htab_is_prealloc(htab);
672 struct htab_elem *l_new, **pl_new; 687 struct htab_elem *l_new, **pl_new;
673 void __percpu *pptr; 688 void __percpu *pptr;
@@ -707,9 +722,6 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
707 722
708 memcpy(l_new->key, key, key_size); 723 memcpy(l_new->key, key, key_size);
709 if (percpu) { 724 if (percpu) {
710 /* round up value_size to 8 bytes */
711 size = round_up(size, 8);
712
713 if (prealloc) { 725 if (prealloc) {
714 pptr = htab_elem_get_ptr(l_new, key_size); 726 pptr = htab_elem_get_ptr(l_new, key_size);
715 } else { 727 } else {
@@ -1220,17 +1232,9 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = {
1220 1232
1221static struct bpf_map *fd_htab_map_alloc(union bpf_attr *attr) 1233static struct bpf_map *fd_htab_map_alloc(union bpf_attr *attr)
1222{ 1234{
1223 struct bpf_map *map;
1224
1225 if (attr->value_size != sizeof(u32)) 1235 if (attr->value_size != sizeof(u32))
1226 return ERR_PTR(-EINVAL); 1236 return ERR_PTR(-EINVAL);
1227 1237 return htab_map_alloc(attr);
1228 /* pointer is stored internally */
1229 attr->value_size = sizeof(void *);
1230 map = htab_map_alloc(attr);
1231 attr->value_size = sizeof(u32);
1232
1233 return map;
1234} 1238}
1235 1239
1236static void fd_htab_map_free(struct bpf_map *map) 1240static void fd_htab_map_free(struct bpf_map *map)