summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorLang Xu <xulang@uniontech.com>2026-04-02 10:42:36 +0300
committerAlexei Starovoitov <ast@kernel.org>2026-04-12 23:36:32 +0300
commit171609f047552b51b8ed78f338cbffb84b7f5e8f (patch)
treefd468ce818d0cf5616ceaf8049d269169b974127 /tools
parent576afddfee8d1108ee299bf10f581593540d1a36 (diff)
downloadlinux-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')
-rw-r--r--tools/testing/selftests/bpf/prog_tests/cgroup_storage.c42
-rw-r--r--tools/testing/selftests/bpf/progs/cgroup_storage.c43
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";