Re: [PATCH] bpf: Fix integer overflow in argument calculation for bpf_map_area_alloc
From: Bui Quang Minh <hidden>
Date: 2021-05-17 16:27:59
Also in:
bpf, lkml
On 1/28/21 7:41 AM, Daniel Borkmann wrote:
On 1/27/21 5:23 AM, Bui Quang Minh wrote:quoted
On Tue, Jan 26, 2021 at 09:36:57AM +0000, Lorenz Bauer wrote:quoted
On Tue, 26 Jan 2021 at 08:26, Bui Quang Minh [off-list ref] wrote:quoted
In 32-bit architecture, the result of sizeof() is a 32-bit integer so the expression becomes the multiplication between 2 32-bit integer which can potentially leads to integer overflow. As a result, bpf_map_area_alloc() allocates less memory than needed. Fix this by casting 1 operand to u64.Some quick thoughts: * Should this have a Fixes tag?Ok, I will add Fixes tag in later version patch.quoted
* Seems like there are quite a few similar calls scattered around (cpumap, etc.). Did you audit these as well?[...]quoted
In cpumap, static struct bpf_map *cpu_map_alloc(union bpf_attr *attr) { cmap->cpu_map = bpf_map_area_alloc(cmap->map.max_entries * sizeof(struct bpf_cpu_map_entry *), cmap->map.numa_node); } I think this is safe because max_entries is not permitted to be larger than NR_CPUS.Yes.quoted
In stackmap, there is a place that I'm not very sure about static int prealloc_elems_and_freelist(struct bpf_stack_map *smap) { u32 elem_size = sizeof(struct stack_map_bucket) + smap->map.value_size; smap->elems = bpf_map_area_alloc(elem_size * smap->map.max_entries, smap->map.numa_node); } This is called after another bpf_map_area_alloc in stack_map_alloc(). In the first bpf_map_area_alloc() the argument is calculated in an u64 variable; so if in the second one, there is an integer overflow then the first one must be called with size > 4GB. I think the first one will probably fail (I am not sure about the actual limit of vmalloc()), so the second one might not be called.I would sanity check this as well. Looks like k*alloc()/v*alloc() call sites typically use array_size() which returns SIZE_MAX on overflow, 610b15c50e86 ("overflow.h: Add allocation size calculation helpers").
Hi, I almost forget about this patch, I have checked the bpf_map_area_alloc in in stackmap.c and I can see that integer overflow cannot happen in this stackmap.c case. In stack_map_alloc(), u64 cost; ... cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap); cost += n_buckets * (value_size + sizeof(struct stack_map_bucket)); smap = bpf_map_area_alloc(cost, bpf_map_attr_numa_node(attr)); (1) ... prealloc_elems_and_freelist(smap); In prealloc_elems_and_freelist(), u32 elem_size = sizeof(struct stack_map_bucket) + smap->map.value_size; smap->elems = bpf_map_area_alloc(elem_size * smap->map.max_entries, smap->map.numa_node); (2) Argument calculation at (1) is safe. Argument calculation at (2) can potentially result in an integer overflow in 32-bit architecture. However, if the integer overflow happens, it means argument at (1) must be 2**32, which cannot pass the SIZE_MAX check in __bpf_map_area_alloc() In __bpf_map_area_alloc() if (size >= SIZE_MAX) return NULL; So I think the original patch has fixed instances of this bug pattern. Thank you, Quang Minh.