Re: [PATCH bpf v2 1/2] bpf: Fix queue/stack map u32 index overflow
Andrii Nakryiko <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <CAEf4BzZj3-qWtBaSQ5PKKji531Qe_EWEsFU4=VsHzHaa775E7g@mail.gmail.com> |
On Mon, Aug 10, 2026 at 2:28 AM <[email protected]> wrote: > > From: Yuan Chen <[email protected]> > > The queue/stack map addresses elements[] with the product of a u32 > head/tail index and value_size, but the storage itself is allocated in > 64-bit arithmetic. When max_entries * value_size exceeds U32_MAX, the > product wraps and push/peek/pop operate on the wrong element, corrupting > map data and leaking stale values to user space. > > The original bound check was removed by commit c85d69135a91 ("bpf: move > memory size checks to bpf_map_charge_init()"), which migrated only the > bytes-to-pages conversion and dropped the overflow guard, so oversized > queue/stack maps can be created again. > > Restore the bound in queue_stack_map_alloc_check(): reject maps whose > element storage would exceed U32_MAX bytes, keeping the u32 index > multiplication overflow-free. Also reject max_entries == U32_MAX, which > would make the u32 capacity counter qs->size (max_entries + 1) wrap to > 0 and permanently break the map. > > Fixes: c85d69135a91 ("bpf: move memory size checks to bpf_map_charge_init()") > Signed-off-by: Yuan Chen <[email protected]> > --- > kernel/bpf/queue_stack_maps.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c > index c1c9dee4dcdd..bb2453693b80 100644 > --- a/kernel/bpf/queue_stack_maps.c > +++ b/kernel/bpf/queue_stack_maps.c > @@ -59,6 +59,16 @@ static int queue_stack_map_alloc_check(union bpf_attr *attr) > */ > return -E2BIG; > > + /* > + * The u32 head/tail index is multiplied by value_size to address > + * elements[], and qs->size (max_entries + 1) is stored in a u32. > + * Bound the map size so neither the product nor the capacity > + * counter can overflow. > + */ > + if ((u64)attr->max_entries * attr->value_size > U32_MAX || > + attr->max_entries == U32_MAX) > + return -E2BIG; maybe just if (attr->max_entries >= U32_MAX / attr->value_size) return -E2BIG; This will reject any combination of max_entries and value_size (which we already checked for zero, so we are fine with division here) that would get us at U32_MAX size or larger. That automatically eliminates max_entries == U32_MAX as well. pw-bot: cr > + > return 0; > } > > -- > 2.54.0 >