[PATCH bpf] selftests/bpf: Check returned keys in map batch validators

From: Tianyi Chen

Date: Sun Sep 06 2026 - 10:42:21 EST


The hash and array batch validators mark visited entries by output
position, making the subsequent completeness checks always succeed.
Duplicate keys with matching values can therefore hide missing entries.

Check that returned keys fall within the populated range and index
the visited array by key. This detects missing entries while preserving
unordered results and existing per-CPU value validation.

Controlled inputs confirm that the old validators accept duplicates
and out-of-range keys with matching values, while the updated checks
reject them. Ordered, reversed and shuffled valid keys still pass,
and scalar and per-CPU value corruption is still rejected. The full
test_maps suite passes with no skips on the matching kernel.

Fixes: 30ff3c59137d ("selftests/bpf: Add batch ops testing for htab and htab_percpu map")
Fixes: f0fac2cec286 ("selftests/bpf: Add batch ops testing to array bpf map")
Assisted-by: LLM
Signed-off-by: Tianyi Chen <hi@xxxxxxxxx>
---
tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c | 5 ++++-
tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c | 4 +++-
2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c b/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
index b595556315b..76d3800a82a 100644
--- a/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
+++ b/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
@@ -45,6 +45,9 @@ static void map_batch_verify(int *visited, __u32 max_entries, int *keys,

memset(visited, 0, max_entries * sizeof(*visited));
for (i = 0; i < max_entries; i++) {
+ CHECK(keys[i] < 0 || keys[i] >= max_entries, "key checking",
+ "error: i %d key %d out of range\n", i, keys[i]);
+
if (is_pcpu) {
cpu_offset = i * nr_cpus;
for (j = 0; j < nr_cpus; j++) {
@@ -59,7 +62,7 @@ static void map_batch_verify(int *visited, __u32 max_entries, int *keys,
"error: i %d key %d value %lld\n", i, keys[i],
values[i]);
}
- visited[i] = 1;
+ visited[keys[i]] = 1;
}
for (i = 0; i < max_entries; i++) {
CHECK(visited[i] != 1, "visited checking",
diff --git a/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c b/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
index 5da493b94ae..430949f9691 100644
--- a/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
+++ b/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
@@ -50,6 +50,8 @@ static void map_batch_verify(int *visited, __u32 max_entries,

memset(visited, 0, max_entries * sizeof(*visited));
for (i = 0; i < max_entries; i++) {
+ CHECK(keys[i] < 1 || keys[i] > max_entries, "key checking",
+ "error: i %d key %d out of range\n", i, keys[i]);

if (is_pcpu) {
for (j = 0; j < bpf_num_possible_cpus(); j++) {
@@ -65,7 +67,7 @@ static void map_batch_verify(int *visited, __u32 max_entries,
((int *)values)[i]);
}

- visited[i] = 1;
+ visited[keys[i] - 1] = 1;

}
for (i = 0; i < max_entries; i++) {
--
2.55.0