mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Merge patch series "bpf: Fix OOB in pcpu_init_value and add a test"
xulang <xulang@uniontech.com> says: ==================== Fix OOB read when copying element from a BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the same value_size that is not rounded up to 8 bytes, and add a test case to reproduce the issue. The root cause is that pcpu_init_value() uses copy_map_value_long() which rounds up the copy size to 8 bytes, but CGROUP_STORAGE map values are not 8-byte aligned (e.g., 4-byte). This causes a 4-byte OOB read when the copy is performed. ==================== Link: https://lore.kernel.org/r/7653EEEC2BAB17DF+20260402073948.2185396-1-xulang@uniontech.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
fa2942918a
|
|
@ -1056,7 +1056,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
|
|||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (cpu == current_cpu)
|
||||
copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value);
|
||||
copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value);
|
||||
else /* Since elem is preallocated, we cannot touch special fields */
|
||||
zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -99,3 +101,43 @@ void test_cgroup_storage(void)
|
|||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user