Skip to content

Commit 33ba43e

Browse files
borkmanndavem330
authored andcommitted
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: bcc6b1b ("bpf: Add hash of maps support") Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fcd03e3 commit 33ba43e

File tree

1 file changed

+17
-13
lines changed

1 file changed

+17
-13
lines changed

kernel/bpf/hashtab.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -652,12 +652,27 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr,
652652
}
653653
}
654654

655+
static bool fd_htab_map_needs_adjust(const struct bpf_htab *htab)
656+
{
657+
return htab->map.map_type == BPF_MAP_TYPE_HASH_OF_MAPS &&
658+
BITS_PER_LONG == 64;
659+
}
660+
661+
static u32 htab_size_value(const struct bpf_htab *htab, bool percpu)
662+
{
663+
u32 size = htab->map.value_size;
664+
665+
if (percpu || fd_htab_map_needs_adjust(htab))
666+
size = round_up(size, 8);
667+
return size;
668+
}
669+
655670
static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
656671
void *value, u32 key_size, u32 hash,
657672
bool percpu, bool onallcpus,
658673
struct htab_elem *old_elem)
659674
{
660-
u32 size = htab->map.value_size;
675+
u32 size = htab_size_value(htab, percpu);
661676
bool prealloc = htab_is_prealloc(htab);
662677
struct htab_elem *l_new, **pl_new;
663678
void __percpu *pptr;
@@ -696,9 +711,6 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
696711

697712
memcpy(l_new->key, key, key_size);
698713
if (percpu) {
699-
/* round up value_size to 8 bytes */
700-
size = round_up(size, 8);
701-
702714
if (prealloc) {
703715
pptr = htab_elem_get_ptr(l_new, key_size);
704716
} else {
@@ -1209,17 +1221,9 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = {
12091221

12101222
static struct bpf_map *fd_htab_map_alloc(union bpf_attr *attr)
12111223
{
1212-
struct bpf_map *map;
1213-
12141224
if (attr->value_size != sizeof(u32))
12151225
return ERR_PTR(-EINVAL);
1216-
1217-
/* pointer is stored internally */
1218-
attr->value_size = sizeof(void *);
1219-
map = htab_map_alloc(attr);
1220-
attr->value_size = sizeof(u32);
1221-
1222-
return map;
1226+
return htab_map_alloc(attr);
12231227
}
12241228

12251229
static void fd_htab_map_free(struct bpf_map *map)

0 commit comments

Comments
 (0)