Commit a27e8967 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'fix-hash-bucket-overflow-checks-for-32-bit-arches'

Toke Høiland-Jørgensen says:

====================
Fix hash bucket overflow checks for 32-bit arches

Syzbot managed to trigger a crash by creating a DEVMAP_HASH map with a
large number of buckets because the overflow check relies on
well-defined behaviour that is only correct on 64-bit arches.

Fix the overflow checks to happen before values are rounded up in all
the affected map types.

v3:
- Keep the htab->n_buckets > U32_MAX / sizeof(struct bucket) check
- Use 1UL << 31 instead of U32_MAX / 2 + 1 as the constant to check
  against
- Add patch to fix stackmap.c
v2:
- Fix off-by-one error in overflow check
- Apply the same fix to hashtab, where the devmap_hash code was copied
  from (John)

Toke Høiland-Jørgensen (3):
  bpf: Fix DEVMAP_HASH overflow check on 32-bit arches
  bpf: Fix hashtab overflow check on 32-bit arches
  bpf: Fix stackmap overflow check on 32-bit arches

 kernel/bpf/devmap.c   | 11 ++++++-----
 kernel/bpf/hashtab.c  | 14 +++++++++-----
 kernel/bpf/stackmap.c |  9 ++++++---
 3 files changed, 21 insertions(+), 13 deletions(-)
====================

Link: https://lore.kernel.org/r/20240307120340.99577-1-toke@redhat.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents c7d4274e 7a4b2125
...@@ -130,13 +130,14 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr) ...@@ -130,13 +130,14 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
bpf_map_init_from_attr(&dtab->map, attr); bpf_map_init_from_attr(&dtab->map, attr);
if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) { if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) {
dtab->n_buckets = roundup_pow_of_two(dtab->map.max_entries); /* hash table size must be power of 2; roundup_pow_of_two() can
* overflow into UB on 32-bit arches, so check that first
if (!dtab->n_buckets) /* Overflow check */ */
if (dtab->map.max_entries > 1UL << 31)
return -EINVAL; return -EINVAL;
}
if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) { dtab->n_buckets = roundup_pow_of_two(dtab->map.max_entries);
dtab->dev_index_head = dev_map_create_hash(dtab->n_buckets, dtab->dev_index_head = dev_map_create_hash(dtab->n_buckets,
dtab->map.numa_node); dtab->map.numa_node);
if (!dtab->dev_index_head) if (!dtab->dev_index_head)
......
...@@ -499,7 +499,13 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) ...@@ -499,7 +499,13 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
num_possible_cpus()); num_possible_cpus());
} }
/* hash table size must be power of 2 */ /* hash table size must be power of 2; roundup_pow_of_two() can overflow
* into UB on 32-bit arches, so check that first
*/
err = -E2BIG;
if (htab->map.max_entries > 1UL << 31)
goto free_htab;
htab->n_buckets = roundup_pow_of_two(htab->map.max_entries); htab->n_buckets = roundup_pow_of_two(htab->map.max_entries);
htab->elem_size = sizeof(struct htab_elem) + htab->elem_size = sizeof(struct htab_elem) +
...@@ -509,10 +515,8 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) ...@@ -509,10 +515,8 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
else else
htab->elem_size += round_up(htab->map.value_size, 8); htab->elem_size += round_up(htab->map.value_size, 8);
err = -E2BIG; /* check for u32 overflow */
/* prevent zero size kmalloc and check for u32 overflow */ if (htab->n_buckets > U32_MAX / sizeof(struct bucket))
if (htab->n_buckets == 0 ||
htab->n_buckets > U32_MAX / sizeof(struct bucket))
goto free_htab; goto free_htab;
err = bpf_map_init_elem_count(&htab->map); err = bpf_map_init_elem_count(&htab->map);
......
...@@ -91,11 +91,14 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) ...@@ -91,11 +91,14 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
} else if (value_size / 8 > sysctl_perf_event_max_stack) } else if (value_size / 8 > sysctl_perf_event_max_stack)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/* hash table size must be power of 2 */ /* hash table size must be power of 2; roundup_pow_of_two() can overflow
n_buckets = roundup_pow_of_two(attr->max_entries); * into UB on 32-bit arches, so check that first
if (!n_buckets) */
if (attr->max_entries > 1UL << 31)
return ERR_PTR(-E2BIG); return ERR_PTR(-E2BIG);
n_buckets = roundup_pow_of_two(attr->max_entries);
cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap); cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap);
smap = bpf_map_area_alloc(cost, bpf_map_attr_numa_node(attr)); smap = bpf_map_area_alloc(cost, bpf_map_attr_numa_node(attr));
if (!smap) if (!smap)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment