* [PATCH bpf v3 0/2] bpf: Fix queue/stack map u32 index overflow
@ 2026-08-10 13:59 chenyuan_fl
2026-08-10 13:59 ` [PATCH bpf v3 1/2] " chenyuan_fl
2026-08-10 13:59 ` [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl
0 siblings, 2 replies; 11+ messages in thread
From: chenyuan_fl @ 2026-08-10 13:59 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Yuan Chen
From: Yuan Chen <chenyuan@kylinos.cn>
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. Patch 1
restores the dropped bound check; patch 2 adds a regression test.
Changes in v3:
- Fix the Fixes tag: the bound check was removed by a37fb7ef24a4
(which dropped the bpf_map_charge_init() call), not by
c85d69135a91 (which moved the check into bpf_map_charge_init()),
as pointed out in review. Add Cc: stable@vger.kernel.org since the
bug affects v5.11+.
- Define U32_MAX locally in the selftest, as pointed out in review.
Changes in v2:
- Also reject max_entries == U32_MAX: the u32 capacity counter
qs->size (max_entries + 1) would wrap to 0 and permanently break
the map, as pointed out in review.
- Fix the multi-line comment style in the selftest, as pointed out in
review.
Yuan Chen (2):
bpf: Fix queue/stack map u32 index overflow
selftests/bpf: Add regression test for queue/stack map size limit
kernel/bpf/queue_stack_maps.c | 10 ++++
.../bpf/prog_tests/queue_stack_map.c | 49 +++++++++++++++++++
2 files changed, 59 insertions(+)
--
2.54.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH bpf v3 1/2] bpf: Fix queue/stack map u32 index overflow 2026-08-10 13:59 [PATCH bpf v3 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl @ 2026-08-10 13:59 ` chenyuan_fl 2026-08-10 13:59 ` [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 1 sibling, 0 replies; 11+ messages in thread From: chenyuan_fl @ 2026-08-10 13:59 UTC (permalink / raw) To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Yuan Chen, stable From: Yuan Chen <chenyuan@kylinos.cn> 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 a37fb7ef24a4 ("bpf: Eliminate rlimit-based memory accounting for queue_stack_maps maps"), which deleted the bpf_map_charge_init() call and with it the U32_MAX - PAGE_SIZE check that had earlier been moved into bpf_map_charge_init() by c85d69135a91. Oversized queue/stack maps can therefore 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: a37fb7ef24a4 ("bpf: Eliminate rlimit-based memory accounting for queue_stack_maps maps") Cc: stable@vger.kernel.org Signed-off-by: Yuan Chen <chenyuan@kylinos.cn> --- 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; + return 0; } -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-10 13:59 [PATCH bpf v3 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl 2026-08-10 13:59 ` [PATCH bpf v3 1/2] " chenyuan_fl @ 2026-08-10 13:59 ` chenyuan_fl 2026-08-10 14:49 ` bot+bpf-ci 2026-08-13 22:19 ` Andrii Nakryiko 1 sibling, 2 replies; 11+ messages in thread From: chenyuan_fl @ 2026-08-10 13:59 UTC (permalink / raw) To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Yuan Chen From: Yuan Chen <chenyuan@kylinos.cn> Verify that queue/stack maps whose element storage would overflow the u32 head/tail index multiplication are rejected at creation time, and that max_entries == U32_MAX (which would wrap the u32 capacity counter to 0) is rejected as well. Signed-off-by: Yuan Chen <chenyuan@kylinos.cn> --- .../bpf/prog_tests/queue_stack_map.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c index 41441325e179..043cbe92e2ba 100644 --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c @@ -2,6 +2,8 @@ #include <test_progs.h> #include <network_helpers.h> +#define U32_MAX ((u32)UINT_MAX) + enum { QUEUE, STACK, @@ -101,8 +103,55 @@ static void test_queue_stack_map_by_type(int type) bpf_object__close(obj); } +static void test_queue_stack_map_alloc_check(void) +{ + LIBBPF_OPTS(bpf_map_create_opts, opts); + const __u32 big_value = 1 << 20; /* 1MB */ + int fd, saved_errno; + + /* + * Regression test for the u32 index overflow in queue/stack maps: + * a map whose element storage (max_entries * value_size) exceeds + * U32_MAX bytes must be rejected at creation time, otherwise the + * u32 head/tail index multiplication wraps and push/peek/pop + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. + */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, big_value, 8192, &opts); + saved_errno = errno; + ASSERT_LT(fd, 0, "queue_oversize_fd"); + ASSERT_EQ(saved_errno, E2BIG, "queue_oversize_errno"); + if (fd >= 0) + close(fd); + + /* + * max_entries == U32_MAX would make the u32 capacity counter + * qs->size (max_entries + 1) wrap to 0, permanently breaking the + * map, so it must be rejected as well. + */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 1, U32_MAX, &opts); + saved_errno = errno; + ASSERT_LT(fd, 0, "queue_u32max_fd"); + ASSERT_EQ(saved_errno, E2BIG, "queue_u32max_errno"); + if (fd >= 0) + close(fd); + + fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, big_value, 8192, &opts); + saved_errno = errno; + ASSERT_LT(fd, 0, "stack_oversize_fd"); + ASSERT_EQ(saved_errno, E2BIG, "stack_oversize_errno"); + if (fd >= 0) + close(fd); + + /* A normal-sized map must still be created successfully. */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 64, 100, &opts); + ASSERT_GE(fd, 0, "queue_normal_fd"); + if (fd >= 0) + close(fd); +} + void test_queue_stack_map(void) { test_queue_stack_map_by_type(QUEUE); test_queue_stack_map_by_type(STACK); + test_queue_stack_map_alloc_check(); } -- 2.54.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-10 13:59 ` [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl @ 2026-08-10 14:49 ` bot+bpf-ci 2026-08-13 22:19 ` Andrii Nakryiko 1 sibling, 0 replies; 11+ messages in thread From: bot+bpf-ci @ 2026-08-10 14:49 UTC (permalink / raw) To: chenyuan_fl, bpf Cc: ast, daniel, andrii, chenyuan, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 1698 bytes --] > diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > index 41441325e179..043cbe92e2ba 100644 > --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > @@ -2,6 +2,8 @@ > #include <test_progs.h> > #include <network_helpers.h> > > +#define U32_MAX ((u32)UINT_MAX) > + This isn't a bug, but for the single use in the test, would UINT32_MAX (already available via <stdint.h>) work instead of adding a local U32_MAX macro that relies on UINT_MAX coming in transitively? > +static void test_queue_stack_map_alloc_check(void) > +{ > + LIBBPF_OPTS(bpf_map_create_opts, opts); This isn't a bug, but since no field of opts is ever set in this function, would passing NULL as the opts argument read more directly? [ ... ] > + /* > + * Regression test for the u32 index overflow in queue/stack maps: > + * a map whose element storage (max_entries * value_size) exceeds > + * U32_MAX bytes must be rejected at creation time, otherwise the > + * u32 head/tail index multiplication wraps and push/peek/pop > + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. > + */ This isn't a bug, but could these two comments be condensed to the part specific to the test (why 8192 x 1MB and why E2BIG), leaving the description of the head/tail wrap to the comment the kernel patch adds in queue_stack_maps.c? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31396327144 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-10 13:59 ` [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 2026-08-10 14:49 ` bot+bpf-ci @ 2026-08-13 22:19 ` Andrii Nakryiko 2026-08-24 8:33 ` [PATCH bpf v4 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl 1 sibling, 1 reply; 11+ messages in thread From: Andrii Nakryiko @ 2026-08-13 22:19 UTC (permalink / raw) To: chenyuan_fl Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Yuan Chen On Mon, Aug 10, 2026 at 7:00 AM <chenyuan_fl@163.com> wrote: > > From: Yuan Chen <chenyuan@kylinos.cn> > > Verify that queue/stack maps whose element storage would overflow the > u32 head/tail index multiplication are rejected at creation time, and > that max_entries == U32_MAX (which would wrap the u32 capacity counter > to 0) is rejected as well. > > Signed-off-by: Yuan Chen <chenyuan@kylinos.cn> > --- > .../bpf/prog_tests/queue_stack_map.c | 49 +++++++++++++++++++ > 1 file changed, 49 insertions(+) > > diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > index 41441325e179..043cbe92e2ba 100644 > --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > @@ -2,6 +2,8 @@ > #include <test_progs.h> > #include <network_helpers.h> > > +#define U32_MAX ((u32)UINT_MAX) > + > enum { > QUEUE, > STACK, > @@ -101,8 +103,55 @@ static void test_queue_stack_map_by_type(int type) > bpf_object__close(obj); > } > > +static void test_queue_stack_map_alloc_check(void) > +{ > + LIBBPF_OPTS(bpf_map_create_opts, opts); > + const __u32 big_value = 1 << 20; /* 1MB */ > + int fd, saved_errno; > + > + /* > + * Regression test for the u32 index overflow in queue/stack maps: > + * a map whose element storage (max_entries * value_size) exceeds > + * U32_MAX bytes must be rejected at creation time, otherwise the > + * u32 head/tail index multiplication wraps and push/peek/pop > + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, big_value, 8192, &opts); > + saved_errno = errno; > + ASSERT_LT(fd, 0, "queue_oversize_fd"); > + ASSERT_EQ(saved_errno, E2BIG, "queue_oversize_errno"); > + if (fd >= 0) > + close(fd); > + > + /* > + * max_entries == U32_MAX would make the u32 capacity counter > + * qs->size (max_entries + 1) wrap to 0, permanently breaking the > + * map, so it must be rejected as well. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 1, U32_MAX, &opts); > + saved_errno = errno; > + ASSERT_LT(fd, 0, "queue_u32max_fd"); > + ASSERT_EQ(saved_errno, E2BIG, "queue_u32max_errno"); Just ASSERT_EQ(fd, -E2BIG)? libbpf returns an error value directly. > + if (fd >= 0) > + close(fd); > + > + fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, big_value, 8192, &opts); > + saved_errno = errno; > + ASSERT_LT(fd, 0, "stack_oversize_fd"); > + ASSERT_EQ(saved_errno, E2BIG, "stack_oversize_errno"); > + if (fd >= 0) > + close(fd); > + > + /* A normal-sized map must still be created successfully. */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 64, 100, &opts); > + ASSERT_GE(fd, 0, "queue_normal_fd"); > + if (fd >= 0) > + close(fd); > +} > + > void test_queue_stack_map(void) > { > test_queue_stack_map_by_type(QUEUE); > test_queue_stack_map_by_type(STACK); > + test_queue_stack_map_alloc_check(); > } > -- > 2.54.0 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf v4 0/2] bpf: Fix queue/stack map u32 index overflow 2026-08-13 22:19 ` Andrii Nakryiko @ 2026-08-24 8:33 ` chenyuan_fl 2026-08-24 8:33 ` [PATCH bpf v4 1/2] " chenyuan_fl 2026-08-24 8:33 ` [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 0 siblings, 2 replies; 11+ messages in thread From: chenyuan_fl @ 2026-08-24 8:33 UTC (permalink / raw) To: bpf; +Cc: ast, daniel, andrii, andrii.nakryiko, Yuan Chen From: Yuan Chen <chenyuan@kylinos.cn> This series fixes an integer overflow in BPF queue/stack maps. The u32 head/tail index is multiplied by value_size to address elements[], but the storage itself is allocated with 64-bit arithmetic. When max_entries * value_size reaches or exceeds U32_MAX, the index multiplication wraps and push/peek/pop operate on the wrong element, corrupting map data and leaking stale values to user space. max_entries == U32_MAX would also wrap the u32 capacity counter qs->size (max_entries + 1) to 0 and permanently break the map. Patch 1 restores the size bound in queue_stack_map_alloc_check() that was lost when the check inside bpf_map_charge_init() was removed. A single division-based comparison covers both the index multiplication overflow and the capacity counter wrap. Patch 2 adds a regression test for both rejection cases. Many thanks to Andrii Nakryiko for the careful review and the helpful suggestions: the bound has been simplified to a single `max_entries >= U32_MAX / value_size` check, and the selftest now asserts the bpf_map_create() return value directly instead of reading errno. v2 -> v3: - also reject max_entries == U32_MAX, which would wrap the u32 capacity counter qs->size (max_entries + 1) to 0 - fix the Fixes tag: the guard was actually dropped by a37fb7ef24a4, which removed the bpf_map_charge_init() call the check had been moved into by c85d69135a91 v3 -> v4: - simplify the bound to a single `max_entries >= U32_MAX / value_size` comparison, which also rejects max_entries == U32_MAX - check the bpf_map_create() return value directly instead of errno in the selftest Yuan Chen (2): bpf: Fix queue/stack map u32 index overflow selftests/bpf: Add regression test for queue/stack map size limit kernel/bpf/queue_stack_maps.c | 9 ++++++ .../selftests/bpf/prog_tests/queue_stack_map.c | 37 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf v4 1/2] bpf: Fix queue/stack map u32 index overflow 2026-08-24 8:33 ` [PATCH bpf v4 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl @ 2026-08-24 8:33 ` chenyuan_fl 2026-08-24 8:47 ` sashiko-bot 2026-08-24 8:33 ` [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 1 sibling, 1 reply; 11+ messages in thread From: chenyuan_fl @ 2026-08-24 8:33 UTC (permalink / raw) To: bpf; +Cc: ast, daniel, andrii, andrii.nakryiko, Yuan Chen, stable From: Yuan Chen <chenyuan@kylinos.cn> 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 reaches or 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. max_entries == U32_MAX would also make the u32 capacity counter qs->size (max_entries + 1) wrap to 0 and permanently break the map. The original bound check was removed by commit a37fb7ef24a4 ("bpf: Eliminate rlimit-based memory accounting for queue_stack_maps maps"), which deleted the bpf_map_charge_init() call and with it the U32_MAX - PAGE_SIZE check that had earlier been moved into bpf_map_charge_init() by c85d69135a91. Oversized queue/stack maps can therefore be created again. Restore the bound in queue_stack_map_alloc_check() with a single comparison that rejects any max_entries/value_size combination whose element storage would reach or exceed U32_MAX bytes, keeping the u32 index multiplication overflow-free and the capacity counter valid. Fixes: a37fb7ef24a4 ("bpf: Eliminate rlimit-based memory accounting for queue_stack_maps maps") Cc: stable@vger.kernel.org Signed-off-by: Yuan Chen <chenyuan@kylinos.cn> --- v4: simplify the bound to a single division-based comparison as suggested by Andrii Nakryiko; this also rejects max_entries == U32_MAX kernel/bpf/queue_stack_maps.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c index c1c9dee4dcdd..0d9e0b807a50 100644 --- a/kernel/bpf/queue_stack_maps.c +++ b/kernel/bpf/queue_stack_maps.c @@ -59,6 +59,15 @@ 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 max_entries so neither the product nor the capacity + * counter can wrap (this also rejects max_entries == U32_MAX). + */ + if (attr->max_entries >= U32_MAX / attr->value_size) + return -E2BIG; + return 0; } -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH bpf v4 1/2] bpf: Fix queue/stack map u32 index overflow 2026-08-24 8:33 ` [PATCH bpf v4 1/2] " chenyuan_fl @ 2026-08-24 8:47 ` sashiko-bot 0 siblings, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-08-24 8:47 UTC (permalink / raw) To: chenyuan_fl; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] Kfuncs using enum parameters as array indices lack bounds checking for negative values. -- --- Patch [1]: [PATCH bpf v4 1/2] bpf: Fix queue/stack map u32 index overflow --- commit b3cc6df8f8f6a83f377bada50a4de0c2ebde4779 Author: Yuan Chen <chenyuan@kylinos.cn> bpf: Fix queue/stack map u32 index overflow This commit fixes an integer overflow in queue/stack maps by restoring a bounds check in queue_stack_map_alloc_check(). It rejects max_entries and value_size combinations that would reach or exceed U32_MAX bytes. [ ... ] While reviewing BPF bounds checking, I noticed a pre-existing issue in mm/bpf_memcontrol.c: > mm/bpf_memcontrol.c > > __bpf_kfunc unsigned long bpf_mem_cgroup_vm_events(struct mem_cgroup *memcg, > enum vm_event_item event) > { > if (unlikely(!memcg_vm_event_item_valid(event))) > return (unsigned long)-1; [Severity: High] This is a pre-existing issue, but since enums are represented as signed integers in C, could a BPF program bypass this bounds check by passing a negative enum value? It appears that a negative event value could evade the upper bounds check and lead to an out-of-bounds read when the event is used as an array index. > > return memcg_events(memcg, event); > } > > ... > > __bpf_kfunc unsigned long bpf_mem_cgroup_memory_events(struct mem_cgroup *memcg, > enum memcg_memory_event event) > { > if (unlikely(event >= MEMCG_NR_MEMORY_EVENTS)) > return (unsigned long)-1; [Severity: High] This isn't a bug introduced by this patch, but does this signed comparison handle negative event values? Similar to the above, a negative event value would pass this check and subsequently be used as a negative index for the memory_events array. Does this result in an out-of-bounds memory read? > > return atomic_long_read(&memcg->memory_events[event]); > } -- Sashiko AI review · https://sashiko.dev/#/patchset/20260824083327.1708560-1-chenyuan_fl@163.com?part=1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-24 8:33 ` [PATCH bpf v4 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl 2026-08-24 8:33 ` [PATCH bpf v4 1/2] " chenyuan_fl @ 2026-08-24 8:33 ` chenyuan_fl 2026-08-24 8:43 ` sashiko-bot 2026-08-24 9:25 ` bot+bpf-ci 1 sibling, 2 replies; 11+ messages in thread From: chenyuan_fl @ 2026-08-24 8:33 UTC (permalink / raw) To: bpf; +Cc: ast, daniel, andrii, andrii.nakryiko, Yuan Chen From: Yuan Chen <chenyuan@kylinos.cn> Verify that queue/stack maps whose element storage would overflow the u32 head/tail index multiplication are rejected at creation time, and that max_entries == U32_MAX (which would wrap the u32 capacity counter to 0) is rejected as well. Signed-off-by: Yuan Chen <chenyuan@kylinos.cn> --- v4: check the bpf_map_create() return value directly instead of errno as suggested by Andrii Nakryiko .../selftests/bpf/prog_tests/queue_stack_map.c | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c index 41441325e179..efe808eedd9a 100644 --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c @@ -2,6 +2,8 @@ #include <test_progs.h> #include <network_helpers.h> +#define U32_MAX ((u32)UINT_MAX) + enum { QUEUE, STACK, @@ -101,8 +103,43 @@ static void test_queue_stack_map_by_type(int type) bpf_object__close(obj); } +static void test_queue_stack_map_alloc_check(void) +{ + LIBBPF_OPTS(bpf_map_create_opts, opts); + const __u32 big_value = 1 << 20; /* 1MB */ + int fd; + + /* + * Regression test for the u32 index overflow in queue/stack maps: + * a map whose element storage (max_entries * value_size) exceeds + * U32_MAX bytes must be rejected at creation time, otherwise the + * u32 head/tail index multiplication wraps and push/peek/pop + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. + */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, big_value, 8192, &opts); + ASSERT_EQ(fd, -E2BIG, "queue_oversize"); + + /* + * max_entries == U32_MAX would make the u32 capacity counter + * qs->size (max_entries + 1) wrap to 0, permanently breaking the + * map, so it must be rejected as well. + */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 1, U32_MAX, &opts); + ASSERT_EQ(fd, -E2BIG, "queue_u32max"); + + fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, big_value, 8192, &opts); + ASSERT_EQ(fd, -E2BIG, "stack_oversize"); + + /* A normal-sized map must still be created successfully. */ + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 64, 100, &opts); + ASSERT_GE(fd, 0, "queue_normal"); + if (fd >= 0) + close(fd); +} + void test_queue_stack_map(void) { test_queue_stack_map_by_type(QUEUE); test_queue_stack_map_by_type(STACK); + test_queue_stack_map_alloc_check(); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-24 8:33 ` [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl @ 2026-08-24 8:43 ` sashiko-bot 2026-08-24 9:25 ` bot+bpf-ci 1 sibling, 0 replies; 11+ messages in thread From: sashiko-bot @ 2026-08-24 8:43 UTC (permalink / raw) To: chenyuan_fl; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Massive memory leak and file descriptor leak in the test runner on unpatched kernels. -- --- Patch [2]: [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit --- commit b01042556c787abab943d9e6059710f436274dbe Author: Yuan Chen <chenyuan@kylinos.cn> selftests/bpf: Add regression test for queue/stack map size limit This commit adds a regression test to verify that queue/stack maps whose element storage overflows the u32 head/tail index multiplication are rejected at creation time. It also checks that max_entries == U32_MAX is rejected. > diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > index 41441325e1794..efe808eedd9a8 100644 > --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c [ ... ] > @@ -101,8 +103,43 @@ static void test_queue_stack_map_by_type(int type) > bpf_object__close(obj); > } > > +static void test_queue_stack_map_alloc_check(void) > +{ > + LIBBPF_OPTS(bpf_map_create_opts, opts); > + const __u32 big_value = 1 << 20; /* 1MB */ > + int fd; > + > + /* > + * Regression test for the u32 index overflow in queue/stack maps: > + * a map whose element storage (max_entries * value_size) exceeds > + * U32_MAX bytes must be rejected at creation time, otherwise the > + * u32 head/tail index multiplication wraps and push/peek/pop > + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, big_value, 8192, &opts); > + ASSERT_EQ(fd, -E2BIG, "queue_oversize"); > + > + /* > + * max_entries == U32_MAX would make the u32 capacity counter > + * qs->size (max_entries + 1) wrap to 0, permanently breaking the > + * map, so it must be rejected as well. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 1, U32_MAX, &opts); [Severity: Medium] If this test runs on an unpatched kernel, the previous bpf_map_create() call might unexpectedly succeed and return a valid file descriptor. Because ASSERT_EQ() doesn't abort the test upon failure, won't this next bpf_map_create() call overwrite the 'fd' variable without closing the previous one? This could leak the map file descriptor and the large amount of memory (up to 8GB) allocated by the map, potentially triggering the OOM killer and crashing the test environment. Should we check if 'fd >= 0' and close it after the ASSERT_EQ() for each of these expected-to-fail allocations? > + ASSERT_EQ(fd, -E2BIG, "queue_u32max"); > + > + fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, big_value, 8192, &opts); > + ASSERT_EQ(fd, -E2BIG, "stack_oversize"); > + > + /* A normal-sized map must still be created successfully. */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 64, 100, &opts); > + ASSERT_GE(fd, 0, "queue_normal"); > + if (fd >= 0) > + close(fd); > +} -- Sashiko AI review · https://sashiko.dev/#/patchset/20260824083327.1708560-1-chenyuan_fl@163.com?part=2 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit 2026-08-24 8:33 ` [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 2026-08-24 8:43 ` sashiko-bot @ 2026-08-24 9:25 ` bot+bpf-ci 1 sibling, 0 replies; 11+ messages in thread From: bot+bpf-ci @ 2026-08-24 9:25 UTC (permalink / raw) To: chenyuan_fl, bpf Cc: ast, daniel, andrii, andrii.nakryiko, chenyuan, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 2611 bytes --] > diff --git a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > index 41441325e179..efe808eedd9a 100644 > --- a/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c > +++ b/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c [ ... ] > +static void test_queue_stack_map_alloc_check(void) > +{ > + LIBBPF_OPTS(bpf_map_create_opts, opts); > + const __u32 big_value = 1 << 20; /* 1MB */ > + int fd; > + > + /* > + * Regression test for the u32 index overflow in queue/stack maps: > + * a map whose element storage (max_entries * value_size) exceeds > + * U32_MAX bytes must be rejected at creation time, otherwise the > + * u32 head/tail index multiplication wraps and push/peek/pop > + * address the wrong element. 8192 * 1MB = 8GB > U32_MAX. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, big_value, 8192, &opts); > + ASSERT_EQ(fd, -E2BIG, "queue_oversize"); > + > + /* > + * max_entries == U32_MAX would make the u32 capacity counter > + * qs->size (max_entries + 1) wrap to 0, permanently breaking the > + * map, so it must be rejected as well. > + */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 1, U32_MAX, &opts); > + ASSERT_EQ(fd, -E2BIG, "queue_u32max"); > + > + fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, big_value, 8192, &opts); > + ASSERT_EQ(fd, -E2BIG, "stack_oversize"); Should these three negative test cases close the fd if the map creation unexpectedly succeeds? On a kernel without the fix in patch 1/2, queue_stack_map_alloc_check returns 0 for these attributes. The allocation then attempts an 8.59 GB or 4 GB bpf_map_area_alloc in queue_stack_map_alloc. On a host with enough memory, __vmalloc_node_range can succeed, returning fd >= 0 instead of -E2BIG. When that happens, the assertion fails correctly, but the fd remains open for the rest of test_progs, pinning roughly 20 GB of kernel memory across all remaining tests. The positive test case below shows the pattern: > + /* A normal-sized map must still be created successfully. */ > + fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, 64, 100, &opts); > + ASSERT_GE(fd, 0, "queue_normal"); > + if (fd >= 0) > + close(fd); > +} Adding the same guard after each of the three ASSERT_EQ calls would bound the damage to the failing subtest rather than OOMing the rest of the run. --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32709296749 ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-24 9:25 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-10 13:59 [PATCH bpf v3 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl 2026-08-10 13:59 ` [PATCH bpf v3 1/2] " chenyuan_fl 2026-08-10 13:59 ` [PATCH bpf v3 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 2026-08-10 14:49 ` bot+bpf-ci 2026-08-13 22:19 ` Andrii Nakryiko 2026-08-24 8:33 ` [PATCH bpf v4 0/2] bpf: Fix queue/stack map u32 index overflow chenyuan_fl 2026-08-24 8:33 ` [PATCH bpf v4 1/2] " chenyuan_fl 2026-08-24 8:47 ` sashiko-bot 2026-08-24 8:33 ` [PATCH bpf v4 2/2] selftests/bpf: Add regression test for queue/stack map size limit chenyuan_fl 2026-08-24 8:43 ` sashiko-bot 2026-08-24 9:25 ` bot+bpf-ci
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox