BPF List
 help / color / mirror / Atom feed
* [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement
@ 2026-05-14  7:44 Guannan Wang
  2026-05-14 12:39 ` Mykyta Yatsenko
  2026-05-14 15:30 ` patchwork-bot+netdevbpf
  0 siblings, 2 replies; 3+ messages in thread
From: Guannan Wang @ 2026-05-14  7:44 UTC (permalink / raw)
  To: bpf; +Cc: daniel, gregkh, ast, andrii, xlabai, Guannan Wang

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: db69718b8efa ("bpf: inline bpf_map_lookup_elem() for PERCPU_ARRAY maps")
Signed-off-by: Guannan Wang <wgnbuaa@gmail.com>
---
 kernel/bpf/arraymap.c                         |  2 +-
 .../bpf/prog_tests/percpu_array_inner_map.c   | 57 +++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c

diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 5e25e0353..dfb2110ab 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -827,7 +827,7 @@ const struct bpf_map_ops array_map_ops = {
 };
 
 const struct bpf_map_ops percpu_array_map_ops = {
-	.map_meta_equal = bpf_map_meta_equal,
+	.map_meta_equal = array_map_meta_equal,
 	.map_alloc_check = array_map_alloc_check,
 	.map_alloc = array_map_alloc,
 	.map_free = array_map_free,
diff --git a/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c b/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c
new file mode 100644
index 000000000..2a8b23813
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+
+/*
+ * Test that replacing an inner percpu array map with one that has different
+ * max_entries is rejected.  percpu_array_map_gen_lookup() inlines the
+ * template's index_mask, so allowing a smaller replacement would cause OOB.
+ */
+void test_percpu_array_inner_map(void)
+{
+	LIBBPF_OPTS(bpf_map_create_opts, opts);
+	int outer_fd, tmpl_fd, good_fd, bad_fd, err;
+	int zero = 0;
+
+	/* Create template: percpu array with 8 entries */
+	tmpl_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "tmpl",
+				 sizeof(int), sizeof(long), 8, NULL);
+	if (!ASSERT_OK_FD(tmpl_fd, "create_tmpl"))
+		return;
+
+	/* Create outer array-of-maps using template */
+	opts.inner_map_fd = tmpl_fd;
+	outer_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer",
+				  sizeof(int), sizeof(int), 1, &opts);
+	if (!ASSERT_OK_FD(outer_fd, "create_outer"))
+		goto close_tmpl;
+
+	/* Insert template as initial inner map */
+	err = bpf_map_update_elem(outer_fd, &zero, &tmpl_fd, 0);
+	if (!ASSERT_OK(err, "insert_tmpl"))
+		goto close_outer;
+
+	/* Replacement with same max_entries should succeed */
+	good_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "good",
+				 sizeof(int), sizeof(long), 8, NULL);
+	if (!ASSERT_OK_FD(good_fd, "create_good"))
+		goto close_outer;
+
+	err = bpf_map_update_elem(outer_fd, &zero, &good_fd, 0);
+	ASSERT_OK(err, "replace_same_max_entries");
+	close(good_fd);
+
+	/* Replacement with fewer max_entries must fail */
+	bad_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "bad",
+				sizeof(int), sizeof(long), 2, NULL);
+	if (!ASSERT_OK_FD(bad_fd, "create_bad"))
+		goto close_outer;
+
+	err = bpf_map_update_elem(outer_fd, &zero, &bad_fd, 0);
+	ASSERT_ERR(err, "replace_smaller_max_entries");
+	close(bad_fd);
+
+close_outer:
+	close(outer_fd);
+close_tmpl:
+	close(tmpl_fd);
+}
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement
  2026-05-14  7:44 [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement Guannan Wang
@ 2026-05-14 12:39 ` Mykyta Yatsenko
  2026-05-14 15:30 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 3+ messages in thread
From: Mykyta Yatsenko @ 2026-05-14 12:39 UTC (permalink / raw)
  To: Guannan Wang, bpf; +Cc: daniel, gregkh, ast, andrii, xlabai

On 5/14/26 8:44 AM, Guannan Wang wrote:
> 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: db69718b8efa ("bpf: inline bpf_map_lookup_elem() for PERCPU_ARRAY maps")
> Signed-off-by: Guannan Wang <wgnbuaa@gmail.com>
> ---
>  kernel/bpf/arraymap.c                         |  2 +-
>  .../bpf/prog_tests/percpu_array_inner_map.c   | 57 +++++++++++++++++++
>  2 files changed, 58 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c
> 
> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
> index 5e25e0353..dfb2110ab 100644
> --- a/kernel/bpf/arraymap.c
> +++ b/kernel/bpf/arraymap.c
> @@ -827,7 +827,7 @@ const struct bpf_map_ops array_map_ops = {
>  };
>  
>  const struct bpf_map_ops percpu_array_map_ops = {
> -	.map_meta_equal = bpf_map_meta_equal,
> +	.map_meta_equal = array_map_meta_equal,

It looks like the patch f4d05259213ff ("bpf: Add map_meta_equal map ops")
introduced map_meta_equal op and set bpf_map_meta_equal for percpu_array_map_ops,
correct at that time.

But as db69718b8efa ("bpf: inline bpf_map_lookup_elem() for PERCPU_ARRAY maps")
introduced inlined lookup that uses max_elements, the map_meta_equal should have
been aligned to check for that.

Acked-by: Mykyta Yatsenko <yatsenko@meta.com>

>  	.map_alloc_check = array_map_alloc_check,
>  	.map_alloc = array_map_alloc,
>  	.map_free = array_map_free,
> diff --git a/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c b/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c
> new file mode 100644
> index 000000000..2a8b23813
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/percpu_array_inner_map.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <test_progs.h>
> +
> +/*
> + * Test that replacing an inner percpu array map with one that has different
> + * max_entries is rejected.  percpu_array_map_gen_lookup() inlines the
> + * template's index_mask, so allowing a smaller replacement would cause OOB.
> + */
> +void test_percpu_array_inner_map(void)
> +{
> +	LIBBPF_OPTS(bpf_map_create_opts, opts);
> +	int outer_fd, tmpl_fd, good_fd, bad_fd, err;
> +	int zero = 0;
> +
> +	/* Create template: percpu array with 8 entries */
> +	tmpl_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "tmpl",
> +				 sizeof(int), sizeof(long), 8, NULL);
> +	if (!ASSERT_OK_FD(tmpl_fd, "create_tmpl"))
> +		return;
> +
> +	/* Create outer array-of-maps using template */
> +	opts.inner_map_fd = tmpl_fd;
> +	outer_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer",
> +				  sizeof(int), sizeof(int), 1, &opts);
> +	if (!ASSERT_OK_FD(outer_fd, "create_outer"))
> +		goto close_tmpl;
> +
> +	/* Insert template as initial inner map */
> +	err = bpf_map_update_elem(outer_fd, &zero, &tmpl_fd, 0);
> +	if (!ASSERT_OK(err, "insert_tmpl"))
> +		goto close_outer;
> +
> +	/* Replacement with same max_entries should succeed */
> +	good_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "good",
> +				 sizeof(int), sizeof(long), 8, NULL);
> +	if (!ASSERT_OK_FD(good_fd, "create_good"))
> +		goto close_outer;
> +
> +	err = bpf_map_update_elem(outer_fd, &zero, &good_fd, 0);
> +	ASSERT_OK(err, "replace_same_max_entries");
> +	close(good_fd);
> +
> +	/* Replacement with fewer max_entries must fail */
> +	bad_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "bad",
> +				sizeof(int), sizeof(long), 2, NULL);
> +	if (!ASSERT_OK_FD(bad_fd, "create_bad"))
> +		goto close_outer;
> +
> +	err = bpf_map_update_elem(outer_fd, &zero, &bad_fd, 0);
> +	ASSERT_ERR(err, "replace_smaller_max_entries");
> +	close(bad_fd);
> +
> +close_outer:
> +	close(outer_fd);
> +close_tmpl:
> +	close(tmpl_fd);
> +}


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement
  2026-05-14  7:44 [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement Guannan Wang
  2026-05-14 12:39 ` Mykyta Yatsenko
@ 2026-05-14 15:30 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-05-14 15:30 UTC (permalink / raw)
  To: Guannan Wang; +Cc: bpf, daniel, gregkh, ast, andrii, xlabai

Hello:

This patch was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Thu, 14 May 2026 15:44:54 +0800 you wrote:
> 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.
> 
> [...]

Here is the summary with links:
  - [bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement
    https://git.kernel.org/bpf/bpf/c/593980175389

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-05-14 15:31 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-14  7:44 [PATCH bpf] bpf: Use array_map_meta_equal for percpu array inner map replacement Guannan Wang
2026-05-14 12:39 ` Mykyta Yatsenko
2026-05-14 15:30 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox