From f8b19aeca1652fcadefce8529cd85e5fd475dd69 Mon Sep 17 00:00:00 2001 From: Slava Imameev Date: Sat, 21 Jun 2025 01:18:12 +1000 Subject: selftests/bpf: Add test for bpftool access to read-only protected maps Add selftest cases that validate bpftool's expected behavior when accessing maps protected from modification via security_bpf_map. The test includes a BPF program attached to security_bpf_map with two maps: - A protected map that only allows read-only access - An unprotected map that allows full access The test script attaches the BPF program to security_bpf_map and verifies that for the bpftool map command: - Read access works on both maps - Write access fails on the protected map - Write access succeeds on the unprotected map - These behaviors remain consistent when the maps are pinned Signed-off-by: Slava Imameev Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/r/20250620151812.13952-2-slava.imameev@crowdstrike.com Signed-off-by: Alexei Starovoitov --- .../testing/selftests/bpf/progs/security_bpf_map.c | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/security_bpf_map.c (limited to 'tools/testing/selftests/bpf/progs/security_bpf_map.c') diff --git a/tools/testing/selftests/bpf/progs/security_bpf_map.c b/tools/testing/selftests/bpf/progs/security_bpf_map.c new file mode 100644 index 000000000000..7216b3450e96 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/security_bpf_map.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "vmlinux.h" +#include +#include + +char _license[] SEC("license") = "GPL"; + +#define EPERM 1 /* Operation not permitted */ + +/* From include/linux/mm.h. */ +#define FMODE_WRITE 0x2 + +struct map; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 1); +} prot_status_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 3); +} prot_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 3); +} not_prot_map SEC(".maps"); + +SEC("fmod_ret/security_bpf_map") +int BPF_PROG(fmod_bpf_map, struct bpf_map *map, int fmode) +{ + __u32 key = 0; + __u32 *status_ptr = bpf_map_lookup_elem(&prot_status_map, &key); + + if (!status_ptr || !*status_ptr) + return 0; + + if (map == &prot_map) { + /* Allow read-only access */ + if (fmode & FMODE_WRITE) + return -EPERM; + } + + return 0; +} + +/* + * This program keeps references to maps. This is needed to prevent + * optimizing them out. + */ +SEC("fentry/bpf_fentry_test1") +int BPF_PROG(fentry_dummy1, int a) +{ + __u32 key = 0; + __u32 val1 = a; + __u32 val2 = a + 1; + + bpf_map_update_elem(&prot_map, &key, &val1, BPF_ANY); + bpf_map_update_elem(¬_prot_map, &key, &val2, BPF_ANY); + return 0; +} -- cgit v1.2.3