Skip to content

Commit 5939801

Browse files
keenanwgnAlexei Starovoitov
authored andcommitted
bpf: Use array_map_meta_equal for percpu array inner map replacement
percpu_array_map_ops.map_meta_equal points to the generic bpf_map_meta_equal(), which does not compare max_entries. When a percpu array serves as an inner map, replacing it with one that has fewer max_entries bypasses the check. Since percpu_array_map_gen_lookup() inlines the original template's index_mask as a JIT immediate, a lookup on the replacement map can access pptrs[] out of bounds. Point percpu_array_map_ops.map_meta_equal to array_map_meta_equal(), which already enforces the max_entries equality check. Add a selftest to verify that replacing a percpu array inner map with a differently-sized one is rejected. Fixes: db69718 ("bpf: inline bpf_map_lookup_elem() for PERCPU_ARRAY maps") Signed-off-by: Guannan Wang <wgnbuaa@gmail.com> Acked-by: Mykyta Yatsenko <yatsenko@meta.com> Link: https://lore.kernel.org/r/20260514074454.77491-1-wgnbuaa@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent d25e65a commit 5939801

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

kernel/bpf/arraymap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,7 @@ const struct bpf_map_ops array_map_ops = {
827827
};
828828

829829
const struct bpf_map_ops percpu_array_map_ops = {
830-
.map_meta_equal = bpf_map_meta_equal,
830+
.map_meta_equal = array_map_meta_equal,
831831
.map_alloc_check = array_map_alloc_check,
832832
.map_alloc = array_map_alloc,
833833
.map_free = array_map_free,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
4+
/*
5+
* Test that replacing an inner percpu array map with one that has different
6+
* max_entries is rejected. percpu_array_map_gen_lookup() inlines the
7+
* template's index_mask, so allowing a smaller replacement would cause OOB.
8+
*/
9+
void test_percpu_array_inner_map(void)
10+
{
11+
LIBBPF_OPTS(bpf_map_create_opts, opts);
12+
int outer_fd, tmpl_fd, good_fd, bad_fd, err;
13+
int zero = 0;
14+
15+
/* Create template: percpu array with 8 entries */
16+
tmpl_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "tmpl",
17+
sizeof(int), sizeof(long), 8, NULL);
18+
if (!ASSERT_OK_FD(tmpl_fd, "create_tmpl"))
19+
return;
20+
21+
/* Create outer array-of-maps using template */
22+
opts.inner_map_fd = tmpl_fd;
23+
outer_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer",
24+
sizeof(int), sizeof(int), 1, &opts);
25+
if (!ASSERT_OK_FD(outer_fd, "create_outer"))
26+
goto close_tmpl;
27+
28+
/* Insert template as initial inner map */
29+
err = bpf_map_update_elem(outer_fd, &zero, &tmpl_fd, 0);
30+
if (!ASSERT_OK(err, "insert_tmpl"))
31+
goto close_outer;
32+
33+
/* Replacement with same max_entries should succeed */
34+
good_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "good",
35+
sizeof(int), sizeof(long), 8, NULL);
36+
if (!ASSERT_OK_FD(good_fd, "create_good"))
37+
goto close_outer;
38+
39+
err = bpf_map_update_elem(outer_fd, &zero, &good_fd, 0);
40+
ASSERT_OK(err, "replace_same_max_entries");
41+
close(good_fd);
42+
43+
/* Replacement with fewer max_entries must fail */
44+
bad_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "bad",
45+
sizeof(int), sizeof(long), 2, NULL);
46+
if (!ASSERT_OK_FD(bad_fd, "create_bad"))
47+
goto close_outer;
48+
49+
err = bpf_map_update_elem(outer_fd, &zero, &bad_fd, 0);
50+
ASSERT_ERR(err, "replace_smaller_max_entries");
51+
close(bad_fd);
52+
53+
close_outer:
54+
close(outer_fd);
55+
close_tmpl:
56+
close(tmpl_fd);
57+
}

0 commit comments

Comments
 (0)