From: Yuan Chen 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 --- 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 #include +#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