diff options
| author | Lang Xu <xulang@uniontech.com> | 2026-04-02 10:42:36 +0300 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-04-12 23:36:32 +0300 |
| commit | 171609f047552b51b8ed78f338cbffb84b7f5e8f (patch) | |
| tree | fd468ce818d0cf5616ceaf8049d269169b974127 /tools/testing | |
| parent | 576afddfee8d1108ee299bf10f581593540d1a36 (diff) | |
| download | linux-171609f047552b51b8ed78f338cbffb84b7f5e8f.tar.xz | |
selftests/bpf: Add test for cgroup storage OOB read
Add a test case to reproduce the out-of-bounds read issue when copying
from a cgroup storage map to a pcpu map with a value_size not rounded
up to 8 bytes.
The test creates:
1. A CGROUP_STORAGE map with 4-byte value (not 8-byte aligned)
2. A LRU_PERCPU_HASH map with 4-byte value (same size)
When a socket is created in the cgroup, the BPF program triggers
bpf_map_update_elem() which calls copy_map_value_long(). This function
rounds up the copy size to 8 bytes, but the cgroup storage buffer is
only 4 bytes, causing an OOB read (before the fix).
Signed-off-by: Lang Xu <xulang@uniontech.com>
Link: https://lore.kernel.org/r/D63BF0DBFF1EA122+20260402074236.2187154-2-xulang@uniontech.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing')
| -rw-r--r-- | tools/testing/selftests/bpf/prog_tests/cgroup_storage.c | 42 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/progs/cgroup_storage.c | 43 |
2 files changed, 85 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_storage.c b/tools/testing/selftests/bpf/prog_tests/cgroup_storage.c index cf395715ced4..5b56dc893e73 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgroup_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_storage.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 +#include <unistd.h> +#include <sys/socket.h> #include <test_progs.h> #include "cgroup_helpers.h" #include "network_helpers.h" @@ -94,3 +96,43 @@ cleanup_cgroup: close(cgroup_fd); cleanup_cgroup_environment(); } + +void test_cgroup_storage_oob(void) +{ + struct cgroup_storage *skel; + int cgroup_fd, sock_fd; + + cgroup_fd = cgroup_setup_and_join(TEST_CGROUP); + if (!ASSERT_OK_FD(cgroup_fd, "create cgroup")) + return; + + /* Load and attach BPF program */ + skel = cgroup_storage__open_and_load(); + if (!ASSERT_OK_PTR(skel, "cgroup_storage__open_and_load")) + goto cleanup_cgroup; + + skel->links.trigger_oob = bpf_program__attach_cgroup(skel->progs.trigger_oob, + cgroup_fd); + if (!ASSERT_OK_PTR(skel->links.trigger_oob, "attach_cgroup")) + goto cleanup_skel; + + /* Create a socket to trigger cgroup/sock_create hook. + * This will execute our BPF program and trigger the OOB read + * if the bug is present (before the fix). + */ + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (!ASSERT_OK_FD(sock_fd, "create socket")) + goto cleanup_skel; + + close(sock_fd); + + /* If we reach here without a kernel panic or KASAN report, + * the test passes (the fix is working). + */ + +cleanup_skel: + cgroup_storage__destroy(skel); +cleanup_cgroup: + close(cgroup_fd); + cleanup_cgroup_environment(); +} diff --git a/tools/testing/selftests/bpf/progs/cgroup_storage.c b/tools/testing/selftests/bpf/progs/cgroup_storage.c index db1e4d2d3281..59da1d95e5b9 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_storage.c +++ b/tools/testing/selftests/bpf/progs/cgroup_storage.c @@ -21,4 +21,47 @@ int bpf_prog(struct __sk_buff *skb) return (*counter & 1); } +/* Maps for OOB test */ +struct { + __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE); + __type(key, struct bpf_cgroup_storage_key); + __type(value, __u32); /* 4-byte value - not 8-byte aligned */ +} cgroup_storage_oob SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u32); /* 4-byte value - same as cgroup storage */ +} lru_map SEC(".maps"); + +SEC("cgroup/sock_create") +int trigger_oob(struct bpf_sock *sk) +{ + __u32 key = 0; + __u32 *cgroup_val; + __u32 value = 0x12345678; + + /* Get cgroup storage value */ + cgroup_val = bpf_get_local_storage(&cgroup_storage_oob, 0); + if (!cgroup_val) + return 0; + + /* Initialize cgroup storage */ + *cgroup_val = value; + + /* This triggers the OOB read: + * bpf_map_update_elem() -> htab_map_update_elem() -> + * pcpu_init_value() -> copy_map_value_long() -> + * bpf_obj_memcpy(..., long_memcpy=true) -> + * bpf_long_memcpy(dst, src, round_up(4, 8)) + * + * The copy size is rounded up to 8 bytes, but cgroup_val + * points to a 4-byte buffer, causing a 4-byte OOB read. + */ + bpf_map_update_elem(&lru_map, &key, cgroup_val, BPF_ANY); + + return 1; +} + char _license[] SEC("license") = "GPL"; |
